From 20801851929b8c14ef7ee331215ddba510eca4a0 Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Tue, 4 Dec 2018 16:15:22 -0200 Subject: [PATCH 001/222] HOTFIX - materia do expediente sem observacao no resumo --- sapl/sessao/views.py | 3 ++- sapl/templates/sessao/blocos_resumo/materias_expediente.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 2f93b7056..6082be290 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1403,7 +1403,8 @@ class ResumoView(DetailView): 'resultado_observacao': resultado_observacao, 'autor': autor, 'numero_protocolo': m.materia.numero_protocolo, - 'numero_processo': m.materia.numeracao_set.last() + 'numero_processo': m.materia.numeracao_set.last(), + 'observacao': m.observacao } materias_expediente.append(mat) diff --git a/sapl/templates/sessao/blocos_resumo/materias_expediente.html b/sapl/templates/sessao/blocos_resumo/materias_expediente.html index 556b53039..48dcf9c14 100644 --- a/sapl/templates/sessao/blocos_resumo/materias_expediente.html +++ b/sapl/templates/sessao/blocos_resumo/materias_expediente.html @@ -33,7 +33,7 @@ Processo: {{ m.numero_processo }} {% endif %} - {{m.ementa|safe}} + {{m.ementa|safe}}
{{m.observacao}} {{m.resultado}}
{{m.resultado_observacao}} {% endfor %} From d0efd37c697d0b6f4d554e1188a1b01f7f240784 Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Tue, 11 Dec 2018 15:02:37 -0200 Subject: [PATCH 002/222] HOTFIX - observacao da ementa das materias nao aparecia na pauta da sessao --- sapl/sessao/views.py | 2 ++ sapl/templates/sessao/pauta_sessao_detail.html | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 6082be290..98ca3815c 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -2766,6 +2766,7 @@ class PautaSessaoDetailView(DetailView): mat = {'id': m.materia_id, 'ementa': ementa, + 'observacao': m.observacao, 'titulo': titulo, 'numero': numero, 'resultado': resultado, @@ -2829,6 +2830,7 @@ class PautaSessaoDetailView(DetailView): mat = {'id': o.materia_id, 'ementa': ementa, + 'observacao': o.observacao, 'titulo': titulo, 'numero': numero, 'resultado': resultado, diff --git a/sapl/templates/sessao/pauta_sessao_detail.html b/sapl/templates/sessao/pauta_sessao_detail.html index 8cf784b86..cd779a78a 100644 --- a/sapl/templates/sessao/pauta_sessao_detail.html +++ b/sapl/templates/sessao/pauta_sessao_detail.html @@ -34,7 +34,7 @@
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} - {{m.ementa|safe}} + {{m.ementa|safe}}
{{m.observacao|safe}} {{m.situacao}} {% endfor %} @@ -62,7 +62,7 @@
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} - {{m.ementa|safe}} + {{m.ementa|safe}}
{{m.observacao|safe}} {{m.situacao}} {% endfor %} From dff82278a978ddf7689a7683715f9feafaea5333 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 12 Dec 2018 12:46:49 -0200 Subject: [PATCH 003/222] =?UTF-8?q?HOT-FIX:=20adiciona=20logging=20de=20er?= =?UTF-8?q?ros=20n=C3=A3o=20tratados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/settings.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sapl/settings.py b/sapl/settings.py index 0c3f9935e..d30b4df3c 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -15,6 +15,7 @@ See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ """ import logging import socket +import sys from decouple import config from dj_database_url import parse as db_url @@ -335,12 +336,16 @@ LOGGING = { } -def excepthook(*args): - logging.getLogger(BASE_DIR.name).error( - 'Uncaught exception:', exc_info=args) +def uncaught_exceptions(type, value, error_traceback): + import traceback + 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 = [ 'django.contrib.auth.hashers.PBKDF2PasswordHasher', # default From 789d67ddacb9cedf4fea6a1bd1de92cd1c18ce1a Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 12 Dec 2018 14:58:48 -0200 Subject: [PATCH 004/222] =?UTF-8?q?HOT-FIX:=20diminui=20o=20n=C3=ADvel=20d?= =?UTF-8?q?o=20logging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/parlamentares/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index f9a37b373..ce32475f0 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -574,7 +574,7 @@ class ParlamentarCrud(Crud): # Caso encontre UMA filiação nessas condições 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) return context From 68e8df3a77c5071d623000ce356944627ae3a79f Mon Sep 17 00:00:00 2001 From: Edward Date: Wed, 12 Dec 2018 18:57:37 -0200 Subject: [PATCH 005/222] Fixes #2422 (#2423) --- sapl/templates/protocoloadm/comprovante.html | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sapl/templates/protocoloadm/comprovante.html b/sapl/templates/protocoloadm/comprovante.html index 9dcf9a638..d285b4e4f 100644 --- a/sapl/templates/protocoloadm/comprovante.html +++ b/sapl/templates/protocoloadm/comprovante.html @@ -14,15 +14,21 @@ th, td { 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 */ + }
- - + +
- -
- {% endfor %} + {% endif %}

\ No newline at end of file diff --git a/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html b/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html index 6b09fa37a..c5ffd15df 100644 --- a/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html +++ b/sapl/templates/sessao/blocos_ata/materias_ordem_dia.html @@ -1,23 +1,24 @@
-

- - Matérias da Ordem do Dia: - {% for m in materias_ordem %} - {{m.numero}} - {{m.titulo}} - {% 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 %} +

+ {% if materias_ordem %} + Matérias da Ordem do Dia: + {% for m in materias_ordem %} + {{m.numero}} - {{m.titulo}} + {% 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 %} + {% endif %}

\ No newline at end of file diff --git a/sapl/templates/sessao/blocos_ata/mesa_diretora.html b/sapl/templates/sessao/blocos_ata/mesa_diretora.html index 3d58adc62..f09e9b8e0 100644 --- a/sapl/templates/sessao/blocos_ata/mesa_diretora.html +++ b/sapl/templates/sessao/blocos_ata/mesa_diretora.html @@ -1,10 +1,12 @@

+ {% if mesa %} Mesa Diretora: {% for m in mesa %} {{m.cargo}}: {{m.parlamentar.nome_parlamentar}} / {{ m.parlamentar.filiacao_atual }} ; {% endfor %} + {% endif %}

\ No newline at end of file diff --git a/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html b/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html index 9b65733f9..0896cd9b0 100644 --- a/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html +++ b/sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html @@ -1,6 +1,8 @@

+ {% if object.ocorrenciasessao.conteudo %} Ocorrências da Sessão: {{object.ocorrenciasessao.conteudo|striptags|safe}} -

+ {% endif %} +

diff --git a/sapl/templates/sessao/blocos_ata/oradores_expediente.html b/sapl/templates/sessao/blocos_ata/oradores_expediente.html index b8e972eaa..8bc420b3c 100644 --- a/sapl/templates/sessao/blocos_ata/oradores_expediente.html +++ b/sapl/templates/sessao/blocos_ata/oradores_expediente.html @@ -1,5 +1,6 @@

+ {% if oradores %} Oradores do Expediente: {% for o in oradores %}

{{o.numero_ordem}} - {{o.parlamentar}}
@@ -7,6 +8,7 @@
{{o.observacao}}

{% endfor %} + {% endif %}

diff --git a/sapl/templates/sessao/blocos_ata/oradores_explicacoes.html b/sapl/templates/sessao/blocos_ata/oradores_explicacoes.html index 795a209a2..18ced7b07 100644 --- a/sapl/templates/sessao/blocos_ata/oradores_explicacoes.html +++ b/sapl/templates/sessao/blocos_ata/oradores_explicacoes.html @@ -1,9 +1,11 @@

+ {% if oradores_explicacoes %} Oradores das Explicações Pessoais: - {% for o in oradores_explicacoes %} - {{o.numero_ordem}} - {{o.parlamentar.nome_parlamentar}} / {{ o.parlamentar.filiacao_atual }} ; - {{o.url_discurso}} - {% endfor %} + {% for o in oradores_explicacoes %} + {{o.numero_ordem}} - {{o.parlamentar.nome_parlamentar}} / {{ o.parlamentar.filiacao_atual }} ; + {{o.url_discurso}} + {% endfor %} + {% endif %}

\ No newline at end of file From 62de214057a0d74bde09a3d8ddf932de48810990 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 14 Dec 2018 13:32:57 -0200 Subject: [PATCH 013/222] fix #2421 (#2426) --- sapl/materia/forms.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index c3ce1f36f..39dd4c24d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -127,6 +127,9 @@ class MateriaSimplificadaForm(ModelForm): 'numero_protocolo', 'regime_tramitacao', 'em_tramitacao', 'ementa', 'tipo_apresentacao', 'texto_original'] + widgets = { + 'numero_protocolo': forms.TextInput(attrs={'readonly': True}), + } def __init__(self, *args, **kwargs): From 039ae58396537ad3ea59e4192456677a4d3ce7da Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 14 Dec 2018 15:22:00 -0200 Subject: [PATCH 014/222] Release: 3.1.138 --- docker-compose.yml | 2 +- sapl/templates/base.html | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ac3425c9f..3691de798 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.137 + image: interlegis/sapl:3.1.138 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/templates/base.html b/sapl/templates/base.html index d2f4cca33..0291ef7ba 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -184,7 +184,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.137 + Release: 3.1.138

diff --git a/setup.py b/setup.py index daf572e62..fd2490fbf 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.137', + version='3.1.138', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 60a96d6d90f812492847f52796c5a827c35986cc Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 17 Dec 2018 12:43:43 -0200 Subject: [PATCH 015/222] fix #2418 (#2427) --- sapl/sessao/forms.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 386f123ca..d2e00f47c 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -24,7 +24,7 @@ from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, MateriaPesquisaOrderingFilter, autor_label, autor_modal, timezone) from .models import (Bancada, Bloco, ExpedienteMateria, Orador, JustificativaAusencia, - OradorExpediente, OrdemDia, SessaoPlenaria, + OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoResultadoVotacao, OcorrenciaSessao, RetiradaPauta, TipoRetiradaPauta) @@ -841,7 +841,8 @@ class JustificativaAusenciaForm(ModelForm): ordens = OrdemDia.objects.filter(q) expedientes = ExpedienteMateria.objects.filter(q) 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] @@ -850,9 +851,14 @@ class JustificativaAusenciaForm(ModelForm): presencas = SessaoPlenariaPresenca.objects.filter( q).order_by('parlamentar__nome_parlamentar') + presencas_ordem = PresencaOrdemDia.objects.filter( + q).order_by('parlamentar__nome_parlamentar') 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 = [ (e.id, e.materia) for e in expedientes] From 4d6d7401746c7d4753a14310fa059b87f5252df9 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Mon, 17 Dec 2018 15:17:34 -0200 Subject: [PATCH 016/222] fix #925 (#2428) --- sapl/templates/protocoloadm/protocolo_filter.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sapl/templates/protocoloadm/protocolo_filter.html b/sapl/templates/protocoloadm/protocolo_filter.html index 02c0673fa..316003075 100644 --- a/sapl/templates/protocoloadm/protocolo_filter.html +++ b/sapl/templates/protocoloadm/protocolo_filter.html @@ -62,6 +62,13 @@ Anulado por: {{ p.user_anulacao }} - IP {{ p.ip_anulacao }}
Motivo Anulação: {{ p.justificativa_anulacao }}
{% endif %} + {% if p.tipo_documento and p.documentoadministrativo_set.first %} + Documentos vinculados: + + {{ p.documentoadministrativo_set.first.tipo }} - {{ p.documentoadministrativo_set.first.numero }} / + {{ p.documentoadministrativo_set.first.ano }} + + {% endif %}
{% endfor %} From 62e82aefd204ab3d36b59ea665f474ae67888686 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Wed, 19 Dec 2018 12:19:28 -0200 Subject: [PATCH 017/222] =?UTF-8?q?Fix=20#2313=20-=20Gera=C3=A7=C3=A3o=20d?= =?UTF-8?q?e=20relat=C3=B3rios=20e=20estatisticas=20(#2429)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Colocando opcao de geracao de relatorios em configuracao do sistema * fix 2313 * HOT-FIX: adiciona logging de erros não tratados * HOT-FIX: diminui o nível do logging * inicio do relatorio por mes das normas * normas por mes concluida e inicio normas vigencia * relatorio por vigencia em andamento * adicionadas normas por vigencia * estatisticas das normas por vigencia por ano * tela de estatisticas * adiciona model NormaEstatisticas no map_rules * correcoes e adicao de opcao no configuracao de aplicacao * correcao do teste em norma * retira config relatorio atos que não era utilizado * migration --- sapl/base/forms.py | 81 ++++++++- .../0027_appconfig_relatorios_atos.py | 20 +++ ...28_appconfig_estatisticas_acesso_normas.py | 20 +++ .../0029_remove_appconfig_relatorios_atos.py | 19 +++ sapl/base/models.py | 8 + sapl/base/urls.py | 16 +- sapl/base/views.py | 159 +++++++++++++++++- .../migrations/0017_normaestatisticas.py | 25 +++ sapl/norma/models.py | 12 ++ sapl/norma/tests/test_norma.py | 2 + sapl/norma/views.py | 18 +- sapl/rules/map_rules.py | 2 + .../base/EstatisticasAcessoNormas_filter.html | 64 +++++++ .../RelatorioHistoricoTramitacao_filter.html | 2 +- .../RelatorioMateriasPorAutor_filter.html | 2 +- .../base/RelatorioNormaMes_filter.html | 67 ++++++++ .../base/RelatorioNormasVigencia_filter.html | 57 +++++++ sapl/templates/base/layouts.yaml | 3 + sapl/templates/base/relatorios_list.html | 14 ++ 19 files changed, 578 insertions(+), 13 deletions(-) create mode 100644 sapl/base/migrations/0027_appconfig_relatorios_atos.py create mode 100644 sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py create mode 100644 sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py create mode 100644 sapl/norma/migrations/0017_normaestatisticas.py create mode 100644 sapl/templates/base/EstatisticasAcessoNormas_filter.html create mode 100644 sapl/templates/base/RelatorioNormaMes_filter.html create mode 100644 sapl/templates/base/RelatorioNormasVigencia_filter.html diff --git a/sapl/base/forms.py b/sapl/base/forms.py index ccd2c132b..ec69c50d9 100644 --- a/sapl/base/forms.py +++ b/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.comissoes.models import Reuniao, Comissao from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao) +from sapl.norma.models import (NormaJuridica) from sapl.parlamentares.models import SessaoLegislativa from sapl.sessao.models import SessaoPlenaria from sapl.settings import MAX_IMAGE_UPLOAD_SIZE @@ -688,6 +689,83 @@ class RelatorioAtasFilterSet(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_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Ano')), + '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): filter_overrides = {models.DateField: { @@ -1061,7 +1139,8 @@ class ConfiguracoesAppForm(ModelForm): 'cronometro_consideracoes', 'mostrar_brasao_painel', 'receber_recibo_proposicao', - 'assinatura_ata'] + 'assinatura_ata', + 'estatisticas_acesso_normas'] def __init__(self, *args, **kwargs): super(ConfiguracoesAppForm, self).__init__(*args, **kwargs) diff --git a/sapl/base/migrations/0027_appconfig_relatorios_atos.py b/sapl/base/migrations/0027_appconfig_relatorios_atos.py new file mode 100644 index 000000000..afd3382e1 --- /dev/null +++ b/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'), + ), + ] diff --git a/sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py b/sapl/base/migrations/0028_appconfig_estatisticas_acesso_normas.py new file mode 100644 index 000000000..7a4af06de --- /dev/null +++ b/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'), + ), + ] diff --git a/sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py b/sapl/base/migrations/0029_remove_appconfig_relatorios_atos.py new file mode 100644 index 000000000..fa06b23ac --- /dev/null +++ b/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', + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index 5caf8b2c0..343a8db9b 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -12,6 +12,9 @@ from sapl.utils import (LISTA_DE_UFS, YES_NO_CHOICES, TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensiva')), ('R', _('Restritiva'))) +RELATORIO_ATOS_ACESSADOS = (('S', _('Sim')), + ('N', _('Não'))) + SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')), ('L', _('Sequencial por legislatura')), ('U', _('Sequencial único'))) @@ -84,6 +87,11 @@ class AppConfig(models.Model): verbose_name=_('Visibilidade dos Documentos Administrativos'), 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( max_length=1, verbose_name=_('Sequência de numeração'), diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 93a5b1cd3..ae4add258 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -23,7 +23,11 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, RelatorioMateriasPorAutorView, RelatorioMateriasTramitacaoView, RelatorioPresencaSessaoView, - RelatorioReuniaoView, SaplSearchView) + RelatorioReuniaoView, SaplSearchView, + RelatorioNormasPublicadasMesView, + RelatorioNormasVigenciaView, + EstatisticasAcessoNormas, + RelatoriosListView) app_name = AppConfig.name @@ -84,10 +88,16 @@ urlpatterns = [ url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())), # TODO mover estas telas para a app 'relatorios' - url(r'^sistema/relatorios/$', TemplateView.as_view( - template_name='base/relatorios_list.html'), name='relatorios_list'), + url(r'^sistema/relatorios/$', + RelatoriosListView.as_view(), name='relatorios_list'), url(r'^sistema/relatorios/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$', RelatorioMateriasPorAnoAutorTipoView.as_view(), name='materia_por_ano_autor_tipo'), diff --git a/sapl/base/views.py b/sapl/base/views.py index ca122ce9f..599d6b05f 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,3 +1,5 @@ +import collections +import datetime import logging import os @@ -30,6 +32,7 @@ from sapl.comissoes.models import Reuniao, Comissao from sapl.crud.base import CrudAux, make_pagination from sapl.materia.models import (Autoria, MateriaLegislativa, TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao) +from sapl.norma.models import (NormaJuridica, NormaEstatisticas) from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca) from sapl.utils import (parlamentares_ativos, @@ -45,7 +48,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, RelatorioMateriasTramitacaoilterSet, RelatorioPresencaSessaoFilterSet, RelatorioReuniaoFilterSet, UsuarioCreateForm, - UsuarioEditForm) + UsuarioEditForm, RelatorioNormasMesFilterSet, + RelatorioNormasVigenciaFilterSet) from .models import AppConfig, CasaLegislativa @@ -276,6 +280,20 @@ class AutorCrud(CrudAux): 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): model = SessaoPlenaria filterset_class = RelatorioAtasFilterSet @@ -744,6 +762,145 @@ class RelatorioMateriasPorAutorView(FilterView): 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): model = get_user_model() template_name = 'auth/user_list.html' diff --git a/sapl/norma/migrations/0017_normaestatisticas.py b/sapl/norma/migrations/0017_normaestatisticas.py new file mode 100644 index 000000000..03009eeec --- /dev/null +++ b/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')), + ], + ), + ] diff --git a/sapl/norma/models.py b/sapl/norma/models.py index 6565304ee..80075f113 100644 --- a/sapl/norma/models.py +++ b/sapl/norma/models.py @@ -191,6 +191,18 @@ class NormaJuridica(models.Model): 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() class AutoriaNorma(models.Model): autor = models.ForeignKey(Autor, diff --git a/sapl/norma/tests/test_norma.py b/sapl/norma/tests/test_norma.py index 6603d7167..5c2a76a6a 100644 --- a/sapl/norma/tests/test_norma.py +++ b/sapl/norma/tests/test_norma.py @@ -7,6 +7,7 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm) from sapl.norma.models import NormaJuridica, TipoNormaJuridica +from sapl.base.models import AppConfig @pytest.mark.django_db(transaction=False) @@ -15,6 +16,7 @@ def test_incluir_norma_submit(admin_client): tipo = mommy.make(TipoNormaJuridica, sigla='T', descricao='Teste') + config = mommy.make(AppConfig) # Testa POST response = admin_client.post(reverse('sapl.norma:normajuridica_create'), diff --git a/sapl/norma/views.py b/sapl/norma/views.py index f2dfb6f2e..f7800c42f 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -1,6 +1,8 @@ -import re import logging +import re +import sapl +import weasyprint from django.contrib.auth.mixins import PermissionRequiredMixin 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.edit import FormView from django_filters.views import FilterView -import weasyprint -import sapl from sapl.base.models import AppConfig from sapl.compilacao.views import IntegracaoTaView 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, NormaPesquisaSimplesForm, NormaRelacionadaForm, AutoriaNormaForm) from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, - TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma) + TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma, NormaEstatisticas) # LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '') @@ -190,7 +190,13 @@ class NormaCrud(Crud): return reverse('%s:%s' % (namespace, 'norma_pesquisa')) 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): @@ -225,7 +231,7 @@ class NormaCrud(Crud): class ListView(Crud.ListView, RedirectView): 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')) def get(self, request, *args, **kwargs): diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index aa691da5e..f9b63fd4b 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -139,6 +139,7 @@ rules_group_norma = { (norma.NormaRelacionada, __base__), (norma.AnexoNormaJuridica, __base__), (norma.AutoriaNorma, __base__), + (norma.NormaEstatisticas, __base__), # 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 @@ -242,6 +243,7 @@ rules_group_geral = { (norma.AssuntoNorma, __base__), (norma.TipoNormaJuridica, __base__), (norma.TipoVinculoNormaJuridica, __base__), + (norma.NormaEstatisticas, __base__), (parlamentares.Legislatura, __base__), (parlamentares.SessaoLegislativa, __base__), diff --git a/sapl/templates/base/EstatisticasAcessoNormas_filter.html b/sapl/templates/base/EstatisticasAcessoNormas_filter.html new file mode 100644 index 000000000..a8246e22d --- /dev/null +++ b/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 %} + +



+ PARÂMETROS DE PESQUISA:
+  Ano: {{ ano }}
+
+ {% if normas_mes|length == 0 %} +
+

{% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}

+ {% elif normas_mes|length == meses_sem_acesso|length %} +
+

{% trans 'Nenhuma norma teve acesso neste ano.'%}

+ {% else %} + {% for mes, normas in normas_mes.items %} +
+
Date: Wed, 12 Dec 2018 19:02:47 -0200 Subject: [PATCH 006/222] Fixes #2420 (#2424) --- .../migrations/0010_auto_20181212_1900.py | 20 +++++++++++++++++++ sapl/protocoloadm/models.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 sapl/protocoloadm/migrations/0010_auto_20181212_1900.py diff --git a/sapl/protocoloadm/migrations/0010_auto_20181212_1900.py b/sapl/protocoloadm/migrations/0010_auto_20181212_1900.py new file mode 100644 index 000000000..df5d6c078 --- /dev/null +++ b/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'), + ), + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index aa4e7c0c2..1b061fa18 100644 --- a/sapl/protocoloadm/models.py +++ b/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=260, blank=True, verbose_name=_('Motivo')) timestamp_anulacao = models.DateTimeField(blank=True, null=True) class Meta: From 847ae35b2756e036568182a50eb50940bf063ea6 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Thu, 13 Dec 2018 14:06:54 -0200 Subject: [PATCH 007/222] =?UTF-8?q?add=20condi=C3=A7=C3=A3o=20em=20gera?= =?UTF-8?q?=C3=A7=C3=A3o=20de=20notas=20de=20compila=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index a82f63556..7d28f619a 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -1319,6 +1319,9 @@ class TextEditView(CompMixin, TemplateView): if dispositivo.ta_publicado_id: d = dispositivo.dispositivo_atualizador.dispositivo_pai + if d.auto_inserido: + d = d.dispositivo_pai + ta_publicado = lista_ta_publicado[dispositivo.ta_publicado_id] if\ lista_ta_publicado else dispositivo.ta_publicado From 75ec305d929a8d181a65d6eb9132ea30d55fee28 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Thu, 13 Dec 2018 14:35:39 -0200 Subject: [PATCH 008/222] =?UTF-8?q?adequa=20tag=20de=20nota=20de=20compila?= =?UTF-8?q?=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/templatetags/compilacao_filters.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapl/compilacao/templatetags/compilacao_filters.py b/sapl/compilacao/templatetags/compilacao_filters.py index e56478bae..a7fb2eada 100644 --- a/sapl/compilacao/templatetags/compilacao_filters.py +++ b/sapl/compilacao/templatetags/compilacao_filters.py @@ -83,6 +83,9 @@ def nota_automatica(dispositivo, ta_pub_list): if dispositivo.ta_publicado: 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_pub_list else dispositivo.ta_publicado From de9abc05ebcae1be8e37800c966e93e38d5b1700 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 13 Dec 2018 18:10:49 -0200 Subject: [PATCH 009/222] =?UTF-8?q?HOT-FIX:=20muda=20hera=C3=A7=C3=A3o=20d?= =?UTF-8?q?e=20FrenteCrud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/parlamentares/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index ce32475f0..c47d36566 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -288,7 +288,7 @@ def parlamentares_frente_selected(request): return JsonResponse({'id_list': list(lista_parlamentar_id)}) -class FrenteCrud(CrudAux): +class FrenteCrud(Crud): model = Frente help_topic = 'tipo_situa_militar' public = [RP_DETAIL, RP_LIST] From 21015c43853f7ce4151d867ff1d30514917f82d1 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 14 Dec 2018 11:56:47 -0200 Subject: [PATCH 010/222] fix #2344 (#2417) * Faltando form seleciona e view e html * fix #2344 --- sapl/materia/urls.py | 7 ++ sapl/protocoloadm/forms.py | 77 +++++++++++++ sapl/protocoloadm/views.py | 98 +++++++++++++++- .../materia/impressos/ficha_adm_pdf.html | 107 ++++++++++++++++++ .../materia/impressos/impressos.html | 6 +- 5 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 sapl/templates/materia/impressos/ficha_adm_pdf.html diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index 030e5386e..e446e6a64 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -26,6 +26,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, proposicao_texto, recuperar_materia, ExcluirTramitacaoEmLoteView, RetornarProposicao) from sapl.norma.views import NormaPesquisaSimplesView +from sapl.protocoloadm.views import (FichaPesquisaAdmView, FichaSelecionaAdmView) from .apps import AppConfig @@ -47,6 +48,12 @@ urlpatterns_impressos = [ url(r'^materia/impressos/norma-pesquisa/$', NormaPesquisaSimplesView.as_view(), 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 = [ diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index a621754b7..0edd63a34 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -1000,3 +1000,80 @@ def filtra_tramitacao_adm_destino_and_status(status, destino): status=status, unidade_tramitacao_destino=destino).distinct().values_list( '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') + ) + ) \ No newline at end of file diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 1d68dfce2..8dd7e9e47 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -29,6 +29,7 @@ from sapl.base.signals import tramitacao_signal from sapl.comissoes.models import Comissao from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa +from sapl.materia.views import gerar_pdf_impressos from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.protocoloadm.models import Protocolo 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, DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, - DocumentoAdministrativoForm, ProtocoloDocumentForm, + DocumentoAdministrativoForm, FichaPesquisaAdmForm, FichaSelecionaAdmForm, ProtocoloDocumentForm, ProtocoloFilterSet, ProtocoloMateriaForm, TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm, @@ -1073,3 +1074,98 @@ class DesvincularMateriaView(PermissionRequiredMixin, FormView): materia.numero_protocolo = None materia.save() 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') \ No newline at end of file diff --git a/sapl/templates/materia/impressos/ficha_adm_pdf.html b/sapl/templates/materia/impressos/ficha_adm_pdf.html new file mode 100644 index 000000000..b5de1e0a9 --- /dev/null +++ b/sapl/templates/materia/impressos/ficha_adm_pdf.html @@ -0,0 +1,107 @@ + + + + + + + + + + +
+ +
+ + PROCESSO Nº: {{ documento.numero }} / {{documento.ano}}
+
+ + +
+ + {{documento.tipo}}: {{documento.numero}} / {{documento.ano}}
+
+ + + +
+ + Data de entrada: {{documento.data}}
+
+ + {% if documento.protocolo%} + + +
+
+ Protocolo: {{materia.protocolo}}
+
+ {% endif %} + + + + +
+
+ Ementa: {{documento.assunto}} +
+
+ + +
+ + + diff --git a/sapl/templates/materia/impressos/impressos.html b/sapl/templates/materia/impressos/impressos.html index 71f9f6f6f..5f6001027 100644 --- a/sapl/templates/materia/impressos/impressos.html +++ b/sapl/templates/materia/impressos/impressos.html @@ -26,7 +26,11 @@ - +
+

Capa Documento Administrativo

+ {#

Guia de Remessa

#} {#
    #} From b2786fbed541d8c9c2ff420097c93c9c5db7f5ad Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 14 Dec 2018 11:56:54 -0200 Subject: [PATCH 011/222] fix #2419 (#2425) * fix #2419 * edita teste --- .../migrations/0019_auto_20181214_1023.py | 20 +++++++++++++++++++ sapl/comissoes/models.py | 1 + sapl/comissoes/tests/test_comissoes.py | 3 +-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 sapl/comissoes/migrations/0019_auto_20181214_1023.py diff --git a/sapl/comissoes/migrations/0019_auto_20181214_1023.py b/sapl/comissoes/migrations/0019_auto_20181214_1023.py new file mode 100644 index 000000000..669ea20c6 --- /dev/null +++ b/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)'), + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index f9ffa97fa..2792c80d6 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -221,6 +221,7 @@ class Reuniao(models.Model): null=True, verbose_name=_('Horário de Início (hh:mm)')) hora_fim = models.TimeField( + blank=True, null=True, verbose_name=_('Horário de Término (hh:mm)')) local_reuniao = models.CharField( diff --git a/sapl/comissoes/tests/test_comissoes.py b/sapl/comissoes/tests/test_comissoes.py index d2f8b0bd1..3b45bf337 100644 --- a/sapl/comissoes/tests/test_comissoes.py +++ b/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['data'] == [_('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 From 6d1494647e0b09fcd2ece02359de2bbb48a401cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rog=C3=A9rio=20Fr=C3=A1?= Date: Fri, 14 Dec 2018 11:58:12 -0200 Subject: [PATCH 012/222] Retira titulo do extrato da sessao quando nao tem conteudo (#2414) --- .../sessao/blocos_ata/expedientes.html | 2 + .../blocos_ata/identificacao_basica.html | 8 ++-- .../sessao/blocos_ata/lista_presenca.html | 4 ++ .../blocos_ata/lista_presenca_ordem_dia.html | 15 ++++---- .../blocos_ata/materias_expediente.html | 2 + .../sessao/blocos_ata/materias_ordem_dia.html | 37 ++++++++++--------- .../sessao/blocos_ata/mesa_diretora.html | 2 + .../blocos_ata/ocorrencias_da_sessao.html | 4 +- .../blocos_ata/oradores_expediente.html | 2 + .../blocos_ata/oradores_explicacoes.html | 10 +++-- 10 files changed, 52 insertions(+), 34 deletions(-) diff --git a/sapl/templates/sessao/blocos_ata/expedientes.html b/sapl/templates/sessao/blocos_ata/expedientes.html index 6d199bab3..55df4e9d9 100644 --- a/sapl/templates/sessao/blocos_ata/expedientes.html +++ b/sapl/templates/sessao/blocos_ata/expedientes.html @@ -1,9 +1,11 @@

    + {% if expedientes %} Expedientes: {% for e in expedientes %} {{e.tipo}}: {{e.conteudo|striptags|safe}} {% endfor %} + {% endif %}

    diff --git a/sapl/templates/sessao/blocos_ata/identificacao_basica.html b/sapl/templates/sessao/blocos_ata/identificacao_basica.html index da0a67b42..a6ec9c8c0 100644 --- a/sapl/templates/sessao/blocos_ata/identificacao_basica.html +++ b/sapl/templates/sessao/blocos_ata/identificacao_basica.html @@ -1,8 +1,8 @@

    - Identificação Básica: - {% for b in basica %} - {{b}} ; - {% endfor %} + Identificação Básica: + {% for b in basica %} + {{b}} ; + {% endfor %}

    \ No newline at end of file diff --git a/sapl/templates/sessao/blocos_ata/lista_presenca.html b/sapl/templates/sessao/blocos_ata/lista_presenca.html index 621a4783c..68e869cb5 100644 --- a/sapl/templates/sessao/blocos_ata/lista_presenca.html +++ b/sapl/templates/sessao/blocos_ata/lista_presenca.html @@ -2,15 +2,19 @@

    + {% if presenca_sessao %} Lista de Presença na Sessão: {% for p in presenca_sessao %} {{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ; {% endfor %} + {% endif %}

    + {% if justificativa_ausencia %} Justificativas de Ausências na Sessão: {% for j in justificativa_ausencia %} {{j.parlamentar}} / {{ j.tipo_ausencia }} ; {% endfor %} + {% endif %}

    diff --git a/sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html b/sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html index b118ebe6e..685ffd2bd 100644 --- a/sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html +++ b/sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html @@ -1,11 +1,12 @@ {% load common_tags %}
    -

    - Lista de Presença na Ordem do Dia: - {% for p in presenca_ordem %} - {{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ; - {% endfor %} -

    - +

    + {% if presenca_ordem %} + Lista de Presença na Ordem do Dia: + {% for p in presenca_ordem %} + {{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }} ; + {% endfor %} + {% endif %} +

    diff --git a/sapl/templates/sessao/blocos_ata/materias_expediente.html b/sapl/templates/sessao/blocos_ata/materias_expediente.html index 395abf0cc..7613448fc 100644 --- a/sapl/templates/sessao/blocos_ata/materias_expediente.html +++ b/sapl/templates/sessao/blocos_ata/materias_expediente.html @@ -1,5 +1,6 @@

    + {% if materia_expediente %} Matérias do Expediente: {% for m in materia_expediente %} {{m.numero}} - {{m.titulo}} @@ -21,5 +22,6 @@ {{m.ementa|safe}} {{m.resultado}} {{m.resultado_observacao}}

+ + + + + +

Mês: {{ mes }}

+ {% if not mes in meses_sem_acesso %} + + + + + + + + + + {% for n in normas %} + {% if n.1 > 0 %} + + + + + + {% endif %} + {% endfor %} + +
NormaEmentaAcessos
+ {{n.0.tipo.descricao}} - {{n.0.tipo.sigla}} {{n.0.numero}}/{{n.0.ano}} + {{n.0.ementa}}
{{n.0.observacao}}
{{n.1}}
+ {% else %} +

{% trans 'Nenhuma norma deste mês teve acessos.'%}

+

+ {% endif %} + + {% endfor %} + {% endif %} + {% endif %} +{% endblock base_content %} diff --git a/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html b/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html index cca46d3ad..1151cd094 100644 --- a/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html +++ b/sapl/templates/base/RelatorioHistoricoTramitacao_filter.html @@ -30,7 +30,7 @@ {{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} - {{materia.ementa}} + {{materia.ementa}}
{{materia.observacao}} {% endfor %} diff --git a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html index 6a8ed41a8..35e9aa50c 100644 --- a/sapl/templates/base/RelatorioMateriasPorAutor_filter.html +++ b/sapl/templates/base/RelatorioMateriasPorAutor_filter.html @@ -51,7 +51,7 @@ {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} - {% autoescape off %}{{materia.ementa}}{% endautoescape %} + {% autoescape off %}{{materia.ementa}}
{{materia.observacao}}{% endautoescape %} {% if materia.autoria_set.first != materia.autoria_set.last %} {% for autor in materia.autoria_set.all %} diff --git a/sapl/templates/base/RelatorioNormaMes_filter.html b/sapl/templates/base/RelatorioNormaMes_filter.html new file mode 100644 index 000000000..d4f8d5b30 --- /dev/null +++ b/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 %} + +



+ PARÂMETROS DE PESQUISA:
+  Ano: {{ ano }}
+
+ {% if normas_mes|length == 0 %} +
+

{% trans 'Não foi encontrada nenhuma norma com os parâmetros buscados.'%}

+ {% endif %} + {% for mes, normas in normas_mes.items %} +
+ + + + + + +

Mês: {{ mes }}

+ + + + {% for k, v in quant_normas_mes.items %} + {% if k == mes %} + {% if v > 1 %} + + {% else %} + + {% endif %} + {% endif %} + {% endfor %} + + +
Quantidade encontrada no mês: {{ v }} normas.Quantidade encontrada no mês: 1 norma.
+ + + + + + + + + {% for n in normas %} + + + + + {% endfor %} + +
NormaEmenta
+ {{n.tipo.descricao}} - {{n.tipo.sigla}} {{n.numero}}/{{n.ano}} + {{n.ementa}}
{{n.observacao}}
+
+ {% endfor %} + {% endif %} +{% endblock base_content %} diff --git a/sapl/templates/base/RelatorioNormasVigencia_filter.html b/sapl/templates/base/RelatorioNormasVigencia_filter.html new file mode 100644 index 000000000..6412b5b20 --- /dev/null +++ b/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 %} + +



+ PARÂMETROS DE PESQUISA:
+  Ano: {{ ano }}
+  Vigência: {{ vigencia }}
+ {% if object_list %} +
+ {% if object_list|length > 1 %} +

Foram encontradas {{object_list|length}} normas.

+ {% else %} +

Foi encontrada 1 norma.

+ {% endif %} +
+ + + + + + + + + {% for norma in object_list %} + + + + + {% endfor %} + +
NormaEmenta
+ {{norma.tipo.descricao}} - {{norma.tipo.sigla}} {{norma.numero}}/{{norma.ano}} + {{norma.ementa}}
{{norma.observacao}}
+ {% else %} + + + + + + +
Não foi encontrada nenhuma norma com os parâmetros buscados.
+ {% endif %} +
+

Estatísticas das normas do ano:


+

{{quant_vigente}} vigente(s) / {{quant_nao_vigente}} não vigente(s)

+ {% endif %} +{% endblock base_content %} diff --git a/sapl/templates/base/layouts.yaml b/sapl/templates/base/layouts.yaml index ef1e53d2a..4f6bbd45d 100644 --- a/sapl/templates/base/layouts.yaml +++ b/sapl/templates/base/layouts.yaml @@ -23,6 +23,9 @@ AppConfig: {% trans 'Textos Articulados' %}: - texto_articulado_proposicao texto_articulado_materia texto_articulado_norma + {% trans 'Estatísticas de acesso' %}: + - estatisticas_acesso_normas + {% trans 'Assinaturas' %}: - assinatura_ata diff --git a/sapl/templates/base/relatorios_list.html b/sapl/templates/base/relatorios_list.html index 78192855a..87f8933be 100644 --- a/sapl/templates/base/relatorios_list.html +++ b/sapl/templates/base/relatorios_list.html @@ -48,6 +48,20 @@ Audiência Pública Audiência Pública com o tipo. + + Normas por mês + Normas publicadas por mês. + + + Normas por vigência + Normas vigentes ou não vigentes. + + {% if estatisticas_acesso_normas %} + + Estatísticas de acesso de Normas. + Normas por acesso. + + {% endif %} From baf2bbd8985dd1fe5df0d1f99ff0f4139f41f111 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Wed, 19 Dec 2018 12:20:08 -0200 Subject: [PATCH 018/222] fix #2430 (#2431) * fix #2430 * Corrige pep8 * minor fix --- requirements/requirements.txt | 2 +- sapl/api/forms.py | 26 +++++++------- sapl/base/forms.py | 65 ++++++++++++++++------------------- sapl/materia/forms.py | 52 +++++++++++++--------------- sapl/norma/forms.py | 13 ++++--- sapl/protocoloadm/forms.py | 26 +++++++------- 6 files changed, 86 insertions(+), 98 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 556c5d112..bb93e9f0e 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -9,7 +9,7 @@ django-compressor==2.0 django-crispy-forms==1.6.1 django-extensions==1.9.8 django-extra-views==0.11.0 -django-filter==0.15.3 +django-filter==1.0.0 django-floppyforms==1.6.2 django-model-utils==3.1.1 django-sass-processor==0.5.8 diff --git a/sapl/api/forms.py b/sapl/api/forms.py index c36a0c11f..b9ad11aca 100644 --- a/sapl/api/forms.py +++ b/sapl/api/forms.py @@ -5,9 +5,8 @@ from django.forms.fields import CharField, MultiValueField from django.forms.widgets import MultiWidget, TextInput from django.utils import timezone 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.compat import django_filters from rest_framework.filters import FilterSet from sapl.base.models import Autor, TipoAutor @@ -16,9 +15,9 @@ from sapl.utils import generic_relations_for_model 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(' ') if query: @@ -87,12 +86,12 @@ class SearchForFieldField(MultiValueField): return None -class SearchForFieldFilter(django_filters.filters.MethodFilter): +class SearchForFieldFilter(CharFilter): field_class = SearchForFieldField class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet): - q = MethodFilter() + q = CharFilter(method='filter_q') tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all()) class Meta: @@ -101,18 +100,18 @@ class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet): 'tipo', 'nome', ] - def filter_q(self, queryset, value): + def filter_q(self, queryset, name,value): return SaplGenericRelationSearchFilterSet.filter_q( self, queryset, value).distinct('nome').order_by('nome') class AutorSearchForFieldFilterSet(AutorChoiceFilterSet): - q = SearchForFieldFilter() + q = SearchForFieldFilter(method='filter_q') class Meta(AutorChoiceFilterSet.Meta): pass - def filter_q(self, queryset, value): + def filter_q(self, queryset, name, value): value[0] = value[0].split(',') value[1] = value[1].split(',') @@ -128,7 +127,7 @@ class AutorSearchForFieldFilterSet(AutorChoiceFilterSet): class AutoresPossiveisFilterSet(FilterSet): logger = logging.getLogger(__name__) data_relativa = DateFilter(method='filter_data_relativa') - tipo = MethodFilter() + tipo = CharFilter(method='filter_tipo') class Meta: model = Autor @@ -137,10 +136,11 @@ class AutoresPossiveisFilterSet(FilterSet): def filter_data_relativa(self, queryset, name, value): return queryset - def filter_tipo(self, queryset, value): - + def filter_tipo(self, queryset, name, value): + 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) except: self.logger.error("TipoAutor(pk={}) inexistente.".format(value)) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index ec69c50d9..36267dbc3 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -655,14 +655,13 @@ class AutorFormForAdmin(AutorForm): 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: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = SessaoPlenaria fields = ['data_inicio'] @@ -768,14 +767,13 @@ class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet): class RelatorioPresencaSessaoFilterSet(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: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = SessaoPlenaria fields = ['data_inicio'] @@ -802,19 +800,18 @@ class RelatorioPresencaSessaoFilterSet(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 def qs(self): parent = super(RelatorioHistoricoTramitacaoFilterSet, self).qs return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') 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 fields = ['tipo', 'tramitacao__unidade_tramitacao_local', 'tramitacao__status', 'tramitacao__data_tramitacao'] @@ -842,19 +839,18 @@ class RelatorioHistoricoTramitacaoFilterSet(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 def qs(self): parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') 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 fields = ['tipo', 'tramitacao__unidade_tramitacao_local', 'tramitacao__status', 'tramitacao__data_fim_prazo'] @@ -1014,13 +1010,6 @@ class RelatorioMateriasPorAnoAutorTipoFilterSet(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()) @property @@ -1030,6 +1019,12 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet): .order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero') 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 fields = ['tipo', 'data_apresentacao'] diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 39dd4c24d..454cd9890 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -757,13 +757,6 @@ class AnexadaForm(ModelForm): 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, label='Ano da Matéria', choices=ANO_CHOICES) @@ -794,6 +787,12 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): o = MateriaPesquisaOrderingFilter() 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 fields = ['numero', 'numero_protocolo', @@ -1032,14 +1031,13 @@ class AutoriaMultiCreateForm(Form): 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: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = MateriaLegislativa fields = ['tipo', 'data_apresentacao'] @@ -1063,14 +1061,13 @@ class AcessorioEmLoteFilterSet(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: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = MateriaLegislativa fields = ['tipo', 'data_apresentacao'] @@ -1095,14 +1092,13 @@ class PrimeiraTramitacaoEmLoteFilterSet(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: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = MateriaLegislativa fields = ['tipo', 'data_apresentacao', 'tramitacao__status', 'tramitacao__unidade_tramitacao_destino'] diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 4f6b6a563..7cd8368f7 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -41,13 +41,6 @@ ORDENACAO_CHOICES = [('', '---------'), 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, label='Ano', choices=ANO_CHOICES) @@ -63,6 +56,12 @@ class NormaFilterSet(django_filters.FilterSet): o = NormaPesquisaOrderingFilter() 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 fields = ['tipo', 'numero', 'ano', 'data', 'data_vigencia', 'data_publicacao', 'ementa', 'assuntos'] diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 0edd63a34..97cab4eee 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -66,13 +66,6 @@ class AcompanhamentoDocumentoForm(ModelForm): 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, label='Ano', choices=ANO_CHOICES) @@ -99,6 +92,12 @@ class ProtocoloFilterSet(django_filters.FilterSet): o = AnoNumeroOrderingFilter() class Meta: + filter_overrides = {models.DateTimeField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': 'Data (%s)' % (_('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = Protocolo fields = ['numero', 'tipo_documento', @@ -154,13 +153,6 @@ class ProtocoloFilterSet(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, label='Ano', choices=ANO_CHOICES) @@ -176,6 +168,12 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): o = AnoNumeroOrderingFilter() class Meta: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': 'Data (%s)' % (_('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} model = DocumentoAdministrativo fields = ['tipo', 'numero', From 956e0898e2a749e269de93ab14119c4095b715a0 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Wed, 19 Dec 2018 12:22:34 -0200 Subject: [PATCH 019/222] =?UTF-8?q?Fix=20#2099=20-=20Vota=C3=A7=C3=A3o=20e?= =?UTF-8?q?m=20bloco=20(#2416)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * votacao em bloco * votacao em bloco - em andamento * feita a tela de votacao em bloco * feita a tela de votacao em bloco * votacao em bloco- em andamento * inicio da nova tela da votacao em bloco - em andamento * inicio da nova tela da votacao em bloco - em andamento * Tela de votacao em bloco simbolica. Em progresso. * tela votacao em bloco exibindo as informacoes corretas * Check all incluso para seleção de ordens desejadas. * inicio da tela de votacao para votacao em bloco ordem dia * Alteracoes na votacao em bloco * adicionado salvamento da votacao * correcoes na votacao e no checkbox de marcar todos * adicionada votacao em bloco nominal no expediente * inicio da votacao nominal em bloco * Tela votacao em bloco. * votacao nominal em bloco * pequenas mudancas * inicio da correcao de alguns bugs, como formulario invalido * correcao de erro quando nao ha presentes * correcoes de erros * cancelar votacao simbolica * correcoes diversas e insercao dos menus * Menu adicionado * votacao em bloco * ajusta menu e lança erro se root_pk ou object estiver faltando no contexto * ajusta contexto para votação em bloco no expediente --- sapl/base/templatetags/menus.py | 58 +- sapl/materia/models.py | 1 + sapl/relatorios/views.py | 1 - sapl/sessao/forms.py | 126 +- sapl/sessao/urls.py | 18 +- sapl/sessao/views.py | 615 ++++++++- sapl/static/styles/app.css | 503 ++++++++ sapl/static/styles/compilacao.css | 1136 +++++++++++++++++ sapl/templates/auth/user_list.html | 3 +- sapl/templates/sessao/subnav.yaml | 4 + sapl/templates/sessao/votacao/nominal.html | 76 +- .../votacao/votacao_bloco_expediente.html | 173 +++ .../sessao/votacao/votacao_bloco_ordem.html | 174 +++ .../sessao/votacao/votacao_nominal_bloco.html | 149 +++ .../votacao/votacao_simbolica_bloco.html | 80 ++ 15 files changed, 3009 insertions(+), 108 deletions(-) create mode 100644 sapl/static/styles/app.css create mode 100644 sapl/static/styles/compilacao.css create mode 100644 sapl/templates/sessao/votacao/votacao_bloco_expediente.html create mode 100644 sapl/templates/sessao/votacao/votacao_bloco_ordem.html create mode 100644 sapl/templates/sessao/votacao/votacao_nominal_bloco.html create mode 100644 sapl/templates/sessao/votacao/votacao_simbolica_bloco.html diff --git a/sapl/base/templatetags/menus.py b/sapl/base/templatetags/menus.py index 289cd20e6..5b526002a 100644 --- a/sapl/base/templatetags/menus.py +++ b/sapl/base/templatetags/menus.py @@ -1,3 +1,5 @@ +import logging + from django import template from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ @@ -6,6 +8,8 @@ import yaml register = template.Library() +logger = logging.getLogger(__name__) + @register.inclusion_tag('menus/menu.html', takes_context=True) def menu(context, path=None): @@ -84,7 +88,7 @@ def nav_run(context, path=None): menu = yaml.load(rendered) resolve_urls_inplace(menu, root_pk, rm, context) except Exception as e: - print(_("""Erro na conversão do yaml %s. App: %s. + raise Exception(_("""Erro na conversão do yaml %s. App: %s. Erro: %s """) % ( @@ -113,25 +117,61 @@ def resolve_urls_inplace(menu, pk, rm, context): menu['url'] = '' menu['active'] = '' else: - if ':' in url_name: + if '/' in url_name: + pass + elif ':' in url_name: try: - menu['url'] = reverse('%s' % menu['url'], - kwargs={'pk': pk}) + menu['url'] = reverse('%s' % menu['url']) except: try: - menu['url'] = reverse('%s' % menu['url']) + menu['url'] = reverse('%s' % menu['url'], + kwargs={'pk': pk}) except: - pass + # tem que ser root_pk pois quando está sendo + # renderizado um detail, update, delete + # e ainda sim é necessário colocar o menu, + # nestes, casos o pk da url é do detail, e não + # do master, porém, os menus do subnav, apontam para + # outras áreas que as urls destas são construídas + # com pk do master, e não do detail... por isso + # no contexto deve ter, ou root_pk, ou object + # sendo que qualquer um dos dois,deverá ser o + # master. + # Estes detalhes são relevantes quando usa-se + # o menu isolado. Por outro lado, quando usado + # conjuntamente com o crud, este configura o contexto + # como se deve para o menus.py + log = """ + Erro na construção do Menu: + menu: {} + url: {} + 1) Verifique se a url existe + 2) Se existe no contexto um desses itens: + - context['root_pk'] pk do master + - context['object'] objeto do master + """.format(menu['title'], menu['url']) + logger.error(log) + raise Exception(log) + else: try: menu['url'] = reverse('%s:%s' % ( - rm.app_name, menu['url']), kwargs={'pk': pk}) + rm.app_name, menu['url'])) except: try: menu['url'] = reverse('%s:%s' % ( - rm.app_name, menu['url'])) + rm.app_name, menu['url']), kwargs={'pk': pk}) except: - pass + log = """Erro na construção do Menu: + menu: {} + url: {} + 1) Verifique se a url existe + 2) Se existe no contexto um desses itens: + - context['root_pk'] pk do master + - context['object'] objeto do master + """.format(menu['title'], menu['url']) + logger.error(log) + raise Exception(log) menu['active'] = 'active'\ if context['request'].path == menu['url'] else '' diff --git a/sapl/materia/models.py b/sapl/materia/models.py index 6f322c09c..cfcb71ffc 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -16,6 +16,7 @@ from sapl.comissoes.models import Comissao from sapl.compilacao.models import (PerfilEstruturalTextoArticulado, TextoArticulado) from sapl.parlamentares.models import Parlamentar +#from sapl.protocoloadm.models import Protocolo from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, SaplGenericForeignKey, SaplGenericRelation, restringe_tipos_de_arquivo_txt, texto_upload_path) diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index a8daa645a..0c5dfd377 100755 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -1111,7 +1111,6 @@ def get_pauta_sessao(sessao, casa): sessao_plenaria=sessao): materia = MateriaLegislativa.objects.filter( id=votacao.materia.id).first() - dic_votacao = {} dic_votacao["tipo_materia"] = materia.tipo.sigla + ' - ' + materia.tipo.descricao dic_votacao["num_ordem"] = votacao.numero_ordem diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index d2e00f47c..5a3cde342 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -1,4 +1,4 @@ - +from django.contrib import messages from datetime import datetime from crispy_forms.helper import FormHelper @@ -23,11 +23,10 @@ from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, MateriaPesquisaOrderingFilter, autor_label, autor_modal, timezone) -from .models import (Bancada, Bloco, ExpedienteMateria, Orador, JustificativaAusencia, - OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, - SessaoPlenariaPresenca, TipoResultadoVotacao, OcorrenciaSessao, - RetiradaPauta, TipoRetiradaPauta) - +from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia, + Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, + SessaoPlenariaPresenca, TipoJustificativa, TipoResultadoVotacao, + OcorrenciaSessao, RegistroVotacao, RetiradaPauta, TipoRetiradaPauta) def recupera_anos(): @@ -520,12 +519,43 @@ class OcorrenciaSessaoForm(ModelForm): class VotacaoForm(forms.Form): - votos_sim = forms.CharField(label='Sim') - votos_nao = forms.CharField(label='Não') - abstencoes = forms.CharField(label='Abstenções') - total_votos = forms.CharField(required=False, label='total') + votos_sim = forms.IntegerField(label='Sim') + votos_nao = forms.IntegerField(label='Não') + abstencoes = forms.IntegerField(label='Abstenções') + total_presentes = forms.IntegerField(required=False, widget=forms.HiddenInput()) + voto_presidente = forms.IntegerField(label='A totalização inclui o voto do Presidente?') + total_votos = forms.IntegerField(required=False, label='total') + observacao = forms.CharField(required=False , label='Observação') resultado_votacao = forms.CharField(label='Resultado da Votação') + def clean(self): + cleaned_data = super(VotacaoForm, self).clean() + if not self.is_valid(): + return cleaned_data + + votos_sim = cleaned_data['votos_sim'] + votos_nao = cleaned_data['votos_nao'] + abstencoes = cleaned_data['abstencoes'] + qtde_presentes = cleaned_data['total_presentes'] + qtde_votos = votos_sim + votos_nao + abstencoes + voto_presidente = cleaned_data['voto_presidente'] + + if not voto_presidente: + qtde_presentes -= 1 + + if qtde_votos != qtde_presentes: + raise ValidationError('O total de votos não corresponde com a quantidade de presentes!') + + return cleaned_data + + # def save(self, commit=False): + # #TODO Verificar se esse códido é utilizado + + # votacao = super(VotacaoForm, self).save(commit) + # votacao.materia = self.cleaned_data['materia'] + # votacao.save() + # return votacao + class VotacaoNominalForm(forms.Form): resultado_votacao = forms.ModelChoiceField(label='Resultado da Votação', @@ -891,3 +921,79 @@ class JustificativaAusenciaForm(ModelForm): justificativa.materias_do_expediente.clear() justificativa.materias_da_ordem_do_dia.clear() return justificativa + + +class VotacaoEmBlocoFilterSet(MateriaLegislativaFilterSet): + + o = MateriaPesquisaOrderingFilter() + tramitacao__status = django_filters.ModelChoiceFilter( + required=True, + queryset=StatusTramitacao.objects.all(), + label=_('Status da Matéria')) + + class Meta: + model = MateriaLegislativa + fields = ['tramitacao__status', + 'numero', + 'numero_protocolo', + 'ano', + 'tipo', + 'data_apresentacao', + 'data_publicacao', + 'autoria__autor__tipo', + # FIXME 'autoria__autor__partido', + 'relatoria__parlamentar_id', + 'local_origem_externa', + 'em_tramitacao', + ] + + def __init__(self, *args, **kwargs): + super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs) + + self.filters['tipo'].label = 'Tipo de Matéria' + self.filters['autoria__autor__tipo'].label = 'Tipo de Autor' + # self.filters['autoria__autor__partido'].label = 'Partido do Autor' + self.filters['relatoria__parlamentar_id'].label = 'Relatoria' + + row1 = to_row( + [('tramitacao__status', 12)]) + row2 = to_row( + [('tipo', 12)]) + row3 = to_row( + [('numero', 4), + ('ano', 4), + ('numero_protocolo', 4)]) + row4 = to_row( + [('data_apresentacao', 6), + ('data_publicacao', 6)]) + row5 = to_row( + [('autoria__autor', 0), + (Button('pesquisar', + 'Pesquisar Autor', + css_class='btn btn-primary btn-sm'), 2), + (Button('limpar', + 'limpar Autor', + css_class='btn btn-primary btn-sm'), 10)]) + row6 = to_row( + [('autoria__autor__tipo', 6), + # ('autoria__autor__partido', 6) + ]) + row7 = to_row( + [('relatoria__parlamentar_id', 6), + ('local_origem_externa', 6)]) + row8 = to_row( + [('em_tramitacao', 6), + ('o', 6)]) + row9 = to_row( + [('ementa', 12)]) + + self.form.helper = FormHelper() + self.form.helper.form_method = 'GET' + self.form.helper.layout = Layout( + Fieldset(_('Pesquisa de Matéria'), + row1, row2, row3, + HTML(autor_label), + HTML(autor_modal), + row4, row5, row6, row7, row8, row9, + form_actions(label='Pesquisar')) + ) \ No newline at end of file diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py index f9b07967d..9bcb414b6 100644 --- a/sapl/sessao/urls.py +++ b/sapl/sessao/urls.py @@ -28,7 +28,9 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente, remove_parlamentar_composicao, reordernar_materias_expediente, reordernar_materias_ordem, - sessao_legislativa_legislatura_ajax) + sessao_legislativa_legislatura_ajax, + VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente, + VotacaoEmBlocoSimbolicaView,VotacaoEmBlocoNominalView) from .apps import AppConfig @@ -115,6 +117,16 @@ urlpatterns = [ url(r'^sessao/(?P\d+)/presencaordemdia$', PresencaOrdemDiaView.as_view(), name='presencaordemdia'), + url(r'^sessao/(?P\d+)/votacao_bloco_ordemdia$', + VotacaoEmBlocoOrdemDia.as_view(), + name='votacao_bloco_ordemdia'), + url(r'^sessao/(?P\d+)/votacao_bloco/votnom$', + VotacaoEmBlocoNominalView.as_view(), name='votacaobloconom'), + url(r'^sessao/(?P\d+)/votacao_bloco/votsimb$', + VotacaoEmBlocoSimbolicaView.as_view(), name='votacaoblocosimb'), + url(r'^sessao/(?P\d+)/votacao_bloco_expediente$', + VotacaoEmBlocoExpediente.as_view(), + name='votacao_bloco_expediente'), url(r'^sessao/(?P\d+)/resumo$', ResumoView.as_view(), name='resumo'), url(r'^sessao/(?P\d+)/resumo_ata$', @@ -133,6 +145,10 @@ urlpatterns = [ VotacaoEditView.as_view(), name='votacaosecretaedit'), url(r'^sessao/(?P\d+)/matordemdia/votsimb/(?P\d+)/(?P\d+)$', VotacaoView.as_view(), name='votacaosimbolica'), + + url(r'^sessao/(?P\d+)/matordemdia/votsimbbloco/$', + VotacaoView.as_view(), name='votacaosimbolicabloco'), + url(r'^sessao/(?P\d+)/matordemdia/votsimb' '/view/(?P\d+)/(?P\d+)$', VotacaoEditView.as_view(), name='votacaosimbolicaedit'), diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 98ca3815c..b705e302f 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1,6 +1,6 @@ -from operator import itemgetter import logging +from operator import itemgetter from re import sub from django.contrib import messages @@ -57,7 +57,8 @@ TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria') TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente') TipoJustificativaCrud = CrudAux.build(TipoJustificativa, 'tipo_justificativa') CargoBancadaCrud = CrudAux.build(CargoBancada, '') -TipoResultadoVotacaoCrud = CrudAux.build(TipoResultadoVotacao, 'tipo_resultado_votacao') +TipoResultadoVotacaoCrud = CrudAux.build( + TipoResultadoVotacao, 'tipo_resultado_votacao') TipoRetiradaPautaCrud = CrudAux.build(TipoRetiradaPauta, 'tipo_retirada_pauta') @@ -87,7 +88,8 @@ def verifica_presenca(request, model, spk): logger = logging.getLogger(__name__) if not model.objects.filter(sessao_plenaria_id=spk).exists(): username = request.user.username - logger.error("user=" + username + ". Votação não pode ser aberta sem presenças (sessao_plenaria_id={}).".format(spk)) + logger.error("user=" + username + + ". Votação não pode ser aberta sem presenças (sessao_plenaria_id={}).".format(spk)) msg = _('Votação não pode ser aberta sem presenças') messages.add_message(request, messages.ERROR, msg) return False @@ -301,7 +303,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente): retirada_descricao = retirada.tipo_de_retirada.descricao retirada_observacao = retirada.observacao url = reverse('sapl.sessao:retiradapauta_detail', - kwargs={'pk': retirada.id}) + kwargs={'pk': retirada.id}) resultado = ('%s
%s
' % (url, retirada_descricao, @@ -798,7 +800,8 @@ class PresencaView(FormMixin, PresencaMixin, DetailView): sessao.parlamentar = Parlamentar.objects.get(id=p) sessao.save() username = request.user.username - self.logger.info("user=" + username + ". SessaoPlenariaPresenca salva com sucesso (parlamentar_id={})!".format(p)) + self.logger.info( + "user=" + username + ". SessaoPlenariaPresenca salva com sucesso (parlamentar_id={})!".format(p)) msg = _('Presença em Sessão salva com sucesso!') messages.add_message(request, messages.SUCCESS, msg) @@ -850,7 +853,7 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView): cronometro_aparte = cronometro_aparte.seconds cronometro_ordem = cronometro_ordem.seconds cronometro_consideracoes = cronometro_consideracoes.seconds - + context = TemplateView.get_context_data(self, **kwargs) context.update({ 'head_title': str(_('Painel Plenário')), @@ -904,9 +907,10 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView): ordem.sessao_plenaria = self.object ordem.parlamentar = Parlamentar.objects.get(id=p) ordem.save() + username = request.user.username + self.logger.info( + 'user=' + username + '. PresencaOrdemDia (parlamentar com id={}) salva com sucesso!'.format(p)) - username = request.user.username - self.logger.info('user=' + username + '. PresencaOrdemDia (parlamentar com id={}) salva com sucesso!'.format(p)) msg = _('Presença em Ordem do Dia salva com sucesso!') messages.add_message(request, messages.SUCCESS, msg) @@ -1041,11 +1045,13 @@ class MesaView(FormMixin, DetailView): username = request.user.username try: - self.logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}".format(kwargs['pk'])) + self.logger.debug( + "user=" + username + ". Tentando obter SessaoPlenaria com id={}".format(kwargs['pk'])) sessao = SessaoPlenaria.objects.get( id=kwargs['pk']) except ObjectDoesNotExist: - self.logger.error("user=" + username + ". SessaoPlenaria com id={} não existe.".format(kwargs['pk'])) + self.logger.error( + "user=" + username + ". SessaoPlenaria com id={} não existe.".format(kwargs['pk'])) mensagem = _('Esta Sessão Plenária não existe!') messages.add_message(request, messages.INFO, mensagem) @@ -1100,11 +1106,13 @@ def atualizar_mesa(request): logger = logging.getLogger(__name__) username = request.user.username try: - logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}.".format(request.GET['sessao'])) + logger.debug("user=" + username + + ". Tentando obter SessaoPlenaria com id={}.".format(request.GET['sessao'])) sessao = SessaoPlenaria.objects.get( id=int(request.GET['sessao'])) except ObjectDoesNotExist: - logger.error("user=" + username + ". SessaoPlenaria com id={} inexistente.".format(request.GET['sessao'])) + logger.error("user=" + username + + ". SessaoPlenaria com id={} inexistente.".format(request.GET['sessao'])) return JsonResponse({'msg': ('Sessão Inexistente!', 0)}) # Atualiza os componentes da view após a mudança @@ -1152,19 +1160,23 @@ def insere_parlamentar_composicao(request): composicao = IntegranteMesa() try: - logger.debug("user=" + username + ". Tentando obter SessaoPlenaria com id={}.".format(request.POST['sessao'])) + logger.debug( + "user=" + username + ". Tentando obter SessaoPlenaria com id={}.".format(request.POST['sessao'])) composicao.sessao_plenaria = SessaoPlenaria.objects.get( id=int(request.POST['sessao'])) except MultiValueDictKeyError: - logger.error("user=" + username + ". SessaoPlenaria com id={} não existe.".format(request.POST['sessao'])) + logger.error( + "user=" + username + ". SessaoPlenaria com id={} não existe.".format(request.POST['sessao'])) return JsonResponse({'msg': ('A Sessão informada não existe!', 0)}) try: - logger.debug("user=" + username + ". Tentando obter Parlamentar com id={}.".format(request.POST['parlamentar'])) + logger.debug( + "user=" + username + ". Tentando obter Parlamentar com id={}.".format(request.POST['parlamentar'])) composicao.parlamentar = Parlamentar.objects.get( id=int(request.POST['parlamentar'])) except MultiValueDictKeyError: - logger.error("user=" + username + ". Parlamentar com id={} não existe.".format(request.POST['parlamentar'])) + logger.error( + "user=" + username + ". Parlamentar com id={} não existe.".format(request.POST['parlamentar'])) return JsonResponse({ 'msg': ('Nenhum parlamentar foi inserido!', 0)}) @@ -1183,10 +1195,12 @@ def insere_parlamentar_composicao(request): composicao.save() except MultiValueDictKeyError as e: - logger.error("user=" + username + ". Nenhum cargo foi inserido! " + str(e)) + logger.error("user=" + username + + ". Nenhum cargo foi inserido! " + str(e)) return JsonResponse({'msg': ('Nenhum cargo foi inserido!', 0)}) - logger.info("user=" + username + ". Parlamentar (id={}) inserido com sucesso na sessao_plenaria(id={}) e cargo(ìd={}).") + logger.info("user=" + username + + ". Parlamentar (id={}) inserido com sucesso na sessao_plenaria(id={}) e cargo(ìd={}).") return JsonResponse({'msg': ('Parlamentar inserido com sucesso!', 1)}) else: @@ -1207,7 +1221,8 @@ def remove_parlamentar_composicao(request): if 'composicao_mesa' in request.POST: try: - logger.debug("user=" + username + ". Tentando remover IntegranteMesa com id={}".format(request.POST['composicao_mesa'])) + logger.debug("user=" + username + ". Tentando remover IntegranteMesa com id={}".format( + request.POST['composicao_mesa'])) IntegranteMesa.objects.get( id=int(request.POST['composicao_mesa'])).delete() except ObjectDoesNotExist: @@ -1217,12 +1232,14 @@ def remove_parlamentar_composicao(request): {'msg': ( 'Composição da Mesa não pôde ser removida!', 0)}) - logger.info("user=" + username + ". IntegranteMesa com id={} removido com sucesso.") + logger.info("user=" + username + + ". IntegranteMesa com id={} removido com sucesso.") return JsonResponse( {'msg': ( 'Parlamentar excluido com sucesso!', 1)}) else: - logger.debug("user=" + username + ". Nenhum parlamentar selecionado para ser excluido!") + logger.debug("user=" + username + + ". Nenhum parlamentar selecionado para ser excluido!") return JsonResponse( {'msg': ( 'Selecione algum parlamentar para ser excluido!', 0)}) @@ -1349,7 +1366,6 @@ class ResumoView(DetailView): context.update({'presenca_sessao': parlamentares_sessao, 'justificativa_ausencia': ausentes_sessao}) - # ===================================================================== # Expedientes expediente = ExpedienteSessao.objects.filter( @@ -1450,13 +1466,16 @@ class ResumoView(DetailView): config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata if config_assinatura_ata == 'T' and parlamentares_ordem: - context.update({'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'}) + context.update( + {'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'}) context.update({'assinatura_presentes': parlamentares_ordem}) elif config_assinatura_ata == 'M' and parlamentares_mesa_dia: - context.update({'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'}) + context.update( + {'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'}) context.update({'assinatura_presentes': parlamentares_mesa_dia}) elif config_assinatura_ata == 'P' and presidente_dia: - context.update({'texto_assinatura': 'Assinatura do Presidente da Sessão'}) + context.update( + {'texto_assinatura': 'Assinatura do Presidente da Sessão'}) context.update({'assinatura_presentes': presidente_dia}) # ===================================================================== @@ -1609,7 +1628,8 @@ class ExpedienteView(FormMixin, DetailView): if 'apagar-expediente' in request.POST: ExpedienteSessao.objects.filter( sessao_plenaria_id=self.object.id).delete() - self.logger.info('user=' + username + '. ExpedienteSessao de sessao_plenaria_id={} deletado.'.format(self.object.id)) + self.logger.info( + 'user=' + username + '. ExpedienteSessao de sessao_plenaria_id={} deletado.'.format(self.object.id)) return self.form_valid(form) if form.is_valid(): @@ -1635,7 +1655,8 @@ class ExpedienteView(FormMixin, DetailView): return self.form_valid(form) else: - self.logger.error("user=" + username + ". Erro ao salvar registro (sessao_plenaria_id={}).".format(self.object.id)) + self.logger.error( + "user=" + username + ". Erro ao salvar registro (sessao_plenaria_id={}).".format(self.object.id)) msg = _('Erro ao salvar ExpedienteSessao') messages.add_message(self.request, messages.SUCCESS, msg) return self.form_invalid(form) @@ -1705,7 +1726,8 @@ class OcorrenciaSessaoView(FormMixin, DetailView): messages.add_message(self.request, messages.SUCCESS, msg) username = self.request.user.username - self.logger.info('user=' + username + '. OcorrenciaSessao de sessao_plenaria_id={} atualizada com sucesso.'.format(self.object.id)) + self.logger.info( + 'user=' + username + '. OcorrenciaSessao de sessao_plenaria_id={} atualizada com sucesso.'.format(self.object.id)) @method_decorator(permission_required('sessao.add_ocorrenciasessao')) def post(self, request, *args, **kwargs): @@ -1954,14 +1976,16 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): if RegistroVotacao.objects.filter(ordem_id=ordem_id).exists(): msg = _('Esta matéria já foi votada!') messages.add_message(request, messages.ERROR, msg) - self.logger.info('user=' + username + '. Matéria (ordem_id={}) já votada!'.format(ordem_id)) + self.logger.info( + 'user=' + username + '. Matéria (ordem_id={}) já votada!'.format(ordem_id)) return HttpResponseRedirect(reverse( 'sapl.sessao:ordemdia_list', kwargs={'pk': kwargs['pk']})) try: ordem = OrdemDia.objects.get(id=ordem_id) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto OrdemDia (pk={}) não existe.'.format(ordem_id)) + self.logger.error( + 'user=' + username + '. Objeto OrdemDia (pk={}) não existe.'.format(ordem_id)) raise Http404() presentes = PresencaOrdemDia.objects.filter( @@ -1971,7 +1995,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): materia_votacao = ordem if not ordem.votacao_aberta: - self.logger.error('user=' + username + '. A votação para esta OrdemDia (id={}) encontra-se fechada!'.format(ordem_id)) + self.logger.error( + 'user=' + username + '. A votação para esta OrdemDia (id={}) encontra-se fechada!'.format(ordem_id)) msg = _('A votação para esta matéria encontra-se fechada!') messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(reverse( @@ -1984,7 +2009,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): expediente_id = kwargs['oid'] if (RegistroVotacao.objects.filter( expediente_id=expediente_id).exists()): - self.logger.error("user=" + username + ". RegistroVotacao (expediente_id={}) já existe.".format(expediente_id)) + self.logger.error( + "user=" + username + ". RegistroVotacao (expediente_id={}) já existe.".format(expediente_id)) msg = _('Esta matéria já foi votada!') messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(reverse( @@ -1992,10 +2018,12 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): kwargs={'pk': kwargs['pk']})) try: - self.logger.debug("user=" + username + ". Tentando obter Objeto ExpedienteMateria com id={}.".format(expediente_id)) + self.logger.debug( + "user=" + username + ". Tentando obter Objeto ExpedienteMateria com id={}.".format(expediente_id)) expediente = ExpedienteMateria.objects.get(id=expediente_id) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id)) + self.logger.error( + 'user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id)) raise Http404() presentes = SessaoPlenariaPresenca.objects.filter( @@ -2005,7 +2033,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): materia_votacao = expediente if not expediente.votacao_aberta: - msg = _('A votação para este ExpedienteMateria (id={}) encontra-se fechada!'.format(expediente_id)) + msg = _( + 'A votação para este ExpedienteMateria (id={}) encontra-se fechada!'.format(expediente_id)) messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(reverse( 'sapl.sessao:expedientemateria_list', @@ -2033,19 +2062,23 @@ class VotacaoNominalAbstract(SessaoPermissionMixin): if self.ordem: ordem_id = kwargs['oid'] try: - self.logger.debug("user=" + username + ". Tentando obter objeto OrdemDia com id={}.".format(ordem_id)) + self.logger.debug( + "user=" + username + ". Tentando obter objeto OrdemDia com id={}.".format(ordem_id)) materia_votacao = OrdemDia.objects.get(id=ordem_id) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto OrdemDia com id={} não existe.'.format(ordem_id)) + self.logger.error( + 'user=' + username + '. Objeto OrdemDia com id={} não existe.'.format(ordem_id)) raise Http404() elif self.expediente: expediente_id = kwargs['oid'] try: - self.logger.debug("user=" + username + ". Tentando obter ExpedienteMateria com id={}.".format(expediente_id)) + self.logger.debug( + "user=" + username + ". Tentando obter ExpedienteMateria com id={}.".format(expediente_id)) materia_votacao = ExpedienteMateria.objects.get( id=expediente_id) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id)) + self.logger.error( + 'user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id)) raise Http404() if form.is_valid(): @@ -2231,7 +2264,8 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin): votacao = RegistroVotacao.objects.filter(ordem_id=ordem_id).last() if not ordem or not votacao: - self.logger.error('user=' + username + '. Objeto OrdemDia com id={} ou RegistroVotacao de OrdemDia não existe.'.format(ordem_id)) + self.logger.error( + 'user=' + username + '. Objeto OrdemDia com id={} ou RegistroVotacao de OrdemDia não existe.'.format(ordem_id)) raise Http404() materia = ordem.materia @@ -2304,7 +2338,8 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin): try: materia_votacao = OrdemDia.objects.get(id=ordem_id) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto OrdemDia com id={} não existe.'.format(ordem_id)) + self.logger.error( + 'user=' + username + '. Objeto OrdemDia com id={} não existe.'.format(ordem_id)) raise Http404() elif self.expediente: @@ -2314,7 +2349,8 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin): materia_votacao = ExpedienteMateria.objects.get( id=expediente_id) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id)) + self.logger.error( + 'user=' + username + '. Objeto ExpedienteMateria com id={} não existe.'.format(expediente_id)) raise Http404() if(int(request.POST['anular_votacao']) == 1): @@ -2993,7 +3029,8 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin, msg = _('%s adicionado(a) com sucesso!' % MateriaLegislativa.objects.get(id=m)) messages.add_message(request, messages.SUCCESS, msg) - self.logger.info("user=" + username + ". MateriaLegislativa de id={} adicionado(a) com sucesso!".format(m)) + self.logger.info( + "user=" + username + ". MateriaLegislativa de id={} adicionado(a) com sucesso!".format(m)) except MultiValueDictKeyError: msg = _('Formulário Inválido. Você esqueceu de selecionar ' + '%s' % @@ -3068,7 +3105,8 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente): msg = _('%s adicionado(a) com sucesso!' % MateriaLegislativa.objects.get(id=m)) messages.add_message(request, messages.SUCCESS, msg) - self.logger.debug('user=' + username + '. MateriaLegislativa de id={} adicionado(a) com sucesso!'.format(m)) + self.logger.debug( + 'user=' + username + '. MateriaLegislativa de id={} adicionado(a) com sucesso!'.format(m)) except MultiValueDictKeyError: msg = _('Formulário Inválido. Você esqueceu de selecionar ' + 'o tipo de votação de %s' % @@ -3129,7 +3167,8 @@ def mudar_ordem_materia_sessao(request): numero_ordem=posicao_inicial) except ObjectDoesNotExist: username = request.user.username - logger.error("user=" + username + ". Materia com sessao_plenaria={} e numero_ordem={}.".format(pk_sessao, posicao_inicial)) + logger.error("user=" + username + + ". Materia com sessao_plenaria={} e numero_ordem={}.".format(pk_sessao, posicao_inicial)) raise # TODO tratar essa exceção # Se a posição inicial for menor que a final, todos que @@ -3241,13 +3280,494 @@ class JustificativaAusenciaCrud(MasterDetailCrud): pass +class VotacaoEmBlocoExpediente(ListView): + + model = ExpedienteMateria + template_name = 'sessao/votacao/votacao_bloco_expediente.html' + app_label = AppConfig.label + context_object_name = 'expedientes' + logger = logging.getLogger(__name__) + + def get_queryset(self): + kwargs = self.kwargs + return ExpedienteMateria.objects.filter(sessao_plenaria_id=kwargs['pk'], + resultado='') + + def get_context_data(self, **kwargs): + context = super(VotacaoEmBlocoExpediente, + self).get_context_data(**kwargs) + context['turno_choices'] = Tramitacao.TURNO_CHOICES + context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk']) + context['pk'] = self.kwargs['pk'] + context['root_pk'] = self.kwargs['pk'] + return context + + +class VotacaoEmBlocoOrdemDia(ListView): + model = OrdemDia + template_name = 'sessao/votacao/votacao_bloco_ordem.html' + app_label = AppConfig.label + logger = logging.getLogger(__name__) + context_object_name = 'ordem_dia' + parent_field = 'sessao_plenaria' + + def get_queryset(self): + return OrdemDia.objects.filter(sessao_plenaria_id=self.kwargs['pk'], + resultado='') + + def get_context_data(self, **kwargs): + context = super(VotacaoEmBlocoOrdemDia, + self).get_context_data(**kwargs) + context['turno_choices'] = Tramitacao.TURNO_CHOICES + context['pk'] = self.kwargs['pk'] + context['root_pk'] = self.kwargs['pk'] + context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk']) + return context + + +class VotacaoEmBlocoSimbolicaView(TemplateView): + + """ + Votação Simbólica + """ + + template_name = 'sessao/votacao/votacao_simbolica_bloco.html' + logger = logging.getLogger(__name__) + + def post(self, request, *args, **kwargs): + + if not 'context' in locals(): + context = {'pk': self.kwargs['pk'], + 'root_pk': self.kwargs['pk'], + 'title': SessaoPlenaria.objects.get(id=self.kwargs['pk']) + } + + if 'marcadas_1' in request.POST: + + context.update({'resultado_votacao': TipoResultadoVotacao.objects.all(), + 'origem': request.POST['origem']}) + + # marcadas_1 se refere a votação simbólica e marcadas_2 a votação + # nominal + if request.POST['origem'] == 'ordem': + ordens = OrdemDia.objects.filter( + id__in=request.POST.getlist('marcadas_1')) + qtde_presentes = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']).count() + context.update({'ordens': ordens, + 'total_presentes': qtde_presentes}) + else: + expedientes = ExpedienteMateria.objects.filter( + id__in=request.POST.getlist('marcadas_1')) + qtde_presentes = SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=self.kwargs['pk']).count() + context.update({'expedientes': expedientes, + 'total_presentes': qtde_presentes}) + + if 'salvar-votacao' in request.POST: + form = VotacaoForm(request.POST) + + if form.is_valid(): + + origem = request.POST['origem'] + + if origem == 'ordem': + ordens = OrdemDia.objects.filter( + id__in=request.POST.getlist('ordens')) + + for ordem in ordens: + try: + votacao = RegistroVotacao() + votacao.numero_votos_sim = int( + request.POST['votos_sim']) + votacao.numero_votos_nao = int( + request.POST['votos_nao']) + votacao.numero_abstencoes = int( + request.POST['abstencoes']) + votacao.observacao = request.POST['observacao'] + votacao.materia = ordem.materia + votacao.ordem = ordem + resultado = TipoResultadoVotacao.objects.get( + id=request.POST['resultado_votacao']) + votacao.tipo_resultado_votacao = resultado + votacao.save() + except Exception as e: + username = request.user.username + self.logger.error('user=' + username + '. Problemas ao salvar ' + 'RegistroVotacao da materia de id={} ' + 'e da ordem de id={}. ' + .format(ordem.materia.id, ordem.id) + str(e)) + return self.form_invalid(form, context) + else: + ordem.resultado = resultado.nome + ordem.votacao_aberta = False + ordem.save() + + else: + expedientes = ExpedienteMateria.objects.filter( + id__in=request.POST.getlist('expedientes')) + for expediente in expedientes: + try: + votacao = RegistroVotacao() + votacao.numero_votos_sim = int( + request.POST['votos_sim']) + votacao.numero_votos_nao = int( + request.POST['votos_nao']) + votacao.numero_abstencoes = int( + request.POST['abstencoes']) + votacao.observacao = request.POST['observacao'] + votacao.materia = expediente.materia + votacao.expediente = expediente + resultado = TipoResultadoVotacao.objects.get( + id=request.POST['resultado_votacao']) + votacao.tipo_resultado_votacao = resultado + votacao.save() + except Exception as e: + username = request.user.username + self.logger.error('user=' + username + '. Problemas ao salvar RegistroVotacao da materia de id={} ' + 'e da ordem de id={}. '.format(expediente.materia.id, expediente.id) + str(e)) + return self.form_invalid(form, context) + else: + expediente.resultado = resultado.nome + expediente.votacao_aberta = False + expediente.save() + + return HttpResponseRedirect(self.get_success_url()) + + else: + return self.form_invalid(form, context) + + if 'cancelar-votacao' in request.POST: + if request.POST['origem'] == 'ordem': + ordens = OrdemDia.objects.filter( + id__in=request.POST.getlist('ordens')) + for ordem in ordens: + ordem.votacao_aberta = False + ordem.save() + else: + expedientes = ExpedienteMateria.objects.filter( + id__in=request.POST.getlist('expedientes')) + for expediente in expedientes: + expediente.votacao_aberta = False + expediente.save() + + return HttpResponseRedirect(self.get_success_url()) + + return self.render_to_response(context) + + def get_tipos_votacao(self): + for tipo in TipoResultadoVotacao.objects.all(): + yield tipo + + def get_success_url(self): + if self.request.POST['origem'] == 'ordem': + return reverse('sapl.sessao:ordemdia_list', + kwargs={'pk': self.kwargs['pk']}) + else: + return reverse('sapl.sessao:expedientemateria_list', + kwargs={'pk': self.kwargs['pk']}) + + def form_invalid(self, form, context): + + errors_tuple = [(form[e].label, form.errors[e]) + for e in form.errors if e in form.fields] + error_message = '
    ' + for e in errors_tuple: + error_message += '
  • %s: %s
  • ' % (e[0], e[1][0]) + for e in form.non_field_errors(): + error_message += '
  • %s
  • ' % e + error_message += '
' + + messages.add_message(self.request, messages.ERROR, error_message) + + if self.request.POST['origem'] == 'ordem': + ordens = OrdemDia.objects.filter( + id__in=self.request.POST.getlist('ordens')) + qtde_presentes = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']).count() + context.update({'ordens': ordens, + 'total_presentes': qtde_presentes}) + elif self.request.POST['origem'] == 'expediente': + expedientes = ExpedienteMateria.objects.filter( + id__in=self.request.POST.getlist('expedientes')) + qtde_presentes = SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=self.kwargs['pk']).count() + context.update({'expedientes': expedientes, + 'total_presentes': qtde_presentes}) + + context.update({'resultado_votacao': TipoResultadoVotacao.objects.all(), + 'form': form, + 'origem': self.request.POST['origem']}) + + return self.render_to_response(context) + + +class VotacaoEmBlocoNominalView(TemplateView): + """ + Votação Nominal + """ + template_name = 'sessao/votacao/votacao_nominal_bloco.html' + logger = logging.getLogger(__name__) + + def post(self, request, *args, **kwargs): + username = request.user.username + form = VotacaoNominalForm(request.POST) + + if not 'context' in locals(): + context = {'pk': self.kwargs['pk'], + 'root_pk': self.kwargs['pk'], + 'title': SessaoPlenaria.objects.get(id=self.kwargs['pk']), + 'subnav_template_name': 'sessao/subnav.yaml'} + + if 'marcadas_2' in request.POST: + + context.update({'resultado_votacao': TipoResultadoVotacao.objects.all(), + 'origem': request.POST['origem']}) + + # marcadas_1 se refere a votação simbólica e marcadas_2 a votação + # nominal + if request.POST['origem'] == 'ordem': + ordens = OrdemDia.objects.filter( + id__in=request.POST.getlist('marcadas_2')) + presentes = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=kwargs['pk']) + context.update({'ordens': ordens}) + else: + expedientes = ExpedienteMateria.objects.filter( + id__in=request.POST.getlist('marcadas_2')) + presentes = SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=kwargs['pk']) + context.update({'expedientes': expedientes}) + total_presentes = presentes.count() + context.update({'parlamentares': self.get_parlamentares(), + 'total_presentes': total_presentes}) + + if 'cancelar-votacao' in request.POST: + if request.POST['origem'] == 'ordem': + for ordem_id in request.POST.getlist('ordens'): + ordem = OrdemDia.objects.get(id=ordem_id) + fechar_votacao_materia(ordem) + return HttpResponseRedirect(reverse( + 'sapl.sessao:ordemdia_list', kwargs={'pk': self.kwargs['pk']})) + else: + for expediente_id in request.POST.getlist('expedientes'): + expediente = ExpedienteMateria.objects.get( + id=expediente_id) + fechar_votacao_materia(expediente) + return HttpResponseRedirect(reverse( + 'sapl.sessao:expedientemateria_list', + kwargs={'pk': self.kwargs['pk']})) + + if 'salvar-votacao' in request.POST: + + if form.is_valid(): + 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, context) + + qtde_votos = (int(request.POST['votos_sim']) + + int(request.POST['votos_nao']) + + int(request.POST['abstencoes']) + + int(request.POST['nao_votou'])) + + # Caso todas as opções sejam 'Não votou', fecha a votação + if int(request.POST['nao_votou']) == qtde_votos: + self.logger.error('user=' + username + '. Não é possível finalizar a votação sem ' + 'nenhum voto.') + form.add_error(None, 'Não é possível finalizar a votação sem ' + 'nenhum voto.') + return self.form_invalid(form, context) + + if request.POST['origem'] == 'ordem': + for ordem_id in request.POST.getlist('ordens'): + ordem = OrdemDia.objects.get(id=ordem_id) + # Remove todas as votação desta matéria, caso existam + RegistroVotacao.objects.filter( + ordem_id=ordem_id).delete() + votacao = RegistroVotacao() + votacao.numero_votos_sim = int( + request.POST['votos_sim']) + votacao.numero_votos_nao = int( + request.POST['votos_nao']) + votacao.numero_abstencoes = int( + request.POST['abstencoes']) + votacao.observacao = request.POST['observacao'] + votacao.materia = ordem.materia + votacao.ordem = ordem + votacao.tipo_resultado_votacao = form.cleaned_data['resultado_votacao'] + votacao.save() + + for votos in request.POST.getlist('voto_parlamentar'): + v = votos.split(':') + voto = v[0] + parlamentar_id = v[1] + + voto_parlamentar = VotoParlamentar.objects.get_or_create( + parlamentar_id=parlamentar_id, + ordem_id=ordem_id)[0] + + voto_parlamentar.voto = voto + voto_parlamentar.parlamentar_id = parlamentar_id + voto_parlamentar.votacao_id = votacao.id + voto_parlamentar.save() + + ordem.resultado = form.cleaned_data['resultado_votacao'].nome + ordem.votacao_aberta = False + ordem.save() + + VotoParlamentar.objects.filter( + ordem_id=ordem_id, + votacao__isnull=True).delete() + + else: + for expediente_id in request.POST.getlist('expedientes'): + expediente = ExpedienteMateria.objects.get( + id=expediente_id) + RegistroVotacao.objects.filter( + expediente_id=expediente_id).delete() + votacao = RegistroVotacao() + votacao.numero_votos_sim = int( + request.POST['votos_sim']) + votacao.numero_votos_nao = int( + request.POST['votos_nao']) + votacao.numero_abstencoes = int( + request.POST['abstencoes']) + votacao.observacao = request.POST['observacao'] + votacao.materia = expediente.materia + votacao.expediente = expediente + votacao.tipo_resultado_votacao = form.cleaned_data['resultado_votacao'] + votacao.save() + + # Salva os votos de cada parlamentar + for votos in request.POST.getlist('voto_parlamentar'): + v = votos.split(':') + voto = v[0] + parlamentar_id = v[1] + + voto_parlamentar = VotoParlamentar.objects.get_or_create( + parlamentar_id=parlamentar_id, + expediente_id=expediente_id)[0] + + voto_parlamentar.voto = voto + voto_parlamentar.parlamentar_id = parlamentar_id + voto_parlamentar.votacao_id = votacao.id + voto_parlamentar.save() + + expediente.resultado = form.cleaned_data['resultado_votacao'].nome + expediente.votacao_aberta = False + expediente.save() + + VotoParlamentar.objects.filter( + expediente_id=expediente_id, + votacao__isnull=True).delete() + + return HttpResponseRedirect(self.get_success_url()) + + else: + return self.form_invalid(form, context) + + return self.render_to_response(context) + + def get_parlamentares(self): + + # campos hidden ainda não preenchidos + if 'marcadas_2' in self.request.POST: + if self.request.POST['origem'] == 'ordem': + presencas = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']) + ordens_id = self.request.POST.getlist('marcadas_2') + voto_parlamentar = VotoParlamentar.objects.filter( + ordem=ordens_id[0]) + else: + presencas = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']) + expedientes_id = self.request.POST.getlist('marcadas_2') + voto_parlamentar = VotoParlamentar.objects.filter( + expediente=expedientes_id[0]) + + # campos hidden já preenchidos + else: + if self.request.POST['origem'] == 'ordem': + presencas = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']) + ordens_id = self.request.POST.getlist('ordens') + voto_parlamentar = VotoParlamentar.objects.filter( + ordem=ordens_id[0]) + else: + presencas = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']) + expedientes_id = self.request.POST.getlist('expedientes') + voto_parlamentar = VotoParlamentar.objects.filter( + expediente=expedientes_id[0]) + + presentes = [p.parlamentar for p in presencas] + + for parlamentar in Parlamentar.objects.filter(ativo=True): + if parlamentar in presentes: + try: + voto = voto_parlamentar.get( + parlamentar=parlamentar) + except ObjectDoesNotExist: + username = self.request.user.username + self.logger.error('user=' + username + '. Objeto voto_parlamentar do ' + + 'parlamentar de id={} não existe.'.format(parlamentar.pk)) + yield [parlamentar, None] + else: + yield [parlamentar, voto.voto] + + def get_success_url(self): + if self.request.POST['origem'] == 'ordem': + return reverse('sapl.sessao:ordemdia_list', + kwargs={'pk': self.kwargs['pk']}) + else: + return reverse('sapl.sessao:expedientemateria_list', + kwargs={'pk': self.kwargs['pk']}) + + def form_invalid(self, form, context): + + errors_tuple = [(form[e].label, form.errors[e]) + for e in form.errors if e in form.fields] + error_message = '
    ' + for e in errors_tuple: + error_message += '
  • %s: %s
  • ' % (e[0], e[1][0]) + for e in form.non_field_errors(): + error_message += '
  • %s
  • ' % e + error_message += '
' + + messages.add_message(self.request, messages.ERROR, error_message) + + if self.request.POST['origem'] == 'ordem': + ordens = OrdemDia.objects.filter( + id__in=self.request.POST.getlist('ordens')) + presentes = PresencaOrdemDia.objects.filter( + sessao_plenaria_id=self.kwargs['pk']) + context.update({'ordens': ordens}) + elif self.request.POST['origem'] == 'expediente': + expedientes = ExpedienteMateria.objects.filter( + id__in=self.request.POST.getlist('expedientes')) + presentes = SessaoPlenariaPresenca.objects.filter( + sessao_plenaria_id=self.kwargs['pk']) + context.update({'expedientes': expedientes}) + + total_presentes = presentes.count() + context.update({'parlamentares': self.get_parlamentares(), + 'total_presentes': total_presentes, + 'resultado_votacao': TipoResultadoVotacao.objects.all(), + 'form': form, + 'origem': self.request.POST['origem']}) + + return self.render_to_response(context) + + class RetiradaPautaCrud(MasterDetailCrud): model = RetiradaPauta public = [RP_LIST, RP_DETAIL, ] parent_field = 'sessao_plenaria' class BaseMixin(MasterDetailCrud.BaseMixin): - list_field_names = ['tipo_de_retirada', 'materia', 'observacao', 'parlamentar'] + list_field_names = ['tipo_de_retirada', + 'materia', 'observacao', 'parlamentar'] class ListView(MasterDetailCrud.ListView): paginate_by = 10 @@ -3269,7 +3789,8 @@ class RetiradaPautaCrud(MasterDetailCrud): layout_key = None def get_initial(self): - sessao_plenaria = RetiradaPauta.objects.get(id=self.kwargs['pk']).sessao_plenaria + sessao_plenaria = RetiradaPauta.objects.get( + id=self.kwargs['pk']).sessao_plenaria return {'sessao_plenaria': sessao_plenaria} class DeleteView(MasterDetailCrud.DeleteView): diff --git a/sapl/static/styles/app.css b/sapl/static/styles/app.css new file mode 100644 index 000000000..3561a3e06 --- /dev/null +++ b/sapl/static/styles/app.css @@ -0,0 +1,503 @@ +.container-home { + position: relative; + padding: 2em 1.5em 1.5em 1.5em; + max-width: 1000px; + margin: 0 auto; } + .container-home a:hover { + color: #444; + -webkit-transition: 0.3s ease-in; + -moz-transition: 0.3s ease-in; + -o-transition: 0.3s ease-in; } + .container-home #homeIndex { + text-align: center; } + .container-home .homeBanner span { + color: white; + font-size: 32px; + font-weight: 600; + display: inline-block; + vertical-align: middle; + padding: 2px 45px 4px; + border: 2px solid; } + .container-home .homeBanner::after { + display: inline-block; + vertical-align: middle; + height: 100%; } + .container-home .homeBlock { + display: inline-block; + position: relative; + background-color: #F3F3F3; + width: 190px; + height: 260px; + margin: 3px; + text-align: center; + font-size: 0; + overflow: hidden; } + .container-home .homeBlock > a { + display: block; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; } + .container-home .homeBlock::after { + content: ''; + display: inline-block; + vertical-align: middle; + height: 100%; + overflow: visible; + clear: none; + visibility: initial; } + .container-home .homeContent { + position: relative; + padding: 10px; + text-align: justify; + font-size: 14px; + color: #FFF; + opacity: 0; + transition: opacity 0.5s ease; + display: inline-block; + vertical-align: middle; } + .container-home .homeContent p { + display: block; + line-height: 13px; + font-size: 80%; + color: white; } + .container-home .homeIcon { + position: relative; + display: inline-block; + width: 105px; + height: 105px; + border-radius: 50%; + background: #364347; + z-index: 1; } + .container-home .homeIcon::before { + content: ''; + position: absolute; + width: 100%; + height: 100%; + border-radius: 50%; + background: #364347; + top: 0; + left: 0; + transform: scale(0.95); + transition: transform 0.6s ease; } + .container-home .homeIcon img { + position: absolute; + margin: auto; + top: 0; + bottom: 0; + right: 0; + left: 0; + transition: opacity 0.4s 0.4s ease; } + .container-home .homeFront { + position: absolute; + top: 46%; + width: 100%; + font-size: 0; + transform: translateY(-60%); } + .container-home .homeFront h2 { + position: absolute; + margin-top: 18px; + font-size: 22px; + font-weight: 700; + color: #595959 !important; + width: 100%; + padding: 0 6%; + z-index: 0; } + .container-home .homeTitle { + display: block; + height: 32px; + text-align: center; + width: 100%; + opacity: 0; + transition: opacity 0.4s ease; } + .container-home .homeTitle::before { + content: ''; + display: inline-block; + vertical-align: middle; + height: 100%; } + .container-home .homeTitle h2 { + display: inline-block; + vertical-align: middle; + max-width: 110px; + font-size: 14px; + color: white !important; + line-height: 1em; } + .container-home .homeTitle img { + display: inline-block; + vertical-align: middle; + height: 30px; + margin-right: 5px; } + .container-home .homeBlock:hover .homeIcon::before { + transform: scale(3.6) translateY(7px); } + .container-home .homeBlock:hover .homeContent { + opacity: 1; + transition-delay: 0.2s; } + .container-home .homeBlock:hover .homeIcon img { + opacity: 0; + transition-duration: 0.2s; + transition-delay: 0s; } + .container-home .homeBlock:hover .homeTitle { + opacity: 1; } + +html { + position: relative; + min-height: 100%; } + +body { + margin-bottom: 160px; } + +h1, h2, h3, h4, h5, h6, form, dl, dt, dd, p, div, img, a { + margin: 0; + padding: 0; } + +h1, .h1 { + font-size: 30px; } + +h2, .h2 { + font-size: 24px; } + +h3, .h3 { + font-size: 20px; } + +h4, .h4 { + font-size: 16px; } + +h5, .h5 { + font-size: 14px; } + +h6, .h6 { + font-size: 12px; } + +p { + margin: 0.5em 0; } + p .control-label { + font-weight: bold; } + +label { + margin-bottom: 0; + line-height: 1; } + +fieldset fieldset { + font-size: 95%; } + fieldset fieldset legend { + font-size: 18px; } + +.page-header { + margin: 20px 0px 10px; } + +.caret.top { + transform: rotate(180deg); } + +.btn:hover, .btn:focus { + color: inherit; } + +.btn-default.btn-excluir { + color: #d9534f; } + .btn-default.btn-excluir:hover { + color: #fff; + border-color: #de6764; + background-color: #de6764; } + +.btn-cancel-iframe { + position: relative; + text-align: right; + opacity: 0.5; } + .btn-cancel-iframe:hover { + opacity: 1; } + .btn-cancel-iframe a { + padding: 10px; + display: inline-block; } + +.legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; + clear: both; } + +.grid-gutter-width-right { + margin-right: 15px; } + +.controls-file { + padding: 10px; + border: 1px solid #d6e1e5; + border-radius: 4px; } + .controls-file label.checkbox-inline { + margin: 0px; + display: block; } + +.help-block-danger { + margin: 15px; + padding: 15px; + border: 2px dashed #f00; } + +.control-label { + margin: 0; } + +.form-control-static { + padding-top: 0; + min-height: auto; } + .form-control-static img { + max-width: 100%; } + +.pagination { + padding-top: 25px; } + +.modal .alert { + margin-bottom: 0; } + +.avatar-parlamentar { + height: 128px; + width: 128px; + margin: 0 auto; + display: table; } + +.masthead { + padding: 10px; } + .masthead .nav { + clear: both; } + .masthead .navbar-brand { + padding: 0px; + color: inherit; + font-size: 24px; } + .masthead .navbar-brand img.img-responsive { + height: 95px; + margin-right: 15px; + display: inline-block; } + .masthead .navbar-brand small { + color: #93A4AA; + font-size: 75%; + line-height: 25px; } + .masthead .navbar-brand .vcenter { + display: inline-block; + vertical-align: middle; + float: none; + padding: 10px; } + +nav.navbar { + margin-bottom: 0; + border-radius: 0; + font-size: 15px; } + +nav .navbar-nav > li > a { + padding-top: 0px; + padding-bottom: 0px; + line-height: 75px; } + nav .navbar-nav > li > a:hover { + background-color: #23527c; } + +nav .navbar-nav > li:nth-child(2) > .dropdown-menu { + right: auto; } + +nav .navbar-nav:last-child > li:last-child a { + padding-right: 0px; } + +.controls-radio-checkbox { + padding: 0px; + border: 1px solid #d6e1e5; + border-radius: 4px; + min-height: 20px; } + .controls-radio-checkbox .checkbox, .controls-radio-checkbox .radio, .controls-radio-checkbox .checkbox-inline, .controls-radio-checkbox .radio-inline { + padding: 8px 8px 8px 36px; + margin: 0; + line-height: 1.6; + display: block; } + .controls-radio-checkbox .checkbox:hover, .controls-radio-checkbox .radio:hover, .controls-radio-checkbox .checkbox-inline:hover, .controls-radio-checkbox .radio-inline:hover { + background-color: #d6e1e5; } + .controls-radio-checkbox .checkbox .icons, .controls-radio-checkbox .radio .icons, .controls-radio-checkbox .checkbox-inline .icons, .controls-radio-checkbox .radio-inline .icons { + top: auto; + left: 8px; } + .controls-radio-checkbox .checkbox-inline, .controls-radio-checkbox .radio-inline { + display: inline-block; } + .controls-radio-checkbox .help-block { + margin: 15px; + padding: 15px; + border: 2px dashed #d6e1e5; } + +.controls-radio-checkbox__old { + padding: 0px; + border: 1px solid #d6e1e5; + border-radius: 4px; + min-height: 20px; } + .controls-radio-checkbox__old label { + padding: 0; + line-height: 2.7; + padding-left: 36px; } + .controls-radio-checkbox__old label .icons { + top: 8px; + left: 8px; } + .controls-radio-checkbox__old label.checkbox-inline, .controls-radio-checkbox__old label.radio-inline { + padding-right: 8px; } + .controls-radio-checkbox__old label.checkbox-inline .icons, .controls-radio-checkbox__old label.radio-inline .icons { + top: 8px; + left: 8px; } + .controls-radio-checkbox__old .checkbox, .controls-radio-checkbox__old .radio, .controls-radio-checkbox__old .checkbox-inline, .controls-radio-checkbox__old .radio-inline { + margin: 0; } + .controls-radio-checkbox__old .checkbox:hover, .controls-radio-checkbox__old .radio:hover, .controls-radio-checkbox__old .checkbox-inline:hover, .controls-radio-checkbox__old .radio-inline:hover { + background-color: #d6e1e5; } + +.manual, .manual ul { + padding-left: 1.5em; + list-style-type: none; + margin-top: 0; + font-size: 100%; } + +.manual li { + display: list-item; + line-height: 1.5em; + padding-right: 0; } + .manual li a { + background-color: transparent; + border: none; + border-radius: none; + padding: 0; } + +.container-tabaux .sidebar-tabaux { + background: #fafafa; + margin-top: -70px; + padding: 10px; + border: 1px solid #eee; } + .container-tabaux .sidebar-tabaux .navbar-right { + margin: 0; } + .container-tabaux .sidebar-tabaux .nav-pills > li + li { + margin-left: 0px; } + .container-tabaux .sidebar-tabaux li { + width: 100%; } + .container-tabaux .sidebar-tabaux span { + display: none; } + .container-tabaux .sidebar-tabaux .dropdown-menu { + padding: 0px; + right: 10px; + margin-top: -5px; + overflow: hidden; } + .container-tabaux .sidebar-tabaux .dropdown-menu a { + border: 0px; } + +.container-tabaux ul { + list-style: none; + padding: 0; } + +.container-tabaux .list { + font-family: "SourceSansProSemiBold", Helvetica, Arial, sans-serif; + font-size: 0px; + display: table; + width: 100%; + margin: 0; } + .container-tabaux .list ul { + display: table; + width: 100%; + margin: 0; } + .container-tabaux .list li { + width: calc(50%); + display: inline-block; + position: relative; } + .container-tabaux .list > li { + width: 100%; + border-bottom: 1px solid #eee; + padding-bottom: 20px; + margin-bottom: 20px; } + .container-tabaux .list .head_title { + color: #364347; + font-size: 2.4rem; + text-transform: none; } + .container-tabaux .list a span { + display: none; } + +#styleparlamentar { + border: 0px solid #d6e1e5; + border-top-color: #d6e1e5; + border-right-color: #d6e1e5; + border-bottom-color: #d6e1e5; + border-left-color: #d6e1e5; + border-image-source: initial; + border-image-slice: initial; + border-image-repeat: initial; + font-size: 16px; + line-height: 1.467; + padding: 7px 12px; + height: 40px; + -webkit-appearance: none; + border-radius: 4px; + -webkit-box-shadow: none; + box-shadow: none; + margin-left: 1.0em; } + +.footer { + background: #364347; + color: white; + text-align: center; + position: absolute; + width: 100%; + bottom: 0px; } + .footer p { + color: white; + margin-top: 10px; } + .footer .container { + padding-top: 25px; } + +@media (max-width: 1199px) { + nav .container { + width: auto !important; } + .navbar-nav > li > a { + padding-left: 10.71429px; + padding-right: 10.71429px; } } + +@media (max-width: 1091px) { + .container { + width: auto; } + .navbar-nav > li > a { + padding-left: 7.5px; + padding-right: 7.5px; } + .masthead .navbar-brand { + font-size: 22px; } + .masthead .navbar-brand img.img-responsive { + height: 60px; + margin-right: 7.5px; } } + +@media (max-width: 991px) { + body { + margin: 0; } + .footer { + position: relative; } + .caret { + margin-left: 1px; } + .navbar-nav > li > a { + padding-left: 4px; + padding-right: 4px; } } + +@media (max-width: 767px) { + nav .navbar-nav > li > a { + line-height: 2.5; } + nav .navbar-right { + position: absolute; + top: 0; + margin: 10px; } + nav .navbar-right > li { + vertical-align: top; + display: inline-block; } + nav .navbar-right > li a { + padding-left: 10px; + padding-right: 10px; } + nav .navbar-right .pesquisa.open ul { + position: absolute; } + nav .navbar-right .navbar-form { + margin: 8px 0; } + .table { + width: auto; + white-space: normal; + display: block; + overflow-x: auto; } } + +@media (min-width: 1092px) and (max-width: 1199px) { + .container { + width: 1070px; } } + +@media print { + a[href]:after { + content: none !important; } } diff --git a/sapl/static/styles/compilacao.css b/sapl/static/styles/compilacao.css new file mode 100644 index 000000000..557ef057a --- /dev/null +++ b/sapl/static/styles/compilacao.css @@ -0,0 +1,1136 @@ +a:link:after, a:visited:after { + content: ""; } + +.test_import:nth-child(even) { + background-color: #ccc; } + +#wait_message { + display: block; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: rgba(220, 220, 220, 0.75); + z-index: 99; } + #wait_message #msg { + position: relative; + margin: 20% auto; + padding: 1.2em 2em; + max-width: 600px; + text-align: center; + font-size: 1.5em; + color: #677; + border: 1px solid #eee; + background-color: #fff !important; + box-shadow: 0 1px 2px #999; } + +.text-center { + text-align: center; } + +.cp-notify { + z-index: 9999; + position: fixed; + top: 2em; + left: 50%; + min-width: 600px; + transform: translate(-50%, 0); + transition: all 0.4s ease; + opacity: 0.97; } + .cp-notify.hide { + opacity: 0; + top: -1000px; + display: block !important; + transition: all 0.4s ease; } + .cp-notify .message { + padding: 1em; + border: 2px solid rgba(0, 0, 0, 0.1); + border-radius: 4px; + color: rgba(0, 0, 0, 0.6); + line-height: 1em; + font-size: 1.3em; + text-align: center; + box-shadow: 0 0 100px rgba(0, 0, 0, 0.2); } + +.cp { + /* and dpt */ } + .cp .desativado .dtxt, .cp .dpt .dptt > a.desativado .dtxt, .cp .desativado .dtxt *, .cp .dpt .dptt > a.desativado .dtxt *, .cp .desativado .dpt-link, .cp .dpt .dptt > a.desativado .dpt-link, .cp .desativado .dpt-link *, .cp .dpt .dptt > a.desativado .dpt-link * { + text-decoration: line-through; + color: #999 !important; } + .cp .desativado .dtxt table, .cp .dpt .dptt > a.desativado .dtxt table, .cp .desativado .dtxt table td, .cp .dpt .dptt > a.desativado .dtxt table td, .cp .desativado .dtxt * table, .cp .dpt .dptt > a.desativado .dtxt * table, .cp .desativado .dtxt * table td, .cp .dpt .dptt > a.desativado .dtxt * table td, .cp .desativado .dpt-link table, .cp .dpt .dptt > a.desativado .dpt-link table, .cp .desativado .dpt-link table td, .cp .dpt .dptt > a.desativado .dpt-link table td, .cp .desativado .dpt-link * table, .cp .dpt .dptt > a.desativado .dpt-link * table, .cp .desativado .dpt-link * table td, .cp .dpt .dptt > a.desativado .dpt-link * table td { + border: 1px dotted #ccc; } + .cp a { + text-decoration: none; + cursor: pointer; } + .cp .diff .desativado, .cp .diff .dpt .dptt > a.desativado, .cp .dpt .diff .dptt > a.desativado, .cp .diff .desativado *, .cp .diff .dpt .dptt > a.desativado *, .cp .dpt .diff .dptt > a.desativado * { + text-decoration: line-through; + color: #ddd !important; + font-size: 90%; } + .cp .diff .added { + color: #04DE2C; } + .cp .dpt { + font-size: 1em; + position: relative; } + .cp .dpt.indent { + padding-left: 1em; } + .cp .dpt .ementa { + padding: 2em 0em 2em 35%; + font-weight: bold; } + .cp .dpt .titulo_generico, .cp .dpt .anexo, .cp .dpt .disp_preliminares, .cp .dpt .disp_gerais, .cp .dpt .disp_transitorias, .cp .dpt .disp_finais, .cp .dpt .parte, .cp .dpt .livro, .cp .dpt .titulo, .cp .dpt .capitulo, .cp .dpt .secao, .cp .dpt .subsecao, .cp .dpt .itemsecao { + text-align: center; + margin-bottom: 1em; + font-size: 1.15em; + margin-top: 3em; } + .cp .dpt .titulo { + margin-top: 2em; } + .cp .dpt .capitulo { + margin-top: 1.5em; + font-size: 1.15em; } + .cp .dpt .secao { + margin-top: 1.2em; + margin-bottom: 0.7em; + font-weight: bold; + font-size: 1.15em; } + .cp .dpt .subsecao, + .cp .dpt .itemsecao { + margin-top: 1em; + margin-bottom: 0.6em; + font-weight: bold; + font-size: 1.15em; } + .cp .dpt .artigo { + font-size: 1.15em; + float: left; } + .cp .dpt .artigo .dptt { + position: relative; } + .cp .dpt .caput { + margin-top: 0.3333em; + font-size: 1.15em; } + .cp .dpt .paragrafo { + font-size: 1.1em; + margin-top: 0.2222em; } + .cp .dpt .inciso { + font-size: 1.1em; + margin-top: 0.1667em; } + .cp .dpt .alinea { + font-size: 1.0em; + margin-top: 2px; } + .cp .dpt .item { + font-size: 1.0em; + margin-top: 2px; } + .cp .dpt .assinatura { + margin-top: 0.6em; + font-size: 1.15em; } + .cp .dpt .fecho_lei { + margin-top: 0.6em; + font-size: 1.15em; } + .cp .dpt .page-break { + page-break-before: always; } + .cp .dpt .bloco_alteracao { + padding-left: 10%; + font-style: italic; + color: #018; } + .cp .dpt .bloco_alteracao a { + text-decoration: underline; } + .cp .dpt .bloco_alteracao a, .cp .dpt .bloco_alteracao table, .cp .dpt .bloco_alteracao table td { + color: #018 !important; } + .cp .dpt .dn { + /* Notas de Dispositivo*/ + font-weight: normal; + position: relative; + font-size: 70%; } + .cp .dpt .dn p, .cp .dpt .dn ul { + font-weight: normal; + margin: 0 0 0 0; + list-style: none; + padding: 0; } + .cp .dpt .dn .dnl { + /* Lista Notas de Dispositivo*/ + display: block; + text-align: left !important; } + .cp .dpt .dn .dnl * { + display: inline; } + .cp .dpt .dn .dnl .bullet { + padding: 0 0.333em; + display: inline-block; } + .cp .dpt .dn .dnl .dnli { + min-height: 2.5em; } + .cp .dpt .dn .dnl .dnli:hover ul { + transition: opacity 0.5s linear, clip 0s 0.3s; + clip: auto; + opacity: 1; + background: rgba(230, 230, 230, 0.9); } + .cp .dpt .dn .dnl .dnli ul { + transition: opacity 0.5s linear, clip 0s 0.3s; + clip: rect(0, 0, 0, 0); + opacity: 0; + position: absolute; + background: transparent; + right: 0; + padding: 0.2em 0.5em 0em 0.5em; + border: 1px solid #c7e3d3; + border-top: 0px; + font-size: 1.5rem; } + .cp .dpt .dn .dnl .dnli ul li { + display: table-cell; + color: #aaa; } + .cp .dpt .dn .dnl .dnli ul li:hover { + color: #787; } + .cp .dpt .dn .dnl .dnli ul li:hover a { + color: #27AE60 !important; } + .cp .dpt .dn .dnl .dnli ul li .nowner { + color: #27AE60 !important; } + .cp .dpt .dn .dnl .dnli .ntitulo { + font-weight: bold; + color: #03A203; + text-decoration: none; } + .cp .dpt .dn .dnl .dnli .ntitulo a { + color: #294 !important; } + .cp .dpt .dn .dnl .dnli .ntexto { + color: #06D806; } + .cp .dpt .dn .dnl .dnli .ntexto a { + color: #03A203 !important; } + .cp .dpt .dn .dnl:hover { + display: block; } + .cp .dpt .dn .dnl:hover * { + display: block; } + .cp .dpt .dn .dnl:hover > .bullet { + display: none; } + .cp .dpt .dn .dnl:hover .dnli { + margin-top: 0.5em; + border-top: 1px solid #c7e3d3; } + .cp .dpt .dptt { + clear: left; } + .cp .dpt .dptt > a { + color: #000000; } + .cp .dpt .dptt > a.nota-alteracao { + color: #02baf2; + font-size: 0.75em; } + .cp .dpt .dptt > a.nota-alteracao:hover { + text-decoration: underline; } + .cp .dpt .dptt .dne { + position: absolute; + display: block; + right: 0; + left: 0; + top: 0; + height: 0; + transform: scaleX(0); + transform-origin: right; + transition: all 0.3s ease; + border-top: 1px solid #2980B9; } + .cp .dpt .dptt .dne ul.btns-action { + list-style: none; + padding: 0; + position: absolute; + right: 0; + background-color: #2980B9; } + .cp .dpt .dptt .dne ul.btns-action li { + float: left; } + .cp .dpt .dptt .dne ul.btns-action li:hover { + background-color: rgba(0, 0, 0, 0.1); } + .cp .dpt .dptt .dne ul.btns-action li a { + color: white; + padding: 0.15em 1em 0; + display: inline-block; } + .cp .dpt .dptt .dne-nota { + position: relative; + transform: scaleX(1); + height: auto; + border-top: 0px; } + .cp .dpt .dptt .dne-nota ul.btns-action { + display: none; } + .cp .dpt .dptt .dne-nota .dne-form { + margin: 1em -2em 0em; + text-align: left; + font-size: 1.6rem; } + .cp .dpt .dptt:hover .dne { + height: 0.1667rem; + transform: scaleX(1); + transition-delay: 1s; } + .cp .dpt .dptt:hover .dne-nota { + height: auto; + transition-delay: 0s; } + .cp .tipo-vigencias { + list-style: none; + position: fixed; + bottom: 0px; + left: 50%; + transform: translate(-50%, 0); + margin: 0; + padding: 0; + background-color: #2980B9; + z-index: 1000; + opacity: 0.9; + transition: all 0.3s ease-in-out; } + .cp .tipo-vigencias li { + display: inline-block; + border-left: 1px solid #fff; + float: left; } + .cp .tipo-vigencias li a { + color: white; + padding: 0.3em 1em 0; + display: inline-block; + font-size: 110%; + cursor: pointer; } + .cp .tipo-vigencias li a.selected { + background-color: rgba(0, 0, 0, 0.5); } + .cp .tipo-vigencias li:hover { + background-color: rgba(0, 0, 0, 0.2); } + .cp .tipo-vigencias:hover { + opacity: 1; } + +/* end cp */ +.cp.cpe { + /* fim .dpt */ + /* fim dpt-alts */ } + .cp.cpe .desativado, .cp.cpe .dpt .dptt > a.desativado { + text-decoration: line-through; + color: #999 !important; } + .cp.cpe .desativado table, .cp.cpe .dpt .dptt > a.desativado table, .cp.cpe .desativado table td, .cp.cpe .dpt .dptt > a.desativado table td { + border: 1px dotted #ccc; } + .cp.cpe .desativado a.nota-alteracao * { + color: #02baf2 !important; } + .cp.cpe .dpt { + display: block; } + .cp.cpe .dpt > .dpt-actions-fixed { + position: absolute; + right: -0.8em; + top: -0.8em; + z-index: 3; + opacity: 0; } + .cp.cpe .dpt > .dpt-actions-fixed .activate { + display: none; } + .cp.cpe .dpt > .dpt-actions-fixed .deactivate { + display: inline; } + .cp.cpe .dpt > .dpt-actions-fixed .btn-dpt-edit.btn-default { + color: #333; } + .cp.cpe .dpt > .dpt-actions-fixed .btn-dpt-edit.btn-default:hover { + color: #fff; + background-color: #02baf2; } + .cp.cpe .dpt > .dpt-actions, .cp.cpe .dpt > .dpt-actions-bottom { + display: none; } + .cp.cpe .dpt > .dpt-text { + cursor: text; + min-height: 30px; + border: 1px solid transparent; } + .cp.cpe .dpt > .dpt-text:hover, .cp.cpe .dpt > .dpt-text.hover-fixed { + background-color: rgba(0, 0, 0, 0.01); + color: #2980B9; + border: 1px solid #eee; + transition: color 0.3s ease; } + .cp.cpe .dpt > .dpt-text.artigo { + float: none; } + .cp.cpe .dpt > .dpt-text a.link-rotulo { + color: #000; } + .cp.cpe .dpt:hover > .dpt-actions-fixed { + opacity: 1; } + .cp.cpe .dpt:hover > .dpt-actions-fixed:hover ~ .dpt-text { + background-color: rgba(0, 0, 0, 0.01); + color: #2980B9; + border: 1px solid #eee; + transition: color 0.3s ease; } + .cp.cpe .dpt .semtexto { + font-weight: bold; + color: #9aaed6; } + .cp.cpe .dpt .semtexto:hover { + color: #5f76a4; } + .cp.cpe .dpt-alts { + margin: 0; + margin-bottom: 1em; + padding: 0; + background-color: transparent; + min-height: 100px; + border: 2px dashed #fff; } + .cp.cpe .dpt-alts:hover { + border-color: #d9ddde; } + .cp.cpe .dpt-alts:empty { + border-color: #ddd; } + .cp.cpe .dpt-alts.drag { + width: 100% !important; + border-color: #d9ddde; } + .cp.cpe .dpt-alts.drag .dpt { + transition-duration: 0s !important; } + .cp.cpe .dpt-alts .dpt { + width: 100% !important; + box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); + padding: 0; + margin: 0; + background-color: #edf0f1; + height: auto !important; + min-height: 2em; + z-index: 1; } + .cp.cpe .dpt-alts .dpt:not(:first-child) { + border-top: 1px solid white; } + .cp.cpe .dpt-alts .dpt > .dpt-text { + padding: 0.3em 1em; + margin-top: 0; + margin-bottom: 0; } + .cp.cpe .dpt-alts .dpt > .dpt-text a.link-rotulo { + text-decoration: underline; } + .cp.cpe .dpt-alts .dpt-selected.dpt { + margin: 0em -0.5em; } + .cp.cpe .dpt-selected.dpt { + width: auto !important; + margin: 1em -0.5em; + border: 1px solid #fad46b !important; + padding: 0; + background-color: #fafafa; + border-radius: 3px; + z-index: 4; } + .cp.cpe .dpt-selected.dpt > .dpt-text { + border: 1px solid transparent; } + .cp.cpe .dpt-selected.dpt > .dpt-text:hover { + border: 1px solid transparent; + background-color: transparent; } + .cp.cpe .dpt-selected.dpt > .dpt-form { + margin-bottom: 0em; } + .cp.cpe .dpt-selected.dpt > .dpt-actions, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom { + display: table; + background-color: #e5e5e5; + padding: 1em; + margin-bottom: 0em; + width: 100%; } + .cp.cpe .dpt-selected.dpt > .dpt-actions > .btn-action, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom > .btn-action { + display: table-cell; + float: none; } + .cp.cpe .dpt-selected.dpt > .dpt-actions .btn-excluir, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .btn-excluir, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar { + display: inline-block; + opacity: 0.3; } + .cp.cpe .dpt-selected.dpt > .dpt-actions .btn-excluir:hover, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar:hover, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar:hover, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .btn-excluir:hover, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar:hover, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar:hover { + opacity: 1; } + .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom { + margin: 0; } + .cp.cpe .dpt-selected .dpt-block { + border-top: 1px solid #e5e5e5 !important; + opacity: 0.6; + transition: opacity 0.4s ease; } + .cp.cpe .dpt-selected .dpt-block:hover { + opacity: 1; } + .cp.cpe .dpt-selected .dpt:only-child { + /*border-bottom: 1px solid #e5e5e5 !important;*/ } + .cp.cpe .dpt-selected .dpt:not(:last-child) { + /*border-bottom: 1px solid #e5e5e5 !important;*/ } + .cp.cpe .dpt-selected .dpt-text { + opacity: 0.7; + margin: 0; + padding: 0.7em; } + .cp.cpe .dpt-selected .dpt-text:hover { + opacity: 1; + background-color: #f5f5f5; } + .cp.cpe .dpt-selected .dpt-alts { + margin: 1em; } + .cp.cpe .dpt-selected .dpt-alts .dpt { + box-shadow: 0 0 0; } + .cp.cpe .dpt-selected > .dpt-actions-fixed { + opacity: 1; + top: -12px; + right: 0.5em; } + .cp.cpe .dpt-selected > .dpt-actions-fixed .activate { + display: inline; } + .cp.cpe .dpt-selected > .dpt-actions-fixed .deactivate { + display: none; } + .cp.cpe .dpt-selected > .dpt-actions-fixed .btn-dpt-edit { + padding-top: 2px; + padding-bottom: 1px; } + .cp.cpe .dpt-selected > .dpt-actions-fixed .btn-dpt-edit.btn-default { + background-color: #fad46b; + border: 1px solid #fad46b; } + .cp.cpe .dpt-selected .dropdown-menu.dropdown-menu-left { + right: auto !important; + left: 0; + padding: 2px 0; } + .cp.cpe .dpt-selected .dropdown-menu.dropdown-menu-left > .top.arrow { + right: 88%; + left: auto; } + .cp.cpe .dpt-selected .dropdown-menu li a { + padding-top: 2px; + padding-bottom: 2px; } + .cp.cpe .dpt-selected .btn-group .radius-right { + border-bottom-right-radius: 4px !important; + border-top-right-radius: 4px !important; } + .cp.cpe .dpt-selected:hover > .dpt-actions-fixed { + opacity: 1; } + +.cp.cpe1_old_apagar { + margin-bottom: 15em; + /* fim dpt */ + /* fim dpt-selected */ } + .cp.cpe1_old_apagar .desativado, .cp.cpe1_old_apagar .dpt .dptt > a.desativado, .cp.cpe1_old_apagar .desativado *, .cp.cpe1_old_apagar .dpt .dptt > a.desativado * { + text-decoration: line-through; + color: #999 !important; } + .cp.cpe1_old_apagar .desativado table, .cp.cpe1_old_apagar .dpt .dptt > a.desativado table, .cp.cpe1_old_apagar .desativado table td, .cp.cpe1_old_apagar .dpt .dptt > a.desativado table td, .cp.cpe1_old_apagar .desativado * table, .cp.cpe1_old_apagar .dpt .dptt > a.desativado * table, .cp.cpe1_old_apagar .desativado * table td, .cp.cpe1_old_apagar .dpt .dptt > a.desativado * table td { + border: 1px dotted #ccc; } + .cp.cpe1_old_apagar a { + text-decoration: none; + cursor: pointer; } + .cp.cpe1_old_apagar .dpt { + position: relative; + display: block; } + .cp.cpe1_old_apagar .dpt .semtexto { + font-weight: bold; + color: #BFD1F6; } + .cp.cpe1_old_apagar .dpt .artigo { + float: none; } + .cp.cpe1_old_apagar .dpt .caput { + margin-top: 0; } + .cp.cpe1_old_apagar .dpt > .actions_right, .cp.cpe1_old_apagar .dpt-selected .csform .dpt > .actions_left { + color: #fff; + right: 0em; + position: absolute; + opacity: 0; + transition: all 0.4s ease-in-out; + z-index: 1000; } + .cp.cpe1_old_apagar .dpt > .actions_right a.btn-bloco, .cp.cpe1_old_apagar .dpt-selected .csform .dpt > .actions_left a.btn-bloco { + background-color: #3498db; + color: #ffffff !important; + padding: 8px 18px 6px; + display: inline-block; + line-height: 1; + float: right; } + .cp.cpe1_old_apagar .dpt > .actions_right a.btn-bloco:hover, .cp.cpe1_old_apagar .dpt-selected .csform .dpt > .actions_left a.btn-bloco:hover { + opacity: 1; + background-image: -webkit-linear-gradient(top, #1c81c4, #0b6dad); + background-image: -moz-linear-gradient(top, #1c81c4, #0b6dad); + background-image: -ms-linear-gradient(top, #1c81c4, #0b6dad); + background-image: -o-linear-gradient(top, #1c81c4, #0b6dad); + background-image: linear-gradient(to bottom, #1c81c4, #0b6dad); } + .cp.cpe1_old_apagar .dpt:hover > .actions_right, .cp.cpe1_old_apagar .dpt-selected .csform .dpt:hover > .actions_left { + opacity: 1; } + .cp.cpe1_old_apagar .dpt .bloco { + display: block; + clear: both; } + .cp.cpe1_old_apagar .dpt .bloco *:hover { + color: #27AE60; } + .cp.cpe1_old_apagar .dpt .bloco .de { + cursor: pointer; } + .cp.cpe1_old_apagar .dpt .articulacao { + border-top: 2px solid #e5e5e5; + margin: 2em 0; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao { + margin: 1em 0; + padding: 0em; + background-color: transparent; + min-height: 100px; + border: 2px dashed #fff; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao:hover { + border-color: #d9ddde; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao.drag { + width: 100% !important; + border-color: #d9ddde; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao.drag .dpt { + transition-duration: 0s !important; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt { + width: 100% !important; + box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); + padding: 0.3em 1em; + margin: 0; + background-color: #edf0f1; + z-index: 1; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt:not(:first-child) { + border-top: 1px solid white; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt.ui-draggable div { + cursor: pointer; } + .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt.dpt-comp-selected { + transition: all 0.3s ease; + width: auto !important; + margin: 2em -3.7em; + box-shadow: 0 0 6px rgba(0, 0, 0, 0.16), 0 6px 12px rgba(0, 0, 0, 0.32); } + .cp.cpe1_old_apagar .dpt-selected { + font-size: 1em; + border: 0px solid #CCC; + margin: 1em -1.8em 1em -1.8em; + padding: 2.2em 2.2em 1.6em 2.2em; + box-shadow: -4px 15px 15px rgba(0, 0, 0, 0.1), 0px 6px 6px rgba(0, 0, 0, 0.23); + background-image: -webkit-linear-gradient(top, #eaeaee, #ddd); + background-image: -moz-linear-gradient(top, #eaeaee, #ddd); + background-image: -ms-linear-gradient(top, #eaeaee, #ddd); + background-image: -o-linear-gradient(top, #eaeaee, #ddd); + background-image: linear-gradient(to bottom, #eaeaee, #ddd); + /* fim csform*/ } + .cp.cpe1_old_apagar .dpt-selected ul { + list-style: none; + margin: 0; + padding: 0; } + .cp.cpe1_old_apagar .dpt-selected .semtexto { + color: #999; } + .cp.cpe1_old_apagar .dpt-selected .bloco { + opacity: 0.5; } + .cp.cpe1_old_apagar .dpt-selected .bloco:hover { + opacity: 1; } + .cp.cpe1_old_apagar .dpt-selected .bloco a:hover { + background: transparent; } + .cp.cpe1_old_apagar .dpt-selected > .bloco { + opacity: 1; + margin: 1em; } + .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao { + margin: 0; + padding: 1em; + border: 0 transparent; + background-image: -webkit-linear-gradient(top, #eaeaee, #ddd); + background-image: -moz-linear-gradient(top, #eaeaee, #ddd); + background-image: -ms-linear-gradient(top, #eaeaee, #ddd); + background-image: -o-linear-gradient(top, #eaeaee, #ddd); + background-image: linear-gradient(to bottom, #eaeaee, #ddd); } + .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao:hover { + border-color: transparent; } + .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao.drag { + width: 100% !important; } + .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao.drag .dpt { + transition-duration: 0s !important; } + .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao .dpt { + width: auto !important; + transition: all 0.3s ease; + background-color: white; } + .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao .dpt:not(:first-child) { + border-top: 0px solid white; } + .cp.cpe1_old_apagar .dpt-selected > .dpt { + padding: 0; } + .cp.cpe1_old_apagar .dpt-selected > .dpt:last-child { + padding-bottom: 1em; } + .cp.cpe1_old_apagar .dpt-selected > .actions_right a.btn-bloco, .cp.cpe1_old_apagar .dpt-selected .csform .dpt-selected > .actions_left a.btn-bloco { + display: none; } + .cp.cpe1_old_apagar .dpt-selected .csform { + /* compilacao simple form */ + display: block; + clear: both; + z-index: 9; + position: static; + /* actions_inserts */ } + .cp.cpe1_old_apagar .dpt-selected .csform .btns-action { + -webkit-animation: fadeIn 1s ease-in-out; + -moz-animation: fadeIn 1s ease-in-out; + -o-animation: fadeIn 1s ease-in-out; + opacity: 1; + position: absolute; + display: table; + transition: all 0.4s ease-in-out; } + .cp.cpe1_old_apagar .dpt-selected .csform .btns-action a { + color: #16407c; + display: block; + background: transparent; + vertical-align: middle; + text-align: center; + font-weight: normal; + text-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + padding: 0.33em 0.4em; } + .cp.cpe1_old_apagar .dpt-selected .csform .btns-action > li { + position: relative; + display: table-cell; + vertical-align: top; } + .cp.cpe1_old_apagar .dpt-selected .csform .btns-action > li:hover { + background-color: rgba(255, 255, 255, 0.5); } + .cp.cpe1_old_apagar .dpt-selected .csform .btns-action > li:hover > a { + text-shadow: 0 0 5px #777; + color: #0a5; } + .cp.cpe1_old_apagar .dpt-selected .csform .label_status { + position: absolute; + bottom: 0; + right: 0; + color: #889; + padding: 0.3em; + font-size: 80%; + text-align: right; + z-index: 15; + display: table; } + .cp.cpe1_old_apagar .dpt-selected .csform .label_status li { + display: table-cell; + padding: 0 0.5em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents { + z-index: 11; + top: 0em; + left: 0em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents a { + padding: 0.62em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents div, .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents li { + font-size: 80%; + display: table-cell; + vertical-align: middle; + border-right: 1px solid #CCC; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents div { + padding: 0 0.4em; + font-stretch: condensed; + font-variant: small-caps; + font-weight: bold; + text-shadow: 0 0 10px #fff; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents > li:hover a { + color: #16407c; + font-weight: normal; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_top, .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom { + top: 0em; + right: 0em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_top a, .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom a { + padding-right: 1em; + padding-left: 1em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_top li, .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom li { + display: table-cell; + vertical-align: middle; + border-left: 1px solid #CCC; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom { + top: auto; + left: 0; + bottom: 0; + display: inline-block; + border-top: 1px solid #CCC; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom a { + padding: 0 0.4em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom li { + border: 0px; + border-right: 1px solid #CCC; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_right, .cp.cpe1_old_apagar .dpt-selected .csform .actions_left { + top: 2.2em; + right: 0em; + bottom: 0; + display: block; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_right li, .cp.cpe1_old_apagar .dpt-selected .csform .actions_left li { + width: 2.2em; + display: block; + border-bottom: 1px solid #CCC; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_right li:first-child, .cp.cpe1_old_apagar .dpt-selected .csform .actions_left li:first-child { + border-top: 1px solid #CCC; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_left { + right: auto; + left: 0em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts { + background: transparent; + position: relative; + z-index: 19; + display: table; + width: 100%; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li { + display: table-cell; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li:hover > a { + background-image: -webkit-linear-gradient(top, #1c81c4, #0b6dad); + background-image: -moz-linear-gradient(top, #1c81c4, #0b6dad); + background-image: -ms-linear-gradient(top, #1c81c4, #0b6dad); + background-image: -o-linear-gradient(top, #1c81c4, #0b6dad); + background-image: linear-gradient(to bottom, #1c81c4, #0b6dad); } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a { + background-image: -webkit-linear-gradient(top, #3498DB, #2980C9); + background-image: -moz-linear-gradient(top, #3498DB, #2980C9); + background-image: -ms-linear-gradient(top, #3498DB, #2980C9); + background-image: -o-linear-gradient(top, #3498DB, #2980C9); + background-image: linear-gradient(to bottom, #3498DB, #2980C9); + border-right: 1px solid #fff; + padding: 0.2em; + display: block; + color: white; + text-align: center; + white-space: nowrap; + /* btn-excluir */ } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-excluir, .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar { + text-align: left; + background: #A70808; + color: #c99; + padding-left: 1.7em; + position: relative; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-excluir:hover, .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar:hover { + background-color: #c70808; + color: #ecc; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-excluir::before, .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before { + z-index: 20; + position: absolute; + background: url(/static/img/icon_delete_white.png) no-repeat 50% 50%; + content: ""; + top: 0; + left: 0; + display: block; + color: black; + margin-left: 0.4em; + height: 100%; + width: 2em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar { + background: #1f8b4d; + color: white; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar:hover { + background: #2d9c5c; + color: white; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before { + background: url(/static/img/icon_save_white.png) no-repeat 50% 50%; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a span { + padding: 0 0.7em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li:last-child > a { + border-right: 0px solid #fff; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > ul li:nth-child(even) a { + background: #3385CA; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > ul li a { + border-right: 1px solid #fff; + display: block; + color: white; + background: #2980C9; + font-size: 80%; + padding: 0.23em 1em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > ul li a:hover { + background: #0a5ea4; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior { + table-layout: fixed; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul { + transform: translateY(30px); + transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; + clip: rect(0, 0, 0, 0); + opacity: 0; + position: absolute; + margin-left: 0.5em; + box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); + -webkit-transition-delay: 0.4s; + /* Safari */ + transition-delay: 0.4s; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul li a { + border-right: 0px !important; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul li:first-child::before { + border-width: 0.375rem; + border-style: inset inset solid; + content: ""; + display: block; + height: 0px; + width: 0px; + border-color: transparent transparent #3385CA; + position: absolute; + top: -0.71rem; + left: 0.9375rem; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul li:first-child:hover::before { + border-color: transparent transparent #0A5EA4; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul::after { + content: ""; + position: absolute; + z-index: -1; + left: 0; + top: rem-calc(-25px); + height: rem-calc(25px); + width: 100%; + transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior:hover > ul { + transform: translateY(7px); + transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; + opacity: 1; + clip: rect(-100px, 2000px, 2000px, -100px); } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir { + display: block; + position: static; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul { + transform: translateY(30px); + transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; + clip: rect(0, 0, 0, 0); + opacity: 0; + position: absolute; + margin-left: 0.5em; + box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); + -webkit-transition-delay: 0.4s; + /* Safari */ + transition-delay: 0.4s; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li a { + border-right: 0px !important; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child::before { + border-width: 0.375rem; + border-style: inset inset solid; + content: ""; + display: block; + height: 0px; + width: 0px; + border-color: transparent transparent #3385CA; + position: absolute; + top: -0.71rem; + left: 0.9375rem; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child:hover::before { + border-color: transparent transparent #0A5EA4; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul::after { + content: ""; + position: absolute; + z-index: -1; + left: 0; + top: rem-calc(-25px); + height: rem-calc(25px); + width: 100%; + transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir:hover > ul { + transform: translateY(7px); + transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; + opacity: 1; + clip: rect(-100px, 2000px, 2000px, -100px); } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul { + right: 0.5em; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li a { + background-color: #A70808; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li a:hover { + background: #c70808; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child::before { + border-color: transparent transparent #A70808; + right: 10%; + left: auto; } + .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child:hover::before { + border-color: transparent transparent #c70808; } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo { + z-index: 2000; } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul { + transform: translateY(30px); + transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; + clip: rect(0, 0, 0, 0); + opacity: 0; + position: absolute; + margin-left: 0.5em; + box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); + -webkit-transition-delay: 0.4s; + /* Safari */ + transition-delay: 0.4s; } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul li a, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul li a { + border-right: 0px !important; } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul li:first-child::before, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul li:first-child::before { + border-width: 0.375rem; + border-style: inset inset solid; + content: ""; + display: block; + height: 0px; + width: 0px; + border-color: transparent transparent #3385CA; + position: absolute; + top: -0.71rem; + left: 0.9375rem; } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul li:first-child:hover::before, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul li:first-child:hover::before { + border-color: transparent transparent #0A5EA4; } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul::after, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul::after { + content: ""; + position: absolute; + z-index: -1; + left: 0; + top: rem-calc(-25px); + height: rem-calc(25px); + width: 100%; + transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li:hover > ul, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li:hover > ul { + transform: translateY(7px); + transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; + opacity: 1; + clip: rect(-100px, 2000px, 2000px, -100px); } + .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li.menu_excluir > ul li:first-child::before, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li.menu_excluir > ul li:first-child::before { + right: auto; + left: 0.9375rem; } + .cp.cpe1_old_apagar .dpt-selected .csform textarea { + margin: 0; + resize: vertical; + min-height: 12.6em; + border: 0px; + font-size: 120%; + width: 100%; } + .cp.cpe1_old_apagar .dpt-selected .csform textarea:focus { + background: #fff; } + .cp.cpe1_old_apagar .dpt-selected .csform textarea::-webkit-input-placeholder { + color: #c70808; + opacity: 0.6; + font-size: 80%; } + .cp.cpe1_old_apagar .dpt-selected .csform textarea:-moz-placeholder { + /* Firefox 18- */ + color: #c70808; } + .cp.cpe1_old_apagar .dpt-selected .csform textarea::-moz-placeholder { + /* Firefox 19+ */ + color: #c70808; } + .cp.cpe1_old_apagar .dpt-selected .csform textarea:-ms-input-placeholder { + color: #c70808; + opacity: 0.6; } + .cp.cpe1_old_apagar .selected { + background-color: rgba(255, 255, 255, 0.5); } + .cp.cpe1_old_apagar .selected a:hover { + color: #16407c !important; + font-weight: normal !important; } + +.result-busca-dispositivo, .lista-dispositivo { + padding: 0 0 1em; + min-height: 3em; } + .result-busca-dispositivo ul, .lista-dispositivo ul { + list-style: none; + margin: 0; + padding: 1em 0 0; + transition: all 2s linear; + clear: both; } + .result-busca-dispositivo ul li, .lista-dispositivo ul li { + display: table; + border-collapse: separate; + border-bottom: 1px solid white; + width: 100%; } + .result-busca-dispositivo ul li.ta_title, .lista-dispositivo ul li.ta_title { + background-color: rgba(0, 0, 0, 0.15); + border-radius: 4px 4px 0 0; + width: 100%; } + .result-busca-dispositivo ul li:last-child .itemlabel, .lista-dispositivo ul li:last-child .itemlabel { + border-radius: 0 0 4px 0px; + margin: 0px; } + .result-busca-dispositivo ul li:last-child .iteminput, .lista-dispositivo ul li:last-child .iteminput { + border-radius: 0 0 0px 4px; } + .result-busca-dispositivo ul li .iteminput, .lista-dispositivo ul li .iteminput { + background-color: rgba(0, 0, 0, 0.1); + border-right: 1px solid white; + display: table-cell; + padding: 0.5em; + vertical-align: middle; + text-align: center; } + .result-busca-dispositivo ul li .iteminput input, .lista-dispositivo ul li .iteminput input { + margin: 0; } + .result-busca-dispositivo ul li .itemlabel, .lista-dispositivo ul li .itemlabel { + background-color: rgba(0, 0, 0, 0.1); + display: table-cell; + padding: 0.5em; + vertical-align: middle; + width: 100%; } + .result-busca-dispositivo ul li .itemlabel .artigo, .lista-dispositivo ul li .itemlabel .artigo { + float: none; } + .result-busca-dispositivo .nomenclatura_heranca, .lista-dispositivo .nomenclatura_heranca { + font-size: 90%; + color: #057dba; + display: inline; } + +.lista-dispositivo.controls-radio-checkbox { + border: 0px; } + +.label_vigencia { + border-top: 1px solid white; + display: inline-block; + color: #555; } + .label_vigencia span { + color: gray; } + +.cp-nav-parents > .dropdown-menu { + left: 0; + right: auto; } + .cp-nav-parents > .dropdown-menu::before { + content: ''; + position: absolute; + top: -11px; + width: 100%; + height: 11px; } + +.cp-nav-parents:hover > .dropdown-menu { + display: block; } + +.table-notificacoes tbody tr td { + border-top: 1px solid white; + padding: 5px; + vertical-align: middle; } + .table-notificacoes tbody tr td ul { + margin: 0px; + /*padding: 0px; + list-style: none;*/ } + .table-notificacoes tbody tr td ul li:hover { + background-color: rgba(0, 0, 0, 0.1); } + +.btn-modal-open { + float: right; } + +.class_color_container { + background: #ddd !important; } + +.clear { + clear: both; } + +.mce-tinymce.mce-container { + border: 1px solid #ccc !important; + margin-right: 2px; } + +.mce-btn button:hover { + background-color: rgba(0, 0, 0, 0.1) !important; + text-shadow: 0 0 5px #fff; + box-shadow: 0 0 5px #777; } + +.mce-menu { + background: #eee !important; } + +.displaynone { + display: none !important; } + +@media only screen and (max-width: 800px) { + .cp .fixed { + z-index: 98; + position: relative; } + .cp.cpe1 .dpt-selected { + margin: 1em 0; } + .cp.cpe1 .dpt-selected .csform .actions_parents, .cp.cpe1 .dpt-selected .csform .label_status { + font-size: 80%; + position: static !important; + display: block !important; + padding: 0em; + height: auto !important; + left: 0; + right: auto; + text-align: left; } + .cp.cpe1 .dpt-selected .csform .actions_parents div, .cp.cpe1 .dpt-selected .csform .actions_parents li, .cp.cpe1 .dpt-selected .csform .label_status div, .cp.cpe1 .dpt-selected .csform .label_status li { + display: inline-block !important; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul { + transform: translateY(30px); + transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; + clip: rect(0, 0, 0, 0); + opacity: 0; + position: absolute; + margin-left: 0.5em; + box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); + -webkit-transition-delay: 0.4s; + /* Safari */ + transition-delay: 0.4s; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul li a { + border-right: 0px !important; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul li:first-child::before { + border-width: 0.375rem; + border-style: inset inset solid; + content: ""; + display: block; + height: 0px; + width: 0px; + border-color: transparent transparent #3385CA; + position: absolute; + top: -0.71rem; + left: 0.9375rem; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul li:first-child:hover::before { + border-color: transparent transparent #0A5EA4; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul::after { + content: ""; + position: absolute; + z-index: -1; + left: 0; + top: rem-calc(-25px); + height: rem-calc(25px); + width: 100%; + transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li:hover > ul { + transform: translateY(7px); + transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; + opacity: 1; + clip: rect(-100px, 2000px, 2000px, -100px); } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a span { + display: none; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-excluir, .cp.cpe1 .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1_old_apagar .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar { + padding-left: 0; + min-width: 1em; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-excluir::before, .cp.cpe1 .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before, .cp.cpe1_old_apagar .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before, .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before { + width: 100%; + margin: 0; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_in, .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_next, .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_prior { + position: static; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_in > ul { + left: 1em !important; + right: 1em !important; + margin-left: 0; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_in > ul li:first-child::before { + left: 37%; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_next > ul { + left: 0 !important; + right: 1em !important; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_prior > ul { + left: 1em !important; + right: 0 !important; + margin-left: 0; + margin-right: 0.5em; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_prior > ul li:first-child::before { + right: 42%; + left: auto; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.menu_excluir > ul { + left: 10% !important; + right: 0 !important; + margin-left: 0; + margin-right: 0.5em; } + .cp.cpe1 .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child::before { + right: 0; + left: auto; } } + +@media print { + .cp .vigencias, .toggle-topbar, .menu-icon, .button, .tipo-vigencias, .dne { + display: none; } + #btn_font_menos, #btn_font_mais { + display: none; } + .container { + width: 100%; } } diff --git a/sapl/templates/auth/user_list.html b/sapl/templates/auth/user_list.html index b24cb764e..949e544cb 100644 --- a/sapl/templates/auth/user_list.html +++ b/sapl/templates/auth/user_list.html @@ -29,7 +29,6 @@ {% endif %} - Criar Usuário + Criar Usuário - {% include 'paginacao.html'%} {% endblock base_content %} diff --git a/sapl/templates/sessao/subnav.yaml b/sapl/templates/sessao/subnav.yaml index 5e768ae4e..b86684e61 100644 --- a/sapl/templates/sessao/subnav.yaml +++ b/sapl/templates/sessao/subnav.yaml @@ -25,6 +25,8 @@ url: expedientemateria_list - title: {% trans 'Oradores do Expediente' %} url: oradorexpediente_list + - title: {% trans 'Votação em Bloco' %} + url: votacao_bloco_expediente - title: {% trans 'Ordem do Dia' %} children: @@ -32,6 +34,8 @@ url: ordemdia_list - title: {% trans 'Presença Ordem do Dia' %} url: presencaordemdia + - title: {% trans 'Votação em Bloco' %} + url: votacao_bloco_ordemdia - title: {% trans 'Painel Eletrônico' %} url: painel diff --git a/sapl/templates/sessao/votacao/nominal.html b/sapl/templates/sessao/votacao/nominal.html index 96dd28622..27d95c7a0 100644 --- a/sapl/templates/sessao/votacao/nominal.html +++ b/sapl/templates/sessao/votacao/nominal.html @@ -72,46 +72,46 @@ window.history.back(); } - function conta_votos() { - var votos_sim = 0; - var votos_nao = 0; - var votos_abstencao = 0; - var nao_votou = 0; - $('[name=voto_parlamentar]').each(function() { - if (($(this).is(':hidden')) == false) { - switch ($(this).val().substring(0,4)) { - case "Sim:": - votos_sim = votos_sim + 1; - break; - case "Não:": - votos_nao = votos_nao + 1; - break; - case "Abst": - votos_abstencao = votos_abstencao + 1; - break; - case "Não ": - nao_votou = nao_votou + 1; - break; - }; - }; - }); - - $("#soma_votos").empty(); - $("#soma_votos").append("
Sim: " + votos_sim + "
"); - $("#soma_votos").append("
Não: " + votos_nao + "
"); - $("#soma_votos").append("
Abstenções: " + votos_abstencao + "
"); - $("#soma_votos").append("
Ainda não votaram: " + nao_votou + "
"); - var t = setTimeout(function(){ - conta_votos() - }, 500); - } - conta_votos(); - - window.onload = conta_votos(); + function conta_votos() { + var votos_sim = 0; + var votos_nao = 0; + var votos_abstencao = 0; + var nao_votou = 0; + $('[name=voto_parlamentar]').each(function() { + if (($(this).is(':hidden')) == false) { + switch ($(this).val().substring(0,4)) { + case "Sim:": + votos_sim = votos_sim + 1; + break; + case "Não:": + votos_nao = votos_nao + 1; + break; + case "Abst": + votos_abstencao = votos_abstencao + 1; + break; + case "Não ": + nao_votou = nao_votou + 1; + break; + }; + }; + }); + + $("#soma_votos").empty(); + $("#soma_votos").append("
Sim: " + votos_sim + "
"); + $("#soma_votos").append("
Não: " + votos_nao + "
"); + $("#soma_votos").append("
Abstenções: " + votos_abstencao + "
"); + $("#soma_votos").append("
Ainda não votaram: " + nao_votou + "
"); + var t = setTimeout(function(){ + conta_votos() + }, 500); + } + conta_votos(); + + window.onload = conta_votos(); $(window).on('beforeunload', function () { - $("input[type=submit], input[type=button]").prop("disabled", "disabled"); - }); + $("input[type=submit], input[type=button]").prop("disabled", "disabled"); + }); {% endblock extra_js%} diff --git a/sapl/templates/sessao/votacao/votacao_bloco_expediente.html b/sapl/templates/sessao/votacao/votacao_bloco_expediente.html new file mode 100644 index 000000000..55ecdff5a --- /dev/null +++ b/sapl/templates/sessao/votacao/votacao_bloco_expediente.html @@ -0,0 +1,173 @@ +{% extends "crud/detail.html" %} +{% load i18n crispy_forms_tags %} + +{% block base_content %} + +
+ {% csrf_token %} +

+ + + + + + + + + +

{% trans "Tipo de Votação" %}

+
+ +
+ +
+
+
+ +
+

Selecione o(s) expediente(s) desejado(s).

+ + + + + + + +
+ +
+ + {% for o in expedientes %} + + + + {% endfor %} +

{% trans "Expediente" %}

+ + +
+ + + + + + + +{% endblock base_content %} + +{% block extra_js %} + + + +{% endblock extra_js%} diff --git a/sapl/templates/sessao/votacao/votacao_bloco_ordem.html b/sapl/templates/sessao/votacao/votacao_bloco_ordem.html new file mode 100644 index 000000000..a2af7dbe9 --- /dev/null +++ b/sapl/templates/sessao/votacao/votacao_bloco_ordem.html @@ -0,0 +1,174 @@ +{% extends "crud/detail.html" %} +{% load i18n crispy_forms_tags %} + +{% block base_content %} + +
+ {% csrf_token %} +

+ + + + + + + + + +

{% trans "Tipo de Votação" %}

+
+ +
+ +
+
+
+ +
+

Selecione a(s) ordem(s) do dia desejada(s).

+ + + + + + + +
+ +
+ + {% for o in ordem_dia %} + + + + {% endfor %} +

{% trans "Ordem do dia" %}

+ + +
+ + + + + + + +{% endblock base_content %} + +{% block extra_js %} + + + +{% endblock extra_js%} diff --git a/sapl/templates/sessao/votacao/votacao_nominal_bloco.html b/sapl/templates/sessao/votacao/votacao_nominal_bloco.html new file mode 100644 index 000000000..3a9b74c1d --- /dev/null +++ b/sapl/templates/sessao/votacao/votacao_nominal_bloco.html @@ -0,0 +1,149 @@ +{% extends "crud/detail.html" %} +{% load i18n crispy_forms_tags%} + +{% block detail_content %} +
+ {% csrf_token %} + +
+ Votação Nominal + {% if ordens %} + {% for o in ordens %} + +
+ Matéria: {{o.materia}} +
+ Ementa: {{o.materia.ementa|safe}} +
+
+ {% endfor %} + {% else %} + {% for e in expedientes %} + +
+ Matéria: {{e.materia}} +
+ Ementa: {{e.materia.ementa|safe}} +
+
+ {% endfor %} + {% endif %} + {% if total_presentes == 0 %} + + Voltar + {% else %} + +
+ + {% if parlamentares %} + Votos +
+ {% for parlamentar in parlamentares %} +
{{parlamentar.0.nome_parlamentar}}
+
+ {% if parlamentar.1 %} {% endif %} + +
+ {% endfor %} +
+ {% endif %} +
+ Situação da Votação: + +
+ + + + + +
+ +
+
+ Resultado da Votação + +
+
+ +
+
+
+ Observações
+ +
+
+ + + +

+ + + {% endif %} +
+
+{% endblock detail_content %} + +{% block extra_js %} + +{% endblock extra_js%} diff --git a/sapl/templates/sessao/votacao/votacao_simbolica_bloco.html b/sapl/templates/sessao/votacao/votacao_simbolica_bloco.html new file mode 100644 index 000000000..be25d4d69 --- /dev/null +++ b/sapl/templates/sessao/votacao/votacao_simbolica_bloco.html @@ -0,0 +1,80 @@ +{% extends "crud/detail.html" %} +{% load i18n crispy_forms_tags%} + +{% block detail_content %} +
+ {% csrf_token %} + +
+ Votação Simbólica + +
+ {% if ordens %} + {% for o in ordens %} + + Matéria: {{o.materia|safe}} +
+ Ementa: {{o.materia.ementa|safe}} +

+ {% endfor %} + {% else %} + {% for e in expedientes %} + + Matéria: {{e.materia|safe}} +
+ Ementa: {{e.materia.ementa|safe}} +

+ {% endfor %} + {% endif %} + Total presentes: {{total_presentes}} (com presidente) + +
+
+ {% if total_presentes == 0 %} + + Voltar + {% else %} + +
+
Sim:
+
Não:
+
Abstenções:
+
+ +
+
+ A totalização inclui o voto do Presidente? + +
+ +
+ Resultado da Votação + +
+
+ +
+
+ Observações + +
+
+ + + +

+ + + {% endif %} +
+
+{% endblock detail_content %} From c6c994c34495e8741fa0e8bb9b26fa4d3c7a49c1 Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Wed, 19 Dec 2018 14:44:20 -0200 Subject: [PATCH 020/222] =?UTF-8?q?HOTFIX=20-=20definicao=20de=20valor=20d?= =?UTF-8?q?efault=20no=20relat=C3=B3rio=20de=20normas=20por=20vig=C3=AAnci?= =?UTF-8?q?a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/forms.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 36267dbc3..fecba4a52 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -748,6 +748,7 @@ class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet): self.filters['ano'].label = 'Ano' self.form.fields['ano'].required = True self.form.fields['vigencia'] = self.vigencia + self.form.fields['vigencia'].initial = True row1 = to_row([('ano', 12)]) row2 = to_row([('vigencia', 12)]) From c7db9779e0c3cb6194385740123cad465a70360a Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Thu, 20 Dec 2018 08:54:17 -0200 Subject: [PATCH 021/222] HOT-FIX coloca filter_override no novo formato --- sapl/base/forms.py | 14 ++++++-------- sapl/templates/base/relatorios_list.html | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index fecba4a52..a82dcab53 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -694,15 +694,13 @@ class RelatorioNormasMesFilterSet(django_filters.FilterSet): label='Ano da Norma', choices=RANGE_ANOS) - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Ano')), - 'widget': RangeWidgetOverride} - }} - - class Meta: + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Ano')), + 'widget': RangeWidgetOverride} + }} model = NormaJuridica fields = ['ano'] diff --git a/sapl/templates/base/relatorios_list.html b/sapl/templates/base/relatorios_list.html index 87f8933be..012064096 100644 --- a/sapl/templates/base/relatorios_list.html +++ b/sapl/templates/base/relatorios_list.html @@ -58,7 +58,7 @@ {% if estatisticas_acesso_normas %} - Estatísticas de acesso de Normas. + Estatísticas de acesso de Normas Normas por acesso. {% endif %} From 9bf8cc4afe40d169ebed6dade9a239ec82a419e0 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Thu, 20 Dec 2018 14:02:05 -0200 Subject: [PATCH 022/222] fix #2432 (#2434) --- sapl/materia/views.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index ebce51a5d..578357721 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -2039,24 +2039,41 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): if not request.POST['data_encaminhamento']: data_encaminhamento = None else: - data_encaminhamento = tz.localize(datetime.strptime( - request.POST['data_encaminhamento'], "%d/%m/%Y")) + try: + data_encaminhamento = tz.localize(datetime.strptime( + request.POST['data_encaminhamento'], "%d/%m/%Y")) + except ValueError: + msg = _('Formato da data de encaminhamento incorreto.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) if request.POST['data_fim_prazo'] == '': data_fim_prazo = None else: - data_fim_prazo = tz.localize(datetime.strptime( - request.POST['data_fim_prazo'], "%d/%m/%Y")) + try: + data_fim_prazo = tz.localize(datetime.strptime( + request.POST['data_fim_prazo'], "%d/%m/%Y")) + except ValueError: + msg = _('Formato da data fim do prazo incorreto.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) # issue https://github.com/interlegis/sapl/issues/1123 # TODO: usar Form urgente = request.POST['urgente'] == 'True' flag_error = False for materia_id in marcadas: + try: + data_tramitacao = tz.localize(datetime.strptime( + request.POST['data_tramitacao'], "%d/%m/%Y")) + except ValueError: + msg = _('Formato da data da tramitação incorreto.') + messages.add_message(request, messages.ERROR, msg) + return self.get(request, self.kwargs) + t = Tramitacao( materia_id=materia_id, - data_tramitacao=tz.localize(datetime.strptime( - request.POST['data_tramitacao'], "%d/%m/%Y")), + data_tramitacao=data_tramitacao, data_encaminhamento=data_encaminhamento, data_fim_prazo=data_fim_prazo, unidade_tramitacao_local_id=request.POST[ From 0c464b685930aa28476c134d003e138c0c9434a3 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Thu, 20 Dec 2018 14:04:13 -0200 Subject: [PATCH 023/222] Fix #2435 (#2436) --- sapl/base/views.py | 7 ++++++- sapl/templates/base/RelatorioPresencaSessao_filter.html | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sapl/base/views.py b/sapl/base/views.py index 599d6b05f..8d5acce7b 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -10,7 +10,7 @@ from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.core.mail import send_mail from django.core.urlresolvers import reverse -from django.db.models import Count +from django.db.models import Count, Q from django.http import Http404, HttpResponseRedirect from django.template import TemplateDoesNotExist from django.template.loader import get_template @@ -373,8 +373,13 @@ class RelatorioPresencaSessaoView(FilterView): # Completa o dicionario as informacoes parlamentar/sessao/ordem parlamentares_presencas = [] for i, p in enumerate(parlamentares_qs): + m = p.mandato_set.filter(Q(data_inicio_mandato__lte=_range[0], data_fim_mandato__gte=_range[1]) | + Q(data_inicio_mandato__lte=_range[0], data_fim_mandato__isnull=True) | + Q(data_inicio_mandato__gte=_range[0], data_fim_mandato__lte=_range[1])) + m = m.last() parlamentares_presencas.append({ 'parlamentar': p, + 'titular': m.titular, 'sessao_porc': 0, 'ordemdia_porc': 0 }) diff --git a/sapl/templates/base/RelatorioPresencaSessao_filter.html b/sapl/templates/base/RelatorioPresencaSessao_filter.html index e3e447f8d..9836235ca 100644 --- a/sapl/templates/base/RelatorioPresencaSessao_filter.html +++ b/sapl/templates/base/RelatorioPresencaSessao_filter.html @@ -25,6 +25,7 @@ Nome Parlamentar / Partido + Titular Sessão Ordem do Dia @@ -39,6 +40,7 @@ {% for p in parlamentares %} {{p.parlamentar}} / {{p.parlamentar|filiacao_intervalo_filter:date_range|default:"Sem Partido"}} + {%if p.titular %} Sim {% else %} Não {% endif %} {{p.sessao_count}} {{p.sessao_porc}} {{p.ordemdia_count}} From 90dec5fd76c33df51828a58802b5e1e6e1df76db Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 20 Dec 2018 14:13:24 -0200 Subject: [PATCH 024/222] Fixes #2055 - Busca Textual (#2179) Fixes #2055 - Busca Textual --- Dockerfile | 5 +- sapl/base/search_indexes.py | 72 +- sapl/materia/views.py | 2 + sapl/norma/views.py | 2 + sapl/settings.py | 21 +- .../materia/materialegislativa_filter.html | 10 +- .../templates/norma/normajuridica_filter.html | 10 +- solr/docker-compose.yml | 61 + .../sapl_configset/conf/lang/stopwords_en.txt | 54 + .../sapl_configset/conf/lang/stopwords_pt.txt | 253 +++ solr/sapl_configset/conf/managed-schema | 573 +++++++ solr/sapl_configset/conf/params.json | 20 + solr/sapl_configset/conf/protwords.txt | 21 + solr/sapl_configset/conf/saplconfigset.zip | Bin 0 -> 30297 bytes solr/sapl_configset/conf/schema.xml | 165 ++ solr/sapl_configset/conf/solrconfig.xml | 1367 +++++++++++++++++ solr/sapl_configset/conf/stopwords.txt | 14 + solr/sapl_configset/conf/synonyms.txt | 29 + solr_api.py | 155 ++ start.sh | 18 +- 20 files changed, 2797 insertions(+), 55 deletions(-) create mode 100644 solr/docker-compose.yml create mode 100644 solr/sapl_configset/conf/lang/stopwords_en.txt create mode 100644 solr/sapl_configset/conf/lang/stopwords_pt.txt create mode 100644 solr/sapl_configset/conf/managed-schema create mode 100644 solr/sapl_configset/conf/params.json create mode 100644 solr/sapl_configset/conf/protwords.txt create mode 100644 solr/sapl_configset/conf/saplconfigset.zip create mode 100644 solr/sapl_configset/conf/schema.xml create mode 100644 solr/sapl_configset/conf/solrconfig.xml create mode 100644 solr/sapl_configset/conf/stopwords.txt create mode 100644 solr/sapl_configset/conf/synonyms.txt create mode 100755 solr_api.py diff --git a/Dockerfile b/Dockerfile index 3f3adc78e..ffb812d6b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,9 @@ FROM alpine:3.8 ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \ - python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \ - nodejs npm py3-lxml py3-magic postgresql-client poppler-utils antiword vim openssh-client + python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \ + nodejs npm py3-lxml py3-magic postgresql-client poppler-utils antiword \ + curl jq openssh-client vim openssh-client RUN apk update --update-cache && apk upgrade diff --git a/sapl/base/search_indexes.py b/sapl/base/search_indexes.py index f1ec87ddd..0e0283ba8 100644 --- a/sapl/base/search_indexes.py +++ b/sapl/base/search_indexes.py @@ -1,6 +1,4 @@ import os.path -import re -import string import textract import logging @@ -8,6 +6,7 @@ from django.db.models import F, Q, Value from django.db.models.fields import TextField from django.db.models.functions import Concat from django.template import loader +from haystack import connections from haystack.constants import Indexable from haystack.fields import CharField from haystack.indexes import SearchIndex @@ -24,6 +23,7 @@ from sapl.utils import RemoveTag class TextExtractField(CharField): + backend = None logger = logging.getLogger(__name__) def __init__(self, **kwargs): @@ -34,24 +34,20 @@ class TextExtractField(CharField): self.model_attr = (self.model_attr, ) def solr_extraction(self, arquivo): - extracted_data = self._get_backend(None).extract_file_contents( - arquivo)['contents'] - # Remove as tags xml - self.logger.debug("Removendo as tags xml.") - extracted_data = re.sub('<[^>]*>', '', extracted_data) - # Remove tags \t e \n - self.logger.debug("Removendo as \t e \n.") - extracted_data = extracted_data.replace( - '\n', ' ').replace('\t', ' ') - # Remove sinais de pontuação - self.logger.debug("Removendo sinais de pontuação.") - extracted_data = re.sub('[' + string.punctuation + ']', - ' ', extracted_data) - # Remove espaços múltiplos - self.logger.debugger("Removendo espaços múltiplos.") - extracted_data = " ".join(extracted_data.split()) - - return extracted_data + if not self.backend: + self.backend = connections['default'].get_backend() + try: + with open(arquivo.path, 'rb') as f: + content = self.backend.extract_file_contents(f) + if not content or not content['contents']: + return '' + data = content['contents'] + except Exception as e: + print('erro processando arquivo: ' % arquivo.path) + self.logger.error(arquivo.path) + self.logger.error('erro processando arquivo: ' % arquivo.path) + data = '' + return data def whoosh_extraction(self, arquivo): @@ -66,11 +62,11 @@ class TextExtractField(CharField): language='pt-br').decode('utf-8').replace('\n', ' ').replace( '\t', ' ') - def print_error(self, arquivo): - self.logger.error("Erro inesperado processando arquivo: {}".format(arquivo.path)) - msg = 'Erro inesperado processando arquivo: %s' % ( - arquivo.path) - print(msg) + def print_error(self, arquivo, error): + msg = 'Erro inesperado processando arquivo %s erro: %s' % ( + arquivo.path, error) + print(msg, error) + self.logger.error(msg, error) def file_extractor(self, arquivo): if not os.path.exists(arquivo.path) or \ @@ -81,9 +77,9 @@ class TextExtractField(CharField): if SOLR_URL: try: return self.solr_extraction(arquivo) - except Exception as e: - self.logger.error("Erro no arquivo {}. ".format(arquivo.path) + str(e)) - self.print_error(arquivo) + except Exception as err: + print(str(err)) + self.print_error(arquivo, err) # Em ambiente de DEV utiliza-se o Whoosh # Como ele não possui extração, faz-se uso do textract @@ -91,13 +87,13 @@ class TextExtractField(CharField): try: self.logger.debug("Tentando whoosh_extraction no arquivo {}".format(arquivo.path)) return self.whoosh_extraction(arquivo) - except ExtensionNotSupported as e: - self.logger.error("Erro no arquivo {}".format(arquivo.path) + str(e)) - print(str(e)) - except Exception as e2: - self.logger.error(str(e)) - print(str(e2)) self.print_error(arquivo) + except ExtensionNotSupported as err: + print(str(err)) + self.logger.error(str(err)) + except Exception as err: + print(str(err)) + self.print_error(arquivo, str(err)) return '' def ta_extractor(self, value): @@ -133,7 +129,9 @@ class TextExtractField(CharField): value = getattr(obj, attr) if not value: continue - data += getattr(self, func)(value) + data += getattr(self, func)(value) + ' ' + + data = data.replace('\n', ' ') return data @@ -159,6 +157,10 @@ class DocumentoAcessorioIndex(SearchIndex, Indexable): ) ) + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.text.search_index = self + def get_model(self): return self.model diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 578357721..8af8a19e2 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1810,6 +1810,8 @@ class MateriaLegislativaPesquisaView(FilterView): context['show_results'] = show_results_filter_set(qr) + context['USE_SOLR'] = settings.USE_SOLR if hasattr(settings, 'USE_SOLR') else False + return context diff --git a/sapl/norma/views.py b/sapl/norma/views.py index f7800c42f..0e0ed23e4 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -15,6 +15,7 @@ from django.views.generic import TemplateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView +from sapl import settings from sapl.base.models import AppConfig from sapl.compilacao.views import IntegracaoTaView from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, @@ -107,6 +108,7 @@ class NormaPesquisaView(FilterView): context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' context['show_results'] = show_results_filter_set(qr) + context['USE_SOLR'] = settings.USE_SOLR if hasattr(settings, 'USE_SOLR') else False return context diff --git a/sapl/settings.py b/sapl/settings.py index d30b4df3c..0d6a452bc 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -100,23 +100,28 @@ INSTALLED_APPS = ( # FTS = Full Text Search # Desabilita a indexação textual até encontramos uma solução para a issue # https://github.com/interlegis/sapl/issues/2055 -#HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' -HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' +#HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' # Disable auto index +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' SEARCH_BACKEND = 'haystack.backends.whoosh_backend.WhooshEngine' SEARCH_URL = ('PATH', PROJECT_DIR.child('whoosh')) -SOLR_URL = config('SOLR_URL', cast=str, default='') -if SOLR_URL: +# SOLR +USE_SOLR = config('USE_SOLR', cast=bool, default=False) +SOLR_URL = config('SOLR_URL', cast=str, default='http://localhost:8983') +SOLR_COLLECTION = config('SOLR_COLLECTION', cast=str, default='sapl') + +if USE_SOLR: SEARCH_BACKEND = 'haystack.backends.solr_backend.SolrEngine' - SEARCH_URL = ('URL', config('SOLR_URL', cast=str)) - # ...or for multicore... - # 'URL': 'http://127.0.0.1:8983/solr/mysite', + SEARCH_URL = ('URL', '{}/solr/{}'.format(SOLR_URL, SOLR_COLLECTION)) +# BATCH_SIZE: default is 1000 if omitted, avoid Too Large Entity Body errors HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': SEARCH_BACKEND, - SEARCH_URL[0]: SEARCH_URL[1] + SEARCH_URL[0]: SEARCH_URL[1], + 'BATCH_SIZE': 500, + 'TIMEOUT': 60, }, } diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index cdd408af3..5ff3eaee0 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -3,11 +3,13 @@ {% load crispy_forms_tags %} {% block actions %} +
- + {% if USE_SOLR %} + + Pesquisa Textual + + {% endif %} {% if perms.materia.add_materialegislativa %} diff --git a/sapl/templates/norma/normajuridica_filter.html b/sapl/templates/norma/normajuridica_filter.html index ef668cf36..0c7547661 100644 --- a/sapl/templates/norma/normajuridica_filter.html +++ b/sapl/templates/norma/normajuridica_filter.html @@ -4,11 +4,11 @@ {% block actions %}
- + {% if USE_SOLR %} + + Pesquisa Textual + + {% endif %} {% if perms.norma.add_normajuridica %} diff --git a/solr/docker-compose.yml b/solr/docker-compose.yml new file mode 100644 index 000000000..2f97a7e10 --- /dev/null +++ b/solr/docker-compose.yml @@ -0,0 +1,61 @@ +version: '2' +services: + sapldb: + image: postgres:10.5-alpine + restart: always + environment: + POSTGRES_PASSWORD: sapl + POSTGRES_USER: sapl + POSTGRES_DB: sapl + PGDATA : /var/lib/postgresql/data/ + volumes: + - sapldb_data:/var/lib/postgresql/data/ + ports: + - "5432:5432" + + saplsolr: + image: solr:7.4-alpine + restart: always + command: bin/solr start -c -f + volumes: + - solr_data:/opt/solr/server/solr + - solr_configsets:/opt/solr/server/solr/configsets + ports: + - "8983:8983" + + sapl: + image: interlegis/sapl:3.1.138 + # build: . + restart: always + environment: + ADMIN_PASSWORD: interlegis + ADMIN_EMAIL: email@dominio.net + DEBUG: 'False' + USE_TLS: 'False' + EMAIL_PORT: 587 + EMAIL_HOST: smtp.dominio.net + EMAIL_HOST_USER: usuariosmtp + EMAIL_HOST_PASSWORD: senhasmtp + USE_SOLR: 'True' + #SOLR_COLLECTION: sapl + #SOLR_HOST: saplsolr + SOLR_URL: http://saplsolr:8983/solr/sapl + TZ: America/Sao_Paulo + volumes: + - sapl_data:/var/interlegis/sapl/data + - sapl_media:/var/interlegis/sapl/media + - sapl_root:/var/interlegis/sapl + volumes_from: + - saplsolr + depends_on: + - sapldb + - saplsolr + ports: + - "80:80" +volumes: + sapldb_data: + sapl_data: + sapl_media: + sapl_root: + solr_data: + solr_configsets: diff --git a/solr/sapl_configset/conf/lang/stopwords_en.txt b/solr/sapl_configset/conf/lang/stopwords_en.txt new file mode 100644 index 000000000..2c164c0b2 --- /dev/null +++ b/solr/sapl_configset/conf/lang/stopwords_en.txt @@ -0,0 +1,54 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# a couple of test stopwords to test that the words are really being +# configured from this file: +stopworda +stopwordb + +# Standard english stop words taken from Lucene's StopAnalyzer +a +an +and +are +as +at +be +but +by +for +if +in +into +is +it +no +not +of +on +or +such +that +the +their +then +there +these +they +this +to +was +will +with diff --git a/solr/sapl_configset/conf/lang/stopwords_pt.txt b/solr/sapl_configset/conf/lang/stopwords_pt.txt new file mode 100644 index 000000000..acfeb01af --- /dev/null +++ b/solr/sapl_configset/conf/lang/stopwords_pt.txt @@ -0,0 +1,253 @@ + | From svn.tartarus.org/snowball/trunk/website/algorithms/portuguese/stop.txt + | This file is distributed under the BSD License. + | See http://snowball.tartarus.org/license.php + | Also see http://www.opensource.org/licenses/bsd-license.html + | - Encoding was converted to UTF-8. + | - This notice was added. + | + | NOTE: To use this file with StopFilterFactory, you must specify format="snowball" + + | A Portuguese stop word list. Comments begin with vertical bar. Each stop + | word is at the start of a line. + + + | The following is a ranked list (commonest to rarest) of stopwords + | deriving from a large sample of text. + + | Extra words have been added at the end. + +de | of, from +a | the; to, at; her +o | the; him +que | who, that +e | and +do | de + o +da | de + a +em | in +um | a +para | for + | é from SER +com | with +não | not, no +uma | a +os | the; them +no | em + o +se | himself etc +na | em + a +por | for +mais | more +as | the; them +dos | de + os +como | as, like +mas | but + | foi from SER +ao | a + o +ele | he +das | de + as + | tem from TER +à | a + a +seu | his +sua | her +ou | or + | ser from SER +quando | when +muito | much + | há from HAV +nos | em + os; us +já | already, now + | está from EST +eu | I +também | also +só | only, just +pelo | per + o +pela | per + a +até | up to +isso | that +ela | he +entre | between + | era from SER +depois | after +sem | without +mesmo | same +aos | a + os + | ter from TER +seus | his +quem | whom +nas | em + as +me | me +esse | that +eles | they + | estão from EST +você | you + | tinha from TER + | foram from SER +essa | that +num | em + um +nem | nor +suas | her +meu | my +às | a + as +minha | my + | têm from TER +numa | em + uma +pelos | per + os +elas | they + | havia from HAV + | seja from SER +qual | which + | será from SER +nós | we + | tenho from TER +lhe | to him, her +deles | of them +essas | those +esses | those +pelas | per + as +este | this + | fosse from SER +dele | of him + + | other words. There are many contractions such as naquele = em+aquele, + | mo = me+o, but they are rare. + | Indefinite article plural forms are also rare. + +tu | thou +te | thee +vocês | you (plural) +vos | you +lhes | to them +meus | my +minhas +teu | thy +tua +teus +tuas +nosso | our +nossa +nossos +nossas + +dela | of her +delas | of them + +esta | this +estes | these +estas | these +aquele | that +aquela | that +aqueles | those +aquelas | those +isto | this +aquilo | that + + | forms of estar, to be (not including the infinitive): +estou +está +estamos +estão +estive +esteve +estivemos +estiveram +estava +estávamos +estavam +estivera +estivéramos +esteja +estejamos +estejam +estivesse +estivéssemos +estivessem +estiver +estivermos +estiverem + + | forms of haver, to have (not including the infinitive): +hei +há +havemos +hão +houve +houvemos +houveram +houvera +houvéramos +haja +hajamos +hajam +houvesse +houvéssemos +houvessem +houver +houvermos +houverem +houverei +houverá +houveremos +houverão +houveria +houveríamos +houveriam + + | forms of ser, to be (not including the infinitive): +sou +somos +são +era +éramos +eram +fui +foi +fomos +foram +fora +fôramos +seja +sejamos +sejam +fosse +fôssemos +fossem +for +formos +forem +serei +será +seremos +serão +seria +seríamos +seriam + + | forms of ter, to have (not including the infinitive): +tenho +tem +temos +tém +tinha +tínhamos +tinham +tive +teve +tivemos +tiveram +tivera +tivéramos +tenha +tenhamos +tenham +tivesse +tivéssemos +tivessem +tiver +tivermos +tiverem +terei +terá +teremos +terão +teria +teríamos +teriam diff --git a/solr/sapl_configset/conf/managed-schema b/solr/sapl_configset/conf/managed-schema new file mode 100644 index 000000000..0cba1950a --- /dev/null +++ b/solr/sapl_configset/conf/managed-schema @@ -0,0 +1,573 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/solr/sapl_configset/conf/params.json b/solr/sapl_configset/conf/params.json new file mode 100644 index 000000000..06114ef25 --- /dev/null +++ b/solr/sapl_configset/conf/params.json @@ -0,0 +1,20 @@ +{"params":{ + "query":{ + "defType":"edismax", + "q.alt":"*:*", + "rows":"10", + "fl":"*,score", + "":{"v":0} + }, + "facets":{ + "facet":"on", + "facet.mincount": "1", + "":{"v":0} + }, + "velocity":{ + "wt": "velocity", + "v.template":"browse", + "v.layout": "layout", + "":{"v":0} + } +}} \ No newline at end of file diff --git a/solr/sapl_configset/conf/protwords.txt b/solr/sapl_configset/conf/protwords.txt new file mode 100644 index 000000000..1dfc0abec --- /dev/null +++ b/solr/sapl_configset/conf/protwords.txt @@ -0,0 +1,21 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +# Use a protected word file to protect against the stemmer reducing two +# unrelated words to the same base word. + +# Some non-words that normally won't be encountered, +# just to test that they won't be stemmed. +dontstems +zwhacky + diff --git a/solr/sapl_configset/conf/saplconfigset.zip b/solr/sapl_configset/conf/saplconfigset.zip new file mode 100644 index 0000000000000000000000000000000000000000..13a7a41ce84f6f9fe4af1f73fd10906b37291d7e GIT binary patch literal 30297 zcmagEbBr%g)92ZC-?nYrw)@w%ZQHhO+qQMvw$0nNyXTpAb~kx2D-Wm_H`|_czmrL zFzJTIX;msBgli7KT)4Yv|j_7AbJ z6Y)*y3y79s8`UK*=47)=EjF6~Cn)xZ9nDB>0}={Z{27l22gBEtp)5aO@&un9AK*n- zO3mCKogJTItZ;9xWcEDqF^usqwTFEo)T)m{Wu^2l!^>P?OSw=>9lLVN&G8C1W1D8a>@9xcd0PKBT(qO{=9_h{k|%E!^aXU53E&`UO+hn? z^7;1loONf)3|gbrnXK)~3&BpCSqUw3S4LmWfS!^v)gGyDfuYzX%l~i8^7KxkqPo#8DF7 z?m!vUYUDl_mdUV6Cja$+jCi11dY$tCNKZ5c?iCt>@bPbZD-s2yET%u>R4u`|6lXI5 zfi*fk1cqbni(}4HZXG0PrfV}Qj27uz3e{$C2WzWO1R_o}vknj6>PQyO2!WVZMmsK( zt%)z9`zJJ);OCAZNag5F%$KD44lH;M^opnuL^vR)ws)yHF<~ z55hP-y^O7lS_K2KrZhnew7C3}VXEPON8vHnG{I;c46m5PWve;Qj{BaGA@u; zHaZWPu>1-B%jnyTasvH?^xBASVfet|G}}I`#jjj{WZr7?)07$M7mrS)M?VoEywx&G zH7eJ?mwTP9(?q?j6JepWt8|5aWO>Iu?J7!Xoo;EX`0DvZJL z;sjp1s=|krwpMBD(d$=a|3$7cyLTB()C=urPx6@&^z(i5H`zX|Hw)}YBnWtcRn?Rx z@Ay66zq8x3>NeNsN2cl6a4q@l=UU*w8f1=)&_t~S`Ro7OAcs)SpA5L?nDb`j}>fIFS zU@oQ#UfbqC4&)0p#q>~W88qZ*aH}ipPwR~Lzi^x@te(G!=b|V~UL)cjD7yjcP)e6C zJ$_R*LB1%rjfIx(f?$&qeE^w_n^W5;ab6PL>|Qa-RdWMKfm+DXs-}+zgmc- z!Ys%h?St@(NV+W1JCf&ZR9MQ|$3Im9VIw}=EP~T}gI^bOk?(_jz%9C#dx=GL(>aLU zG`3GZL_8pT5Km>GzQd&tg>8DRxiW@E#nCPYi{=q{;8i=TA5`B2Xzw+ zRu0E%#Mja1sq|+{VuG7z1k^@u(omA+y&J_Y))!ULPS!ncaO`WG@9`~xxhP#JIr&GAj zQpA~LC&F^-Jk~6PJu1M1p-pZ|z9Ic#<`Ix1;qZV>JiBLNR!?ec!NetHRM>I~=LwxN zWEO)}Y#nm(2{Ia78J3&I9{Cf|xIZLD&bmHr0?cgHb0;0{b8>{7(5`DCnXaYf{)AbC0<@tec&-ooPyBzH&jr6PX)%{0uL|N1JZXNIHE?$^;vB*R;vs&w$1TPY z;_D9-waXpwlxn8Emt(+SprOWg& z=_dld|CNi^F7%&I6Mk6CKF<0e;WzzeQoohPB50ErLV^&WOj+3QlsgQLhKo6gPAS{U z|C+Gz`yVs;7=lAUVDnKw=&s(EbASOu!#NR7aB3%zbIW6MkLR6Fh41 zN(Q9pw2`DufxIj%?JV71VD)@`?vSDos93rr613*IB4`PpNG1OBaas0qcV2z3PkZ~U z&Q15fad8{L$*tI~P*Dl37?sAAHwF29iZWzNE=4vM%PnsLQ80S#aBrj7ucj7Dq)|*U zQcAIsAQjU~^-@rGAT#z5j*~7Wr>>V(kH}L3`#O9${d%s%{3jc!g5w80ns;H<11fJp zVkYKE69yz%Ryk^DO78LpgFHsGQoKo2$zb`SXSvvsEK2jwa@=!EH;G+B*lyf;Co(6xr$W?L1x#ay%t{M5D`3ea z%QBN)=QsOhN;hSS% zGJ4k%vT+CL_CXd4^y=NcR>t7Mfc_ZOLFyQYarzjpJeoYT3|l-ubzskD8GUs2S4yhHl+b_OwmmlnGph|l}UlLA$jh6$AKc{U3X@cD1s}9=t;3w zTnZ){;WgLfh)ODotphSVVfsw~rmTxtl5rZF^xdh6bMHC`VcG(SBP!(Lv%4>Drt{)VI2h-pm#jMhjrbclsTHIQDl9wG58oPIjtq^s!R+0qC;!w0d-(6nBXWDV&v6<{Ae<< zR83C)DwitPXM`il)ioky)!1gq7HwBRsT)Fh%N7<1#-NOnN0GGlfr$ke9N@Fw&`S|4 zk|o73g^5y#K<6TmP+%`Xk%||J)|4y?(rqYMF;XD|F$2pa*6yj9K^`fDI6l_$)1%Z9 zXyhx@4{%TGRY8hPvZLdsIaXeJ0U^;X z(&T3`20^6iHbobPc^Jl)h!B5cPUqv%W&qh0whP5{C6VW3+dCyOf?zU;5z;%V=+*34 zvjM-6WHfmaGnP$gGdgn1iZrSs&|m)o4&k3G z(7H$LwdyShReTvcR?8yM`_`Sb;`P@#Aqyo?_i>;T(#;y8mf)s8TIhwq(3tXnz9QUr zxB{;OvHc9UT@%-mfn{^sZFs{n&r*Ae3vmfS*B+%Q&SisBh2&F?LQDeSD=_Y83D|4| zu=;M|KtUS^3NwJ@p9B>lMa2(A%L%U{DY8v$LeT4;_ao5F+=IY)=*ugFv>!$OhCNxktf!xtagMZe%@NEs^4k(u9c+Z%J)clZ@~p-m|fM zfRK)J?qVs498>gh(JlBAuTCde@vFifU4g_h=4uih1EvJ2(MtG z5EBkEj042Syf2RPvX#u~i5;NfMJ5qld5|M`f~l;ExQHRvpr7DgWvUyN>pk%b#D>&( zVx#JbA4eH#%AVI1hurKSQoy~r?bGfxLcAqxl!wnsBv(Eg2C^)5+jMgx1IehRp!v0Z z840`sQ92+K+7sNd`O&!c^xldkFo()Foq+%cVIh5CYfws<;ND+#6*OIMV`YV4gRA&> z{#8tPZepclRz%g{)+lbOC}&?ho`(i(HOxkO9`4n!!;6|>U(Jc`I)O>@K3=7l4Kdas z5;_MU|CPa5jBQOwA0zx?# zq=P6@VYf%|{THY-=>7E|`x$~37O`?YToNYuvw#Z3z|-*7IAyA{ zRhkbEHKxR5v1DyWl|G9~5W{Ml&;SCiK!lzxTi5}HAw8kPcrvE5Ln>i#A510_h{jd} z;K}n%B$Q&uGG^!_*;7@Q3z$KLgpCuD2qHk8MH3H0|5K`#Li$${*&YdGW2ulHc!?DB z@vsM|+mH1P6H1tQG86fyPzY0!vBd*2#HfHJ#UXmJ0wQXlW|3BJeJ~&Zm=O3>vTPMn z%RrUtz_kN4!)O58jfmxDYrVE#Vid@(;vraC{r;EN9B19#FK`JzVTb+ERb$x{cS*zo z_MKlLMi|qG8~$Y$VXCY?ezbOuV5+F%L)Q^bCsMduthjXuIMTI(J@%+GpGqGh%6#uCCOx>9D|8Y z>GYtN(@PK;2;&Dejah^d(EZQb$KltZH#>ORRtl)Q5B@0J=s&pCK2qqOb_VC1&4f0I zr+kJL0@iU*DsuE;%6lPJwzZ1+3dNbpfSylk8j8!xQ6==ZAh8QrY1idN%V&0pVwD|<4pu{I355L7N`jB18lWCab_0HMtHQS-8)0Ex zy^%K*A(~>nFTvR$^h5o!^oNeVbH!IJ8wN6 zFgY>DOn@dQruINlD)AxJy3$ggajF`kxvxFB95&F|gnDnIWs9J}`X*)v4HzAmGRsy2 zC(TB5V8{pqvyWXx(5Z2OMg^b4{8hG#xB)c+vQ_X&H|3*z7bHWjO{wc>V;u|X0zvyN z2pXa3QB=gM&$5hY7z!c2VJPk*)JO*Fcp!r!#MEOj_^e0QnU%5;*>LLO20*aSj)o6{ zz|<^h_p78cm&_7Rp5<2Gx%%bz2NZ`=5|s-Ng4G&d&GydleCHpvtJ}*Vgyx+o`vjEHSAnlBuq6NegF zLlAy8SIV9wvmTd?v*S!ZXc#ra3XojeA~36Wl{ZfuKqi`n5n5d(w%di#a8qtzMDYP0}qA&X< z0N6>B>1b~a8V$ym-kZM&J5|E1)jTUyhOIrRr%-9NoT9{AVyP z7xT5Ofn^6qCm!hqRgopb%!}2*a?RzU$Fzqfs2r4##=p~NUwDf=H2MGhPaI& zDLylqR*O-!e5h{bm@6vC$Zdc8F)@rAe{ngG} zF4X&{4}Qp%3`kpYGpu_n;FT=sn)642UU+J?h1_n7tlb0H*GwNe+Np0LC1w zLxE_X3WM`_c#4kuPHuH#(K0uur-1S_^Zc_z+FUz3_xgLddmm&fLW!1UqWxQhs2fkn z390>XbJ{v1;grp_@u!J0uJ;KL(or)*5Gx(E&A?*z7jEray`kjux_$45CIF_o#t=N~ zlWDl);6nMPs2qg1PI%s{%y}t=_Ot^6=1b<^^vei`HwXyrRunKp8chC4YRKx}lTS64 z+mcY$6eLMh)pndCjFQ}p-gq-8yo+?g4pUW z1nVmV_}-wn1hj-Z26BXf8qY~RJK7};j?-28Sd{OTXcu@I!RMMV=z-Z42~CIP&})O* zcJ;irTS8#^GnIH!{aG$LUw8mb#p7q&ePa3#k=TbE_VbK-&jd963+GT5#YkZyx-fFr z==v?kqfm!;@l6Kvs$R2KU{t%ggYPm#p=k=n+bQG{j^0S%b4fblC55)g*IZxZ5fWgl>8r1O4?;aObKnw zeeBjj#(S;8dSmigW*IYD zSMT|4O1lJJ-6~C;bC743?Z31&{O(H-y;S(=crC@iQ9uaYf{W_vH@+daQLpai>rp** z3f|Zy>Il}&U9MTzkQ|Gw&R|Spj4~C1uQ(!i!aUaTI>O3;d70vIu5FKGOOiWFbDSg1 z%2UPj)xJSydHt79FC05L#OJQE-_cFJR7y;z2twx;*xJ6^^vQ`WztEpXp2~vJPB{iWG>N4XPeXS zB|c9*XMn+_l>UKyx@$Ce@~Z_OC8`Xs9x`+hNbJgx_ur=&`fdy`(J8|F`apL%$cS4B zSY<+^aZ1@u^o=X>X?Avd#o7tm_J^Lot$~b0uSa9`KKhdv9>DUDGY=KF=5Y<$Wx_jv zKnd9Bo6AwYsRk}meI~o7B9wSn!Ck>J1!5R$LRzbfhbxqHzsKg^b@S^K)pk>s-8y%F0!2_3A#_t8jW{w z^1%?{0lKI!zm#Lo8&f=uOmX)ununzAwgRdhzE@^>hu=ld|ns&+DZh1U8p z;7fXl!Oy$}-&7LwmrX^u&CzRwRB37y$WD)$xfx+L*NSW8CU}{82S+T9{A_6e`O7vq zV~wKDWvGKG@07@>^P2DYe&B?H=P=a48U?8&^)Dv$B1Hp3{;;|c@E?l9nkgBsss5Ok zQ(n|hdYsBq?hE8t8F>woHl@KVd4Yx58ow#(Pu0L$>h<{kl`VlPuES6Ct>($liS|>V zl`=!{w30^_1cb8F9KXotdFMIiyw(nV%@H~79Z;$f=YUORTpte5p z+~wi+jRd#S`PTBf9vz(~0MtkQuNJrQ$Sr*PgsYjLbMuL4BtCc2X=pufv^u>7#hpXX zV09-i7pG``O`g}BQ*l~^b)=W+T*#kUve5j`Qau;R-v`FHQ*D*OZ*K>iVc4Hs2A|I^ zM+TvGxL;!zqhUg8INbX5%I+=>rLa;RH-JJ44vBeqt*9RAXkaiFpFg#7Xsc%zHiW!{ zb%)<5iW|@e>-33=iVne&w`1;57i@UqCWQD%m8`}m-I-=&c?AQZj#l{fJ|&Hs6XCu- z{X@-ltD{IaFA`DYxE*`eviFsA%i^l}wlKrhfO(1rUPx=&xj~ZNhuhInn*`#IwS}|} zkwECU>F@h`k8QxrSzwnl$#q%rg^E=FLR?nc*MSxu_az*O+LDX#Pl~QI(wdoW%HgrV zkySYlGmT0f0Srk!^dm}m3(?FwZitWC{T%gAe#IfqsM7BaEqdo{ivr_N+ES7~YJum? z_I$h3Jv3y53=cJ~qIRHw#B%-t#JgYCzMryt*hLr{`hfAuu0!8Xh(`tR8AqqwOSV?H zK1Bv8>4i5>Cu~PyhW_SkhO5-3=&ml>DJDm#wX^rK*FsbJPoOsEh3MUx%f+-E5_CMi zi+;~rPu0El`J{%Si5kHL6a9llCQg440Fc+PyaUweU@!?Xz$V@2D}QGU9`c<C~t$ zgHcZZi`8?eWYSc~H|DEEhB5M*!q# zYW$NTgN4kYd2eZJSl!bSo8Zw7=toWN);&B=x+sO;w)ZHFuMZJ1K&Kaw14$dO>4G<+ zk@seZcI+>TU5V5B%qQN`r102^nlC1!q%Gss47#ha%-M)N8S9--$P0~*PtFA=%olZP z%kPqqnHWP_WE%}%Rep!ecsqtP>WICJ2Jt71dAU4%r?R4+vIsw}tArepIod3|KZopgyln1tRUKISiz4L&zlz%vb_l_NIqOEa=`Qs{?9`&c{m1ai&QBBNJlB{mD2bgXyPrBk{NP4zam|)Wtw;!NGE`U;$HA6}9Qp>k_BO(m zU#sxhPsyUE8tFG^LAX%s`w)x&0Y7d=O)+|2lsf~6-9A*J7?_ekllMPzGjRLP*$el- zDsNmNs37RMba)cWZD$r-3Qtpd2OMsPdpnI|&`U^lP6l&4nHp8M?L?#<{CdX>@iC~; zrANdT81(!g+z{x@9P~RHgJ0ifpOCgpBYTn#XWofSc$Gu@SZ6Jw7YY59MY`*;ZO;==o>y@&Gw_r z+^m)>^>y!5E3)LbL-ueHWn!K9`2hCB&32w?v7f}&u!b6AOoEHGh*hlRR_TApTefur zk{8|CN>uenGMZG3(*$^+$!=O{>X=ysE(m%4fQfTx{ZbjoIW0e{y+EPhKzrA)72=Gy z&|ufbhY$i^jb9(6oVRd zeA;FQ2psl%`+*2cYd?MleI6G7@U@>kbWHD|Wf+#CtaYvmfbc``KqI8^YrH}){DUu# z5b7CepStn+fu8eHqfg{m9-0saZ!{M>hK&OC?YiF-X$l(5D0#~qjhXQW`YSDE*s0!z z^xis2K53HPyy-DN(h=qN1G#=MP4}wa2VID=3tA>QHu1WLMTrB}I}iFhT|6$p5F?aP z+v7Pk7NGru)Z%H;r;FagiHCP*#ARJN6g@lPNrQ3Of^cECyrHSMo6^vgUN-VB9Mwg2 z5vc3B*9&kEWuaKy#*>TX_2HyDD!pm2*mJjg`PZ5v3&^DJcrIFr_s4g6ow1%702%WNp|~*Icuu};cvbzVeLXq-1>F9zCoHv-Z_IBVGB#CEWMQ2m@UAj zpM^^nsDmY)XgGegh{GU=yfzb*PAMTma?h=B3B|1@VfCi?{5Nh(tbaS^M_1XpWt_V| zpUm=4KCgvosSwIYZU-0Q6?v)(a)2R$l{8??!cjCJ*Ey4Tu)+~#<(k=NAbM&&g(VJ^ zEa&9XNuvL`YGH6&erORs3WHXYhO_Dqo{`Ew#(MCU{!Jei0hXV*&oB||nmcd^$rf?T zM!z6RUcw{YVDSMoZ^0)_OHa;E?Su3S{$rG=GHRTR`~j)Bh8{;Kaj8vxGR;E52^#$& zH7~)#9Dm*nxAhvV9w}YwH9IDIkXLp@t!@83gVl!O2^rKRM-yk&RR8u2I%}{I!Vfr8 zrjYez5N&Ew1oz3Sd5alU499>ZXu@E70V9)6MErA}pbd>>-DYkWO)Ifxyf#zBY>z4J zSth=*z$lg3P-JgR$&lA#us`HPCZH%4IEnoSlHfZ_OJ(nj@&o?AmqYai3%NQZ5Ksgm z5D?6NRPw(N19}fzoBv%kTx-fW{}=nFZsU1jY%>8U=POC#vBIUu;#R`0oH;HDl#CDt z1%U$+S1K3i>n5ytC22~Q4HyXD`F6vAEqI>dO~1>-p=q%i+vBJ+dOP8^@^$sZ z8qAgKXyOGg9|Ul@z@+W>2j+EPvEbUdRw|u3kozoQZTrElA49Yp7Qi2G-a#SP<{%v{ z8phY$1(=3C=Fphq0D;c(dDIJB@q5Cc5OI|ZsUTQf3Pie%Sl(yaD~D8E3+Ge~Vh{U{`9N1uAC!vvG# zF$ADd$_$NC7MidWO(h>zj;@$PTvs>2HUwT;1Sh9vS`8}fJOf)$mJ!~-74SqHtj!ki zbVTgCy1(`Ojv?x~>-GM73fn0MJ?{^q_}&G$uV245xWeY{;=I*vb$0^Ai4Up1^)Qn1 zMNy6i@QRUJmsh4!lozzoc@UEm3ze#x^}L<5PzFt<@eHvy#7vn4i8EW* zR~K0!X15nRFl}wNVUuJ{-KV?Uu4E^S=P7j&e7C~lPPsoELityq`s%fS&s0&EsD$dLJB5PypggKcY^M#cC>2wZIwx6n zmnP3A<}%Ba#fPsCaSpTyLV(;s`(lDY^Qpv_&#BL!nl9_okg_)5A(u?LaK(GUqNH>Kr* zL>z!M)tl1MT|xOOlsVxU7F^=449S_c2D{2jKMSSgsruj@!@2JUC0$~=YzvOQTTJ}- z86rWKWIE2Pcfx~lXdXt6Eu7|I!be}BYs4DY329c{O+=@E5lS^1@%4X%+1#=yKak<)= zUfP6XXLc!$w0|?Ua|A{h2D3uj`l>FgM&2IouxK2@d%L3QMY?R5rbnauEz8BP+-M!v z@)-IT>1+0!$Sej<)uI!_Qx6(`yrz(ABrsabgiJ2nPA?8u-PceAO<<-rDKOvIPBJQ$ zvjU92=fbkPP1`ig;I(9<|^RQk*P^KZ%GUEDQeNU%^{D_#=w6r1nBkI zOl3x}DKpGf+Gz&e&;~$YXO`k9WVQP2lDy`)TE24g97QCvL1>Y*X0qx;zC8JUAHQ~n z9|)`-pHc4{r?;)>i|u-JwLpGFCr3}j%T3gZH&1ZgM86;0J zrh9ho`-UvS%W0$ypPW;_+Jh_fRonp`ifgaDEM>U5skFCVZ6NT;By;!U;Zi96jVU*d zRfy~NGh^0nyhZ^eh3|tnFTl`0GCVKl+v@$Ix-g64HBZp{RBBl6Mr!U09?w${Tp^To*0z{LxE(L^jC{#S7vycjTxm zhU)zY3u##N!)^30A_`G0{C;cl658RnvCXfiwZ^Wo%|2IK?)>%o%|F7aPn3=bx>rzd z!)zOn{4lrn#n`+(>{oxoNXQF%J*8cS1$tuBtUV&<(5<4<5f;YM7yMXMvnrH>dg2t+)PuQ5>FHd~J5Zcp=n zsyjwow3qhSTn-?S2x`rqd%WW{WiynQ<(IQ<^1zUwwMt zs;a6dr?6m>3M0yxtW~@3`F^yYnU>|rYHkqwuX!i;+)yQ#|6M+Pbnlf%SPSldTHc%e zBll~|$f-bJWA!j8tEyY!Ww`tZwa69UE)7-|mi398JU4oT;d+JwdeH+xC12B)=|Q z8~va-10*S5o>sS#*~G=K0fStcd6^_RSX&LSJd4&syTo0lzoO<+KoA{%+dNW)R_Q}R z{ZU|z3y4q~3+nq&^C;_+)FY@M@hUp&yTtodwRLc-f} za5{nrXHPR$H92vJ`PF57x=qh4aHek01x6<-6E|>9 zb9GceNk+TmM}_jq-Y{1x#0Qr3nl58q+Bd69FGEg2g_cJlt;Rd7v>WF=N2L-4hgk$q zR6?&_{I^ND{{i))_6lcj2F~EWz<2;Ktv&)p z7|RZvts06%@vqQKHpO{X1|>CD0Dg}3TNH*-EV_!3ogdaXrx5W^H~FTvt?JUKQeB<4 z)g${toLXhN58_n;4y=oGIm3yxCcw4`Qk3s%5mRpb9%>!5UPvd!^Uu!{R-6bQi1~$; zkcKi{GB0mf^#stOmJ5!m1;07S=z3r}D>u_p%;0|9+h|Bg9m!BOJf;?BiM9slgEB~i zhTQ#KmgR#>!`q?Wrk)u%yfiO0XG`JH9Uzw!tO-u7oESnAwUgTSBs61Zv8*K*>s5$0 zsOdU~#L;K+95C7X+SE^Dp0zKLhDC8djsho-Nf`Wx@M71I3lNf;0B=) z!`=ZzyBD89`i1OquAc|~kM&*R6VVPGE z5DEHl_Cd^>ZEElnpd`PcHk@KY>U9&t&Zrz?Ym$VPUVY2TAl1VWm>*4=0^~SbkR(@% zESjh)(JT=(n3_#h+iP%V0`wS!o^qaoGT5Pbp)6Dlq)0>gwW*oND)wWPh`i88MR}3k zC1EsML*#Px7$^-)1@Ut3fvNy{m*y1!!Kv>A9q4Lz{NaO*I9ML_aF4@zF@mVuwmMn% zV$n*Y9di?HTIf(g%Xx^2hxO_tx0k=l`vL{<=|cy_&yORZrwpbvfv@-$GGp!~P+EAz zJS=nJVD#+$2~!KtTIc5?%Xj*T&`=*SoUCoB3tonW4mp~coBPvAUvSBTYwwQ|3EM@K zWGsej5b%|8g(k;N+K#qVV&T;iHHikm-!g^zQ+Q)>B8NT(3DJ@@t1LTYU;}@IP$Uvn z9Muk)#-rYO`|_PsA8R5Tq=i4)>`l})&?5XyYC+R2M7A{-cIP;Q@zRi~M1iF{*dg>KDmno@G2jgLp!&SlX@Q+V~}h9ooN1>#nPFp&HMK z8@U5-M>pR6f=*fjQ)JiING9$-DEX%-C9AkovEED+HF5-7efMUYZ(h{2d#`N+(b3hH z!w;&?4tquN9^!3%?`o&-A#o3#pb>>2x1XXc;GZICr4Wq`JsG|=cg&1?f=ygjvspdV ziTok!FwT40{y;O+9-jV^J5_pZNmj<7qt-F15=}cA>^quJK|FCmST!ZS)QV0Vm1yHa zL7&*ScoHTdSx9(-*Uk^E2I^qve5b0S;)+&fjI(naE^ZFGrAS1v+8lO1We_OXtzok; zIax@k%lvSs8EQD^FI|30e>{pS&c7-${AbyxpA@SW`gY;};Hdqc5K3wNQy+?z!Kf`2 z9bJ#C*c90rx^4VmrdE2WwicP#X6RoeQb^LWd1dEO0~1@Mk0G&kq6+;qbP93_Ch;Q| zc=!FUVgDMA_NS*~xV2}j^sHvDxiIG7SJZ5)g)hp7lpYy4RFwZEX~D(t#DT?ftMg5c zRhowzbIju{Z?Tn%>A~K3llv|bjHQvfIdrUY@@MtHC6OiRCby<;IY(|P;d}Y(HDBvPLYf7B>F@ngTT)y zmB&1n7AWR6X6Dnk&SavPTdASTgyNR1%o_Oh!yfhCVZ}zzJGnOL{yVdFq9u^!mvC%d z4S8?!NOF3SpSTp|L*1UMzFJfgeFC}o~yq zzDEz1?)BN5HY>v=8QJck5J~r_O((T00@GCDDY-*iGHFH|S9KsvLSt62`)Rm+aa1S1 zNBz-_+4+ldL7Rruf@O6q#-q?<(=B#@L|L|PSC%fO1%0Cx#->N?*_?yP+01R>8|w%ZU;`razLE^Z5t~20?~*m?aM@gBfFV z>AZg2m?a`vdcj8Ntq}B$-BZRKpSEx^eKI#6e1Fz2u-Tff>#H!Me{VU=b6Ggj=JOx) zLKzNuQR5#PUV{Kl?}P|0e8N2XEy#AKpzFePlMNnLuUBt$)jv=ytu%~;B7Sc@eV_|` zk}ob1_WB;1GW*3;7e(Lk^3h>oJx;_7^mSvesEOX@^_H9@du@;f;ymMdVzi!8`IIo?_nHo?0w`lxkNeb#9h<^i#zW?5&O5LzSh#hqVsYM5lAl2}O}0 zK~sehE4j~uwepoT{;&v*?pg0v(nZe&GK~8xM z z*k2X-Pj_F?0hW8Ep@ute^q7=PK}j}yrX~H!*aSIH7=Cx9anvx;mh9P4)W1+Fvf zNp9^+_|lw~Tcu1Th>I2|@e6<0(N+hgI++@|uA&I@*Olq`-0zm@ zJk0DKC7}&=(&{Uw*&q@8stAAgVl|1X^8egFZ=Bg#ZoJlSyPwJ1>wbC7{SC~YhB{h} z@4`;#n$DN`NrGF0?>$RnW~LOe?lLadV_hyFOZ+RLD;!~mJ3CV|XJYdC=Eg5^`1JBT zbN;e4yrLobHgmS8llP0r*Hw)^T&L$Ee#d_*4Tg8p3=$BdH_EL;X}j}38hgj!Ox}Lc z`i^aD;$&jm_QcK|O>En?J+U#d&53Q>xRXpg(V6}3v-kV_JK=`UUVWmSLZ{&iK? zb*6$yBEm))>kf0fO)Qe%h_ptD*-AsHKxlPt z`zed2GvhCVdivR!)>ZCrHT z4!$qFD5wan2pAl-%y?23&lKj$pSJos-}$ohNX6VTFp4pN*I}Y4;iUN@QRA}V5p|gD zPk9&JvGBwv^#2+2?FF8?*y{Bz9F?hu6_8ugXT1c0x59|L9HMKeXhe3LU?=wdUFccu z@iNa(UO4SU6_+vleEfgvT3nFqXJ`hQB)s+#e+Xm+0xTD)M@NlaX?FIEG>yIvWSATPSSEVaUk^DUZ7_C zHzT5eoR>+e_SC~*Oeen>=x3ZY63%NEg^qKJo)dTH97_|+5v-3Kml(Hx@P~$vU(Iax z$dz!?g6rgxSfB{>WxcDJOy%wm!QgYPx?3Nm{)x`A2`J$$gew02AbZ8^41?*>$m|96 zeVJwk&`nG~r4d9$|Ex6W%N%daV;MQKMo=EOgBT&|zsR|U<#=*Ay+Uo^`*O5V>ldp- zS2hUyV_9QHm%|?J{WJ?@8dI-E99yKGuSCJ9RUA!NSV!ZMJb<7fCAMO=LBTXTb*{lz9@yV`xI&^}X-oABa z7?02audFImkWGm!_85!V`=3bLQHG*DT9@lsVeOmfXZRYVxwz5J`3B9>+LnCU7zYMY z4fn$i=Ub*18UV|E?tZ(fycdB{P==-ZP209ZqEo*_#l}eMBDM(j=yBOJ7 z`8pm~x~FfgpMq)OGctU6Joc!;c3WWGybB$WWP*+HRFa#$1enG69KVpyo(s}D?oYX$ zIXstAhI`BR+7yAL)PdOIQbSIYS2HTlMeW03bZ9bC#P91rVlgdCElZS-$%+qoz7i|- z^lPxwF&zH-(a~gs?cJ8~&hU9QRX;OkC6)k+?a%bjyfZ<5*%;mL8+Sq z*YX-RS8=6~ndV=sKZe_1Jzj2IWUVrR&+cf->}SLCYf;dbk5dJntEjhIW3RWKnqV)wqL zwO-y@qY$&(N$J%wDO=3<=#omKP{k5fIDB#3Yq1cR`VWUL4IP}o?Eood6{@^~pn@mx z5qDw`jQzIXL#l4%LFFn9&>T(kk*|Y43DYs%Q^2659cKsqW8vYmP%Q;~$&=?gCzi(e zRz-VM40u=Qz4z#JecjNv&vUnf#FH>C9XRB=*t1lS_spVwqt*7%A$8y;A@FktiiHW# z!{T<*sZEYM$%2+P(f#=(0X8_6S=^HZLJFOkwumZ2pzMBtxhTAzN}-PUeXLhvF1bzX ztd6M(v^5xJp~5GXTc@7$hN_w{sqV~1f>rm~OHY(QEPoh*-0 z#~>Z?{>OT$aI`Y=i|K6 z_+5)83-xg}zGYJm*-KjsX~8)cMEDbfgjhEHI=>VYsiaWdaQd?^)Veme%~e&0{o-hd z??zqsEa$@=Ief-cNgAhSaXxrdqxH13SsL8{vdTpp3&i`M(S}g%3DkNr;cvTUyyEZ+ z=za5h3)L;bhD%Np!u^IT!fXao_~z@`xO(PKd+RwXy(eawHl<6g1Vylt1@x1Izj`)u;T!-GVc7Tv};SZIiD?WT zy5}&}xMFu-MLCQ0W9XC1y?V!XbNIviBMNC_I0;2&?AttNT=f_2r0>mMZDd4cTw@Q~ ziFB3>NpjBVX{)&(*Eo0J(5o=%QO?s3;X}uab$y1+xRVE5StUDKV!zpZg~+LmW~fYN zqoADz?Vtp-{xp{4dTyBM_GTsVJhXrv*5cT_t@Aba2;7gkDQ3!sk^b(>}5b`+6@-d z?!y0KI8*7%(D`PVvX>3e>%$JS8#iGseWm-FRfD2EZ7WsXOzy8g^UWw&!L}PYVppdYW0e(u(t(K$ILYgbM^%|v>}H*2?( zo3PQTei|{+ zv-S>}*~3so?jz#%DWE_auk|1^N>O-Sz{;vNtNJ*Tl?%(ynaPP0P~7*g)v^QpjwCjL z10_OHXuX^yU}4pTR(~mQAlt7OoTR?(T^N(Kc`_WM>W29qi`ZUcp0I)3k7;&`fucOB zt8u@0D5o~bU_O8f>p0@GNl?nWgMLWch2|{uV#}M?iPvv3dP&OTO+uCI%>nRYb9kBW z0pP3jU@1GGL_GSG9Tz;JW?0@VJz?okDeZ|)DgRwWErl7}L?Xtwf#-<#^_esM@HT^K zDA%4Oe3q~&<8IAVz`*Wd*45OPB^#==0}#&jI`q|XsbaI?2A7Vcf8j0c0?d9b>19IG zmJL46(8+fl1Y1Y(^qu0j4cysgpoR?x5Lqj%U7G7_8hAWW!Zh2cVTcNH1>vuxNhw0! z{0GwE3~h9c9ML=0&A(=%4}tO4p4vjMZwbZcRJA^Mu>dVY<&Gg{cmaya`15$+-m?I`9H zJ@ij|b2T%NzpC6+qN|6V^je_aaw<-7;+yxUj<{!ja-?$MTn)V3M1dQSpU^}hLQcI2 zH*VQ=C~uPJpkrbo8R&g3_)=pHHliU;-PMtW=i7O4wraLt1GCc4wbPD7ao{El%N*(} zETzNP*P_9~A4pipmkVig5C_u|&Tnm=Y0)OqUVkmH<=dnBUOe{&B%wSTDf^N}$8P>} z74qO%X+J(}FGuAWx`&IC{673tsJbo8{xG;1dU)nIG>6ii)+UI*+>o~4mMEP*CLL}- zgpp*28gBo_BFm|yoA1ue7T+Jc*Zb0OwSJ^t(X0H3L(%w!;Fy{+C%yC1*;Q`5B*c_|TW5?rbk+ze5W(e?s zEi=qZ6mS1bDCuy&4q?m$Lk2LPqdUMP;J1RoZF~+$w9AtHdqbhO=;&21EzNhXLUC0E zBwYwzI!V$O!5bxs;P`fh5)2I%9M3%& zJZZ$V>r_r$s(Qs?qY(9HHi`C#k!OS|KD0e#)jrz$uly7Sj6B`_Beo$*cFshz-f)G& zyNt}$;ohD{6-(IM=-+2&pQp7$w`qh|!2#*P5#7;4D4e@bo5HDW$=brp(f)jhN`f&- zfYwh)saVhkLYYXSJ0iOIaNsQ%sqIwkM0ORwvnN3U=Wvoa3~F20*w+;@ls6L06LW20 z;M)y6bR?35s6rsUzz^qsk=>!do3>h3Q8F2uKA4GL;+^CHg@h5}DPf8?o!j+NnW>T! zK78Tcw4(ZiGaq0rPU*Yj8qQ88fdy~GXL38gTxhrYLRliq*?OYL>l3%;623iIQT4ck zn@7`R+x6N~;L^o}AEq@tUv55uKp?N1I&BM1$E zU*f0+ogHTN)Pr0V8dTY%qx9!SG={*K2frT>(>eEpS!}qS>8lo&9cH#ZBuH22*XY8M zDPhWGsdKyO!ZnLb6u^edShdHM|F>}It)2%mHYl%nXug=iE9c^n zQ(Gd3fU5{Oh#qD|1zbK)o7rs)-)YNXwqsXJ)ukF@Il!AiHl76+)W9Q}mVcx|V+gKz z<>&SG%pzQpN0j#t@OMYiR~f2Df_!>}fj$<4j)mG}lVuzB15b+SxcJ@&fR@IEx`IYc zS?d~Q>EKT}>DN&Q{lW1uQOk0^;5>`|b}i!?oz<QKD}+C6)q7Ky^O+lL3)VtGDG&C1ltF^| z_I?gtWO@>Zs=zVh!vufWh^p7)URk#g-(xsDEq2@AP5ST)@e^z4>jOI#crwgx0SPwz zz#bo=m4L#&wqe7=n6N@?0Dj(P;gACo7tHQ$s&8XB^40Hd-;GLMW>q9<`-8P1GDCaL z7L3uzf}84|4JSh8DNlU6`HU7<(N9nY@T9}>ERWY3&&ZFOZlBuNOrY{*iWVkJqXEkK zyP^Dzy6C60Z+!yh?E{I-Fko=w+JOiW8=B7l?N~R&6`r_izlo|c53f5voDvnYfTd#i zVgKhcS(uG1<(K)>xnK1$73g3h(L=4G-}QZAczbku{&T@ITDo`;>y5OcFHz+dNgIZ<+Y9vG>AP|}(% zlIq$?Tb)PmP-#&x6L$@HLPmZ&qVprS>CDG6(f9#*e^VORq|HKXYkGMAyoo0xHoJ=8 z)?sb|{l%9@ZxZI{pWaLLV|v^wXOR!)ZWG2o?Ja2PsJ^wCE7!Rz!!MfiV5n3iwxu%Y znD#U1E+6d(PZL1y*RcU)DUNaxiN-u6Z~At?T;**dV@^a zk(sQnPBTavr;t9~J*#69=R;14eddvE7z@7?JQGJLXT#XunY48^88W?^9%ILfn8Kl$ z?A^v!CILjgA?uuw^RVPCdai7Q!GZ1V_R7@*gHL!#&?Y7~dV6AKRoJ~)C5HZHMOk<* zh^3B4z%m~iM~Z0q@w)ql$bC_^fHAhYJ`W#a^qsYrJo=-gw-fks)LGbQZkv0ALU&Nc zz*%DDI;!GQgp3)V8GDCZZIMa5$df2jpPMQd0y8zdWKl3pC`qBEDS!d@tLw+|Z=T}F zhX_es#0SfM0m2m<&CrUzA^1?dfkMEaI9^R+gFe#SSi8Kr3O7xbZ?^L~XEs??@vM^Y zwbEbZVia_NU4(cg$jDZMl67h0B!C`Ok`|8#JRsPI)C1qFKZ3zfoTVnlC46eZ>`0>; z`FE_eBDX?@BBULF6MtL?xfJUt-xtczX67F~U36D#FE^)|jVeNMOtFaCL0d2Ni$Y+Z zc=}<9c*A(%Iz`@esK{}?;=_GjNy&DRR0?dzj?ku9^ytxl*F6nGA?J^iVWaeii-yk6 z$YDX(!3QL>u@-la$2vdMH>OWRr_q5YkY2Ih;8rJ3=VxT#MP|~2wQnVgSr2dv7`H|N zu5cL#;rbghUv?}Z1x-~QUbq_e*5LblY|VrVt5q-sW?2Z4^nVk%V8=wu7S1))2~-(t zibY{#T{LzkOt7uxgn#{bRwbeD3c0O}jrh4*W+BUsceZnmIBu!fVMlT+&WPXDwPH6k8hxb+{erC z3AqH~pvpA!4~rpY@=62(v%w1lodMYWl^cqW9;;?np(K%H6m+lg#b73@`g=Z*%hczm zKW8Vt`jnqL`{iZqKG_ZWau08;`NWflJ#YhDGsL%J#?OxsX{N~D-QEAMU(ynsf%tP> zgUm5M>xMJ0+4OL|mpdYiqBvT| z7_O5y3OVRLd#=)r1KxHey=TH?YfOBcs3_W8t6rBL|H$o8>P03|<$?vu+X$25RWTB2 z11n~ijsyj%ojF*bw@>GTbewq@BnMYL-`eCl^CwoeK;LdH9T&D(KA%nWnT2MO$BH}e z5?BUPuLL&Nwl(7yW5=(Y7blVX$c+=_d}=JduX68uc{g6rZYUr8VFk7s8>Griah-^>al)wX^r*?L`RlilH`#G3LdqTrqESBe4pbq!Njs5rj?N%2XwMY@P7 z-u~hQYJTgIF+kNyOE2RN$m2SLAyu1rCmfjZ6Pi!VNPBD8!A(cM^kvnMZ@9!p6IlG+ zIv<@tK)Xbuw=+&{_KViPwYb(NYUrm=&|$@5?P1>KTnm~#y6y=q66hf_N}}+Ohl|rX ziIZ&I@`s(ekP1zHr8wPkS(uleRWA!Z;nzA%bpI!5!Ix14bQaXC;Vm84lk(M zRX9<8Yw}37lU*}Q5P^@=Rc9%|egfb;V_Oz}-3Cg&6vJ%A4?KKl%CYOaMEktMOD8^y zIRM7f1#rglr3dZHO$ukxuq2*JzTS6bypHSB4!c!(9JA5}D8EV1q9-ukzCA74^MiKD zEMam&>-?ZpzQ*S|+G#A#N;N8f%I3n+nzvjqIS;I@t!uTWiMYaiWo*8}NS(ZR-kuvt zke1ou6mv{%BsmvD8#beA`Imq%lHcNws-cz{-CQ+r-(9KIvmoAD8%H)8HE{CjJZ0c+ z^hL*2-Qja_;v8F%#|mvOnL@TAHu}ti9r_k1Bo`pHIqw*1uIJAA(WJ~6~?8Ibi^!H($aL&yeQzaTN!N2GO6c?b*fbo zIo>$odoCA81fzKtV}&M6=X=t2(xq-Z!t8hL<4mV7ePJ`|peEtXJCFB1a*WIGo!(a6 zar`bc!8XE*_q~ob}V%=#o_0i5dI@9H^z>oup_ zp01~lEkntXN8ZpZJP6Ol6OM%`gv=(0Fo)GKj#ig&R5KEunIE(Mr1o!XZ0IxG2 zyP;L8!8v-9o-hb62~Xc4xlYB(jL6y2u{3F(3Pi4-M-7HrhJgjt{tYlKF+1aQ_Ly!p zS}=;SCHyIUlp1to{2-PHdh_;q|k!8G5usH09T?8Z@287FN5GT{V4PpN53I{ zz>7T-#uZc-dz<5Tg+NaY)KDmz7x?A(ia3YYtZbe+ls8{{5=6Y^7u;!RbN|}K&Tdq| z<{E&@HbYIv)AbKbih9hrNWcFADc`*6z=J~pql$TQyn~1BjQ1HhSK-s)e9W;pA+gB= zH&oMru44=7KS48Y4voAA_X0_&LNddhw}#c8^s#A)46X03V)#BzyL9qQ&r94R*b%Xv zV?c=9f%f+PmG_G{j?^nP^=FhHw~$Z_vi@}*5n+F$g#)|KE0ve0i_^z+SIH<&w|BQt z%!lg-r&p^#XN-Q1L7xy~As5a`xIIeP$cg#fu0inL+*$hhe0OP+2$TR8Y_UtS=Qb{| z)To;%wAC&+bF#IlsV-3KE`dR>!jynVnpLBS*zry(cXw_W|2{EN>Maoq(hnj^!)y(5 z846_$p4AlZ*xowvK7UgxQL9e0L9GK|d`|UqS^j-gCcms;BvF%&50v_mfv#zM_qcmp~mAh?sKJAt_nmb{a?y*YpTVZ#UGQI7eV^M9~x_nTy@=Eog$ z`Zc*uH>;Op6J~q-*^W2~dG3HUDbSiCy;gwalwuZL0dL zB?pa_h2AxY<~6zNvJ>N9*KDh2XYHJiB@~!Mdsal^)kUk@=99_LNd6qxgizj+P4RY7 zj@u-dq{4rDo&~lXJtb#%DDH%BrhayD1gF!BlQ3&DrCaZ2^zN3BV^ZF@-rfy@f)+3x zh4_-e!}e_6wl$ivZU^=F!*6@4uAQK*TQ3dHjw+>^ZWLpp`WeXO8qlpU**pz{#ar!x z&2=ueO}XE)WjfdMu2LDTM`K_j6wW6UClZOTrqzfEWCCM-VK&qUe|q- z+G2L)wrf0elIWSn&yVh+`<6Avh)IUMB=FD6j0m^0}Cu3)FY4yC;)vJ zg#?WqtwwAAwIa)=5X#qOkIU&%L4hw(r6j^w1SZ?mP|b?}?p0f)l0v|zTJrCFr9MXt zsPOa4MxM2c)?V$zkZ!T}YixXSzE1Bf@4TD1 zOs^GWY}|jX-Swt!|PJL-v}W#rzT8!;lj`a_vzSFO0j91y$tohHm~az_(f@HKLTz= zI%7v*Vma}N!7wRN^7EU15*@5NR~S)Ux7~3#ClctP8Ay>8-DTl<%ydm@qGW8?!Mj$0 z)rFq`V!t3)!?{*;>-9-XhTwcb83oT_K(_lUJNf24T9Uvj=-ZAd$=Oe_1f!Dq<5Tc( zBf{7WJP;RYRCz89Pi`p^(bRejVeu5#AKl!Oha`ZCtz5UZ>n&w)#ds?&?B9|+{W?3? zCpRqr+8_r)!&gnC*?y*VG8y6C8gm4|8&yLM*rQpxcy!(Oz8Y%uO!hA#bf+K=rvBX= zZ^-=q&}s0&@aG(5$Mi@D3lmd(qY(B8S-lY!aOD zGm(7h@0c~XBu0#9>^Qa9*niyEIz4>8gk`V|E^6FEYg@}o(Gr^hSAd%aS&f2&V16jNx${umpU2&<@^c}2^v;3Z#*~`O$nyJh#Dx#HWz>< z=pscPo}KHQ4~Ozc5N*a(YlO5h+RbV2({xkf=y{+FXs@@u7?`QXvO-+@Xk{xOqG~%n z9GO<|Us$C)`i_fh7kEKwe(a3)&`y*UJ=N4A27XMX*C-LUs#$7@!V53UG}N9FH!-z6 zX12n3c*m?8RD!mUgiH$jTU@xnJkT-)=S)F^IsZ*udx`nmj~x<~6`7~?EiTa(vUO{Y z)RRbEYb%H{bNLQy4|xUZebli`Mj@FDS2?O*Lg^g39rks zF$b>J4!pt{q(im_Ic>MN@+n)dGTeMFYDS*DE~cjr9)U%{f=w35q=Q^0wUc?ynFpv(Ro<9|F)PFrfdx_X?up# zT%x}i<)%z9E^%>&U0tHnOkk?IXLJuPC~_ljyZ!YT7BpwHSVZ1-sS>36#GX5oV{#wz zr4j(6R)KQ?71Xgx{5;*1Kc)WtnZFk#2`GD@iwboaFNWV3&L`rp6N_a-v<~5$S+M`S zggNoDI!i~SCpuZqVlNrH(8KaGnNhNRoQ*T>5#k&cev_2FW0?zD^bvmkaz4X?{1X)} zsr?s80)fycY67N1@e)!&2h`$8w?0O|#6cMOjXVAmURXyf*%!-&CAc(75mGKF*u;`> z-+&VSzI8JSBFJh-%2vYR1He~7*f3$tLU!sBj3da7x3V?vTlL|ao**t}N|Wc(0hLls z6M-V3#?v!yv2o&0RW>Eaz?WKc(YkaT75+{gQeIqy_y6-Q#t0#QfvyrVvi zr(y%IsdHKVR>2^#x6*6$(a(w;2gxIJ9!4JdVY%qAE73%o%Peh*JJGY_QLvXbwG@X1 zmUIAdOmuKyZQpe@*qz-zp{VNc;c18!NXI;r+eid9X?Q{#eovzgVv*lC1hXevlTuH> zYQ;F5#1g~3Yl*(;y;&&1XobFub?y`*(x|KoywIoMAi1P5JubLt>0;R+E{eNSHZx7t zO6-ZYpXq4JY!!!(A}tS0qMUtqC5_og@<@+PNkP13=NIps$3l+9M$KC6fN%qy;*i5= zhTY!BeE^S#eOy9gG1#@Nb>JlAgG&f%#xl1NTjFJIKj#^)ErX=s!z~FOHIz~Q8uAu) z>Q}eb=(e20oF|?Xtz+Uj9kWzgTEjW_JDDNekY$c<47(=O;?Au2-??b#!DHxNk|uL; zu`&;fB%%_4%WvYV)n5)%Et8Y5BpzaS%h{K+;UV=HsFQPR@>>CY0I3p}$G}s-L&f>$Xve18s7-(I=s5$hH83v8Qp6_gvHH0ikJWe(PP3-F%OSwCPJ97;MY zN-B(XNnm8B6MOQTaxP4?un{> z`^6wALQV%?GNJ`edForze8t0VusQj+PSm#-cZbSW7d;13R4W-ITfW;+*t%{py)?GL z9Nuyn`jprW?OB?gN)NSZy1OdpeYD`nZe(f^VwFhybxq~;H^*rr91LN80+==|O?G6V z=Grf>YdD)=fF6n0vUrSq#7mWk*}s3QbxpE_Uw-P_qU{2ndVILWYXAj0m}WDtWbaKR*Q)9F z^ZGSfmJM#>j2=b#>~$cMUiY4TA4o)%Bt;l<2tR}_l{ESH$+}_0Mjlbi#^rkY?tI`) zh*p89w8w|`;P`seX$Ww3OShDt zqcHE={ZM4@{e#Ff_i5XnHm4YzY}6K!*q$=!)HXG139WUk2N79iyLA$PoxBgUIEz}x zgN7j=Eh3E1CGv@m!Zua9&kCGp+3tH3_LfzjZE^ddn85URe+K1`ddhz-b~tn%~#HmWM%Ui)oI}><{SW;-?S@L?q?NX3aj#UmBmcrq`N5rHo|6 zdOKGNuZFLhZ={C8{-O3gM8cw}3aC63#=sFano{_0 z{0`%giC5@r7=T8J9O@PGwOO)nOc<_awUGFPlZstU)}muSS9`A0Emmr+NeC#ipSZX1 zaW-D`%_CtKtu8w;Hs7lHTusCBUa|JCL=ZiulxP=}GH>&PF&gcMCM&B4Ls>q3*_GR_ zqm)K(G0n0{M$|_8bmp?Du|GVukxZOH&C;b6cA+>%)&8E9mUTmMIkE(FdyrMEoH2e{ zR){lig0Ns69)>8V(e+#m!ixT7RXRtEtFZ~A+5k^XH10I=gQdEpd?Y5hkeNx$*`+V8 zLEI$!WZ>$`mtQA*Rsi(Bo(dmO#=slN;D!b;NL1;-hQh+t)j6Z)rnM}Gw=-7yv&VL0 z^9{p9{Ms)aG(fh~y3-XryQ_ufd)aoKY6B_y} zoI(2E!kPb$!2Q33Go~t2c16snJts7hVNA1$9qQe3JcZ57L8ABTLJ*?D6ZJZ@3|@_!5}IFS|2)ucnNd#5krQy{S^Hr z-9S%+I)N>HE8(7MRG-#Dq0Uy_u2o5Z;-zE(6r(au;a^1!*N*HQh|9M5UHm#WH~>l+ z!2V#CCwakoH!1$1)R6mSrL}i&U@E68VE&6&ID&}})2s*fcqQ*bk{XoX+8>i$`fnIv zg5G0CPEBAPI%$FTRY>k(wYS@wS8jvM;!bJ=mb%ww&Yd{O>{zeFMaFiX>I}RiH18K< zPE98W(t|fKOWNIA-BgD#z;@~ z(nD!1+evRU-cx%Ff?p2U6(7MH$oWmqz9&&@kC#CVox$ZM-#a3VYO^5q5D?rqO2hLQ z<4N*f&(M?nl;Y+KhEi9nV^V)=kSu@jZ=$sc7uiTeSa6}QHAzY1{e6JmeqCC)1oO|W z>wi4eT+IJQ0Zsl!0TKVhD&uKqZ|C_}v-JOH0amLj*l#c+c3)_sP8$*I@(#ukaFU#@ z#JIwtmN9sx*si0Q>1I)^IQqZmW}BR~Tp;2We@*i8p)haSVqs_?uu|*K`7Y&GMyOtC z^gAopMbTHYAr#L~5*yVWW+mgxDsKtjpM)+PHZKCb!UNNL5JoJl-H~+8<07A5YUUFZ zfnsHmXlto*16>C6k-PN43=;)A7%Yzqh;ow>9P!(dHCK}UBr0A{&eQRMk07EL8Ff=+ z%fp-6<{M*om%ix=4u)~araKa!RGR2x1ZowEIF>>gJRD)8AhIJTFAK?Uk4D-WZiR3@s>$C)F)sYBT8fM%WXY>sUECu z>sY#RRR-d>Ai6|l{v4=qXFmlYoeqy0A`Fs+8ABs=G5}dqKiuiybfS%>P9For!>^K%xIa{r6n_?>OeahyG`=@L$nSe_yr#?=Js;^ndjW|2_0S zgH!*CPKE>gU-_wjkNHp0+P^ZdsQ~}fuKjz!e+te16}U?M7x+)T*}sSUr~T?*ksmaG zf4H#zJ>EZ+9skP9WckbcKLj5C9`m1{)qiEm*!^YxS84S>N9(_b{O5T7SEQQ5U*tcA a_5VbK`rFR@4`moUK=kkT9?bbauKpJT4iLEj literal 0 HcmV?d00001 diff --git a/solr/sapl_configset/conf/schema.xml b/solr/sapl_configset/conf/schema.xml new file mode 100644 index 000000000..597033929 --- /dev/null +++ b/solr/sapl_configset/conf/schema.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id + + + text + + + + diff --git a/solr/sapl_configset/conf/solrconfig.xml b/solr/sapl_configset/conf/solrconfig.xml new file mode 100644 index 000000000..9a9f29196 --- /dev/null +++ b/solr/sapl_configset/conf/solrconfig.xml @@ -0,0 +1,1367 @@ + + + + + + + + + 7.3.1 + + + + + + + + + + + + + + + + + + + + ${solr.data.dir:} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${solr.lock.type:native} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${solr.ulog.dir:} + ${solr.ulog.numVersionBuckets:65536} + + + + + 300000 + false + + + + + + 30000 + + + + + + + + + + + + + + 1024 + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + 20 + + + 200 + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + explicit + 10 + text + edismax + + + + + + + + + + + + + + + + explicit + json + true + + + + + + + + explicit + + + + + + _text_ + + + + + + + true + ignored_ + _text_ + + + + + + + + + text_general + + + + + + default + _text_ + solr.DirectSolrSpellChecker + + internal + + 0.5 + + 2 + + 1 + + 5 + + 4 + + 0.01 + + + + + + + + + + + + default + on + true + 10 + 5 + 5 + true + true + 10 + 5 + + + spellcheck + + + + + + + + + + true + + + tvComponent + + + + + + + + + + + + true + false + + + terms + + + + + + + + string + + + + + + explicit + + + elevator + + + + + + + + + + + 100 + + + + + + + + 70 + + 0.5 + + [-\w ,/\n\"']{20,200} + + + + + + + ]]> + ]]> + + + + + + + + + + + + + + + + + + + + + + + + ,, + ,, + ,, + ,, + ,]]> + ]]> + + + + + + 10 + .,!? + + + + + + + WORD + + + en + US + + + + + + + + + + + + [^\w-\.] + _ + + + + + + + yyyy-MM-dd'T'HH:mm:ss.SSSZ + yyyy-MM-dd'T'HH:mm:ss,SSSZ + yyyy-MM-dd'T'HH:mm:ss.SSS + yyyy-MM-dd'T'HH:mm:ss,SSS + yyyy-MM-dd'T'HH:mm:ssZ + yyyy-MM-dd'T'HH:mm:ss + yyyy-MM-dd'T'HH:mmZ + yyyy-MM-dd'T'HH:mm + yyyy-MM-dd HH:mm:ss.SSSZ + yyyy-MM-dd HH:mm:ss,SSSZ + yyyy-MM-dd HH:mm:ss.SSS + yyyy-MM-dd HH:mm:ss,SSS + yyyy-MM-dd HH:mm:ssZ + yyyy-MM-dd HH:mm:ss + yyyy-MM-dd HH:mmZ + yyyy-MM-dd HH:mm + yyyy-MM-dd + + + + + java.lang.String + text_general + + *_str + 256 + + + true + + + java.lang.Boolean + booleans + + + java.util.Date + pdates + + + java.lang.Long + java.lang.Integer + plongs + + + java.lang.Number + pdoubles + + + + + + + + + + + + + + + + + + + + + + + + + + text/plain; charset=UTF-8 + + + + + ${velocity.template.base.dir:} + ${velocity.solr.resource.loader.enabled:true} + ${velocity.params.resource.loader.enabled:false} + + + + + 5 + + + + + + + + + + + + + + diff --git a/solr/sapl_configset/conf/stopwords.txt b/solr/sapl_configset/conf/stopwords.txt new file mode 100644 index 000000000..ae1e83eeb --- /dev/null +++ b/solr/sapl_configset/conf/stopwords.txt @@ -0,0 +1,14 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/solr/sapl_configset/conf/synonyms.txt b/solr/sapl_configset/conf/synonyms.txt new file mode 100644 index 000000000..eab4ee875 --- /dev/null +++ b/solr/sapl_configset/conf/synonyms.txt @@ -0,0 +1,29 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +#some test synonym mappings unlikely to appear in real input text +aaafoo => aaabar +bbbfoo => bbbfoo bbbbar +cccfoo => cccbar cccbaz +fooaaa,baraaa,bazaaa + +# Some synonym groups specific to this example +GB,gib,gigabyte,gigabytes +MB,mib,megabyte,megabytes +Television, Televisions, TV, TVs +#notice we use "gib" instead of "GiB" so any WordDelimiterGraphFilter coming +#after us won't split it into two words. + +# Synonym mappings can be used for spelling correction too +pixima => pixma + diff --git a/solr_api.py b/solr_api.py new file mode 100755 index 000000000..9bec45daa --- /dev/null +++ b/solr_api.py @@ -0,0 +1,155 @@ + +import requests +import subprocess +import sys +import argparse + + +class SolrClient: + + LIST_CONFIGSETS = "{}/solr/admin/configs?action=LIST&omitHeader=true&wt=json" + UPLOAD_CONFIGSET = "{}/solr/admin/configs?action=UPLOAD&name={}&wt=json" + LIST_COLLECTIONS = "{}/solr/admin/collections?action=LIST&wt=json" + STATUS_COLLECTION = "{}/solr/admin/collections?action=CLUSTERSTATUS&collection={}&wt=json" + STATUS_CORE = "{}/admin/cores?action=STATUS&name={}" + EXISTS_COLLECTION = "{}/solr/{}/admin/ping?wt=json" + OPTIMIZE_COLLECTION = "{}/solr/{}/update?optimize=true&wt=json" + CREATE_COLLECTION = "{}/solr/admin/collections?action=CREATE&name={}&collection.configName={}&numShards={}&replicationFactor={}&maxShardsPerNode={}&wt=json" + DELETE_COLLECTION = "{}/solr/admin/collections?action=DELETE&name={}&wt=json" + DELETE_DATA = "{}/solr/{}/update?commitWithin=1000&overwrite=true&wt=json" + QUERY_DATA = "{}/solr/{}/select?q=*:*" + + CONFIGSET_NAME = "sapl_configset" + + def __init__(self, url): + self.url = url + + def get_num_docs(self, collection_name): + final_url = self.QUERY_DATA.format(self.url, collection_name) + res = requests.get(final_url) + dic = res.json() + num_docs = dic["response"]["numFound"] + return num_docs + + def list_collections(self): + req_url = self.LIST_COLLECTIONS.format(self.url) + res = requests.get(req_url) + dic = res.json() + return dic['collections'] + + def exists_collection(self, collection_name): + collections = self.list_collections() + return True if collection_name in collections else False + + def maybe_upload_configset(self, force=False): + req_url = self.LIST_CONFIGSETS.format(self.url) + res = requests.get(req_url) + dic = res.json() + configsets = dic['configSets'] + # UPLOAD configset + if not self.CONFIGSET_NAME in configsets or force: + files = {'file': ('saplconfigset.zip', + open('./solr/sapl_configset/conf/saplconfigset.zip', + 'rb'), + 'application/octet-stream', + {'Expires': '0'})} + + req_url = self.UPLOAD_CONFIGSET.format(self.url, self.CONFIGSET_NAME) + + resp = requests.post(req_url, files=files) + print(resp.content) + else: + print('O %s já presente no servidor, NÃO enviando.' % self.CONFIGSET_NAME) + + def create_collection(self, collection_name, shards=1, replication_factor=1, max_shards_per_node=1): + self.maybe_upload_configset() + req_url = self.CREATE_COLLECTION.format(self.url, + collection_name, + self.CONFIGSET_NAME, + shards, + replication_factor, + max_shards_per_node) + res = requests.post(req_url) + if res.ok: + print("Collection '%s' created succesfully" % collection_name) + else: + print("Error creating collection '%s'" % collection_name) + as_json = res.json() + print("Error %s: %s" % (res.status_code, as_json['error']['msg'])) + return False + return True + + def delete_collection(self, collection_name): + if collection_name == '*': + collections = self.list_collections() + else: + collections = [collection_name] + + for c in collections: + req_url = self.DELETE_COLLECTION.format(self.url, c) + res = requests.post(req_url) + if not res.ok: + print("Error deleting collection '%s'", c) + print("Code {}: {}".format(res.status_code, res.text)) + else: + print("Collection '%s' deleted successfully!" % c) + + def delete_index_data(self, collection_name): + req_url = self.DELETE_DATA.format(self.url, collection_name) + res = requests.post(req_url, + data='*:*', + headers={'Content-Type': 'application/xml'}) + if not res.ok: + print("Error deleting index for collection '%s'", collection_name) + print("Code {}: {}".format(res.status_code, res.text)) + else: + print("Collection '%s' data deleted successfully!" % collection_name) + + num_docs = self.get_num_docs(collection_name) + print("Num docs: %s" % num_docs) + + +if __name__ == '__main__': + + parser = argparse.ArgumentParser(description='Cria uma collection no Solr') + + # required arguments + parser.add_argument('-u', type=str, metavar='URL', nargs=1, dest='url', + required=True, help='Endereço do servidor Solr na forma http(s)://
[:port]') + parser.add_argument('-c', type=str, metavar='COLLECTION', dest='collection', nargs=1, + required=True, help='Collection Solr a ser criada') + + # optional arguments + parser.add_argument('-s', type=int, dest='shards', nargs='?', + help='Number of shards (default=1)', default=1) + parser.add_argument('-rf', type=int, dest='replication_factor', nargs='?', + help='Replication factor (default=1)', default=1) + parser.add_argument('-ms', type=int, dest='max_shards_per_node', nargs='?', + help='Max shards per node (default=1)', default=1) + + try: + args = parser.parse_args() + except IOError as msg: + parser.error(str(msg)) + sys.exit(-1) + + url = args.url.pop() + collection = args.collection.pop() + + client = SolrClient(url=url) + + if not client.exists_collection(collection): + print("Collection '%s' doesn't exists. Creating a new one..." % collection) + created = client.create_collection(collection, + shards=args.shards, + replication_factor=args.replication_factor, + max_shards_per_node=args.max_shards_per_node) + if not created: + sys.exit(-1) + else: + print("Collection '%s' exists." % collection) + + num_docs = client.get_num_docs(collection) + if num_docs == 0: + print("Performing a full reindex of '%s' collection..." % collection) + p = subprocess.call(["python3", "manage.py", "rebuild_index", "--noinput"]) diff --git a/start.sh b/start.sh index 9695572ef..865c37079 100755 --- a/start.sh +++ b/start.sh @@ -36,6 +36,10 @@ create_env() { echo "EMAIL_SEND_USER = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "DEFAULT_FROM_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "SERVER_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME + echo "USE_SOLR = ""${USER_SOLR-True}" >> $FILENAME + echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-'sapl'}" >> $FILENAME + echo "SOLR_URL = ""${SOLR_URL-'http://saplsolr:8983'}" >> $FILENAME + echo "[ENV FILE] done." } @@ -46,10 +50,22 @@ create_env /bin/sh busy-wait.sh $DATABASE_URL +## SOLR + +NUM_SHARDS=""${NUM_SHARDS-1}" +RF=""${RF-1}" +MAX_SHARDS_PER_NODE=""${NUM_SHARDS-1}" + +# Verifica se a variável USE_SOLR foi definida e é igual a True +if [[ ! -z "$USE_SOLR" ]] && [[ "$USE_SOLR" = "True" ]]; then + python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE & + # python3 manage.py rebuild_index --noinput & +fi + # manage.py migrate --noinput nao funcionava yes yes | python3 manage.py migrate #python3 manage.py collectstatic --no-input -# python3 manage.py rebuild_index --noinput & + echo "Criando usuário admin..." From 66038ec6adb78c0766c5038f5325e5efba3c4420 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 20 Dec 2018 14:57:31 -0200 Subject: [PATCH 025/222] Release: 3.1.139 --- docker-compose.yml | 2 +- sapl/templates/base.html | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3691de798..45a2d206c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.138 + image: interlegis/sapl:3.1.139 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 0291ef7ba..b5a4d1098 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -184,7 +184,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.138 + Release: 3.1.139

diff --git a/setup.py b/setup.py index fd2490fbf..29e5d94f8 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.138', + version='3.1.139', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 984a9cedef0d102c66d1131b6d87576656140138 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 20 Dec 2018 15:37:50 -0200 Subject: [PATCH 026/222] HOT-FIX: conserta --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index 865c37079..ab37fb86e 100755 --- a/start.sh +++ b/start.sh @@ -54,7 +54,7 @@ create_env NUM_SHARDS=""${NUM_SHARDS-1}" RF=""${RF-1}" -MAX_SHARDS_PER_NODE=""${NUM_SHARDS-1}" +MAX_SHARDS_PER_NODE=""${MAX_SHARDS_PER_NODE-1}" # Verifica se a variável USE_SOLR foi definida e é igual a True if [[ ! -z "$USE_SOLR" ]] && [[ "$USE_SOLR" = "True" ]]; then From 0c87632ffe8308e7a74aa57a60450cf834dd041f Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 20 Dec 2018 15:54:36 -0200 Subject: [PATCH 027/222] =?UTF-8?q?HOT-FIX:=20adiciona=20permiss=C3=A3o=20?= =?UTF-8?q?de=20acesso=20a=20vota=C3=A7=C3=A3o=20em=20bloco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/sessao/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index b705e302f..0b18ccbcf 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -3280,7 +3280,7 @@ class JustificativaAusenciaCrud(MasterDetailCrud): pass -class VotacaoEmBlocoExpediente(ListView): +class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView): model = ExpedienteMateria template_name = 'sessao/votacao/votacao_bloco_expediente.html' @@ -3303,7 +3303,7 @@ class VotacaoEmBlocoExpediente(ListView): return context -class VotacaoEmBlocoOrdemDia(ListView): +class VotacaoEmBlocoOrdemDia(PermissionRequiredForAppCrudMixin, ListView): model = OrdemDia template_name = 'sessao/votacao/votacao_bloco_ordem.html' app_label = AppConfig.label @@ -3325,7 +3325,7 @@ class VotacaoEmBlocoOrdemDia(ListView): return context -class VotacaoEmBlocoSimbolicaView(TemplateView): +class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateView): """ Votação Simbólica @@ -3502,7 +3502,7 @@ class VotacaoEmBlocoSimbolicaView(TemplateView): return self.render_to_response(context) -class VotacaoEmBlocoNominalView(TemplateView): +class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView): """ Votação Nominal """ From b4b6d735fbe10d0c334a6aa4daa5cc29be9a0ee0 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 21 Dec 2018 16:54:58 -0200 Subject: [PATCH 028/222] HOT-FIX: fix docker entrypoint script --- sapl/settings.py | 2 +- start.sh | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/sapl/settings.py b/sapl/settings.py index 0d6a452bc..dba421f72 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -120,7 +120,7 @@ HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': SEARCH_BACKEND, SEARCH_URL[0]: SEARCH_URL[1], - 'BATCH_SIZE': 500, + 'BATCH_SIZE': 1000, 'TIMEOUT': 60, }, } diff --git a/start.sh b/start.sh index ab37fb86e..c3049adc3 100755 --- a/start.sh +++ b/start.sh @@ -36,7 +36,7 @@ create_env() { echo "EMAIL_SEND_USER = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "DEFAULT_FROM_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "SERVER_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME - echo "USE_SOLR = ""${USER_SOLR-True}" >> $FILENAME + echo "USE_SOLR = ""${USE_SOLR-False}" >> $FILENAME echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-'sapl'}" >> $FILENAME echo "SOLR_URL = ""${SOLR_URL-'http://saplsolr:8983'}" >> $FILENAME @@ -52,19 +52,18 @@ create_env ## SOLR -NUM_SHARDS=""${NUM_SHARDS-1}" -RF=""${RF-1}" -MAX_SHARDS_PER_NODE=""${MAX_SHARDS_PER_NODE-1}" +NUM_SHARDS=${NUM_SHARDS:=1} +RF=${RF:=1} +MAX_SHARDS_PER_NODE=${MAX_SHARDS_PER_NODE:=1} -# Verifica se a variável USE_SOLR foi definida e é igual a True -if [[ ! -z "$USE_SOLR" ]] && [[ "$USE_SOLR" = "True" ]]; then +if [ "${USE_SOLR-False}" == "True" ]; then python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE & # python3 manage.py rebuild_index --noinput & fi # manage.py migrate --noinput nao funcionava yes yes | python3 manage.py migrate -#python3 manage.py collectstatic --no-input +# python3 manage.py collectstatic --no-input echo "Criando usuário admin..." From fecf9ca04813fe4a8ed5470f2de625421660f4ac Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 21 Dec 2018 17:15:26 -0200 Subject: [PATCH 029/222] HOT-FIX: muda interpreter para BASH --- Dockerfile | 2 +- start.sh | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index ffb812d6b..f4953de84 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM alpine:3.8 ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \ python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \ nodejs npm py3-lxml py3-magic postgresql-client poppler-utils antiword \ - curl jq openssh-client vim openssh-client + curl jq openssh-client vim openssh-client bash RUN apk update --update-cache && apk upgrade diff --git a/start.sh b/start.sh index c3049adc3..cdb3b6868 100755 --- a/start.sh +++ b/start.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash create_env() { echo "[ENV FILE] creating .env file..." @@ -48,17 +48,32 @@ create_env #python3 manage.py bower install -/bin/sh busy-wait.sh $DATABASE_URL +/bin/bash busy-wait.sh $DATABASE_URL ## SOLR +USE_SOLR="${USE_SOLR:=False}" +SOLR_URL="${SOLR_URL:='http://saplsolr:8983'}" +SOLR_COLLECTION="${SOLR_COLLECTION:='sapl_$RANDOM'}" NUM_SHARDS=${NUM_SHARDS:=1} RF=${RF:=1} MAX_SHARDS_PER_NODE=${MAX_SHARDS_PER_NODE:=1} if [ "${USE_SOLR-False}" == "True" ]; then + + echo "SOLR configurations" + echo "===================" + echo "URL: $SOLR_URL" + echo "COLLECTION: $SOLR_COLLECTION" + echo "NUM_SHARDS: $NUM_SHARDS" + echo "REPLICATION FACTOR: $RF" + echo "MAX SHARDS PER NODE: $MAX_SHARDS_PER_NODE" + echo "=========================================" + python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE & # python3 manage.py rebuild_index --noinput & +else + echo "Suporte a SOLR não inicializado." fi # manage.py migrate --noinput nao funcionava From bd24e8454a36b74777a26dc569ae5a82802acf25 Mon Sep 17 00:00:00 2001 From: Edward Date: Sat, 22 Dec 2018 10:21:13 -0200 Subject: [PATCH 030/222] =?UTF-8?q?Gerando=20nome=20de=20collection=20alea?= =?UTF-8?q?t=C3=B3rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index cdb3b6868..d3aa17c09 100755 --- a/start.sh +++ b/start.sh @@ -37,7 +37,7 @@ create_env() { echo "DEFAULT_FROM_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "SERVER_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "USE_SOLR = ""${USE_SOLR-False}" >> $FILENAME - echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-'sapl'}" >> $FILENAME + echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-'sapl_$RANDOM'}" >> $FILENAME echo "SOLR_URL = ""${SOLR_URL-'http://saplsolr:8983'}" >> $FILENAME From 53ce5bc5170af368f730476067c4b74d0bb480d4 Mon Sep 17 00:00:00 2001 From: Edward Date: Sat, 22 Dec 2018 10:50:07 -0200 Subject: [PATCH 031/222] =?UTF-8?q?Espera=20at=C3=A9=20que=20Solr=20esteja?= =?UTF-8?q?=20pronto=20para=20requests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check_solr.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 check_solr.sh diff --git a/check_solr.sh b/check_solr.sh new file mode 100644 index 000000000..17ce5fe65 --- /dev/null +++ b/check_solr.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +echo "Waiting for solr connection at $SOLR_URL ..." +while true; do + echo "$SOLR_URL/solr/admin/collections?action=LIST" + RESULT=$(curl -s -o /dev/null -I "$SOLR_URL/solr/admin/collections?action=LIST" -w '%{http_code}') + echo $RESULT + if [ "$RESULT" -eq '200' ]; then + echo "Solr server is up!" + break + else + sleep 3 + fi +done From 2f23f2c8481941153ec7495130a83d7ddcc23c2a Mon Sep 17 00:00:00 2001 From: Edward Date: Sat, 22 Dec 2018 10:52:53 -0200 Subject: [PATCH 032/222] =?UTF-8?q?Espera=20at=C3=A9=20servidor=20Solr=20e?= =?UTF-8?q?star=20pronto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/start.sh b/start.sh index d3aa17c09..a94cea7a5 100755 --- a/start.sh +++ b/start.sh @@ -69,6 +69,8 @@ if [ "${USE_SOLR-False}" == "True" ]; then echo "REPLICATION FACTOR: $RF" echo "MAX SHARDS PER NODE: $MAX_SHARDS_PER_NODE" echo "=========================================" + + /bin/bash check_solr.sh python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE & # python3 manage.py rebuild_index --noinput & From fefab6d94ea39ff4f790188cdb51f261ac441bae Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 28 Dec 2018 07:47:48 -0200 Subject: [PATCH 033/222] fix #2438 (#2439) * fix #2438 * tira ipdb --- sapl/sessao/forms.py | 4 ++-- sapl/sessao/views.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 5a3cde342..87f7b9c47 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -540,10 +540,10 @@ class VotacaoForm(forms.Form): qtde_votos = votos_sim + votos_nao + abstencoes voto_presidente = cleaned_data['voto_presidente'] - if not voto_presidente: + if qtde_presentes and not voto_presidente: qtde_presentes -= 1 - if qtde_votos != qtde_presentes: + if qtde_presentes and qtde_votos != qtde_presentes: raise ValidationError('O total de votos não corresponde com a quantidade de presentes!') return cleaned_data diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 0b18ccbcf..b4665429b 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1902,7 +1902,8 @@ class VotacaoView(SessaoPermissionMixin): qtde_presentes -= 1 if (qtde_votos > qtde_presentes or qtde_votos < qtde_presentes): - form._errors["total_votos"] = ErrorList([u""]) + msg = _('O total de votos não corresponde com a quantidade de presentes!') + messages.add_message(request, messages.ERROR, msg) return self.render_to_response(context) elif (qtde_presentes == qtde_votos): try: @@ -3330,7 +3331,7 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie """ Votação Simbólica """ - + app_label = AppConfig.label template_name = 'sessao/votacao/votacao_simbolica_bloco.html' logger = logging.getLogger(__name__) @@ -3506,6 +3507,7 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView) """ Votação Nominal """ + app_label = AppConfig.label template_name = 'sessao/votacao/votacao_nominal_bloco.html' logger = logging.getLogger(__name__) From 143b8c9e309a42d6360ad2beb5c3328f6eb8e4c1 Mon Sep 17 00:00:00 2001 From: Victor Fabre Date: Fri, 28 Dec 2018 08:07:56 -0200 Subject: [PATCH 034/222] Release: 3.1.140 --- docker-compose.yml | 2 +- sapl/templates/base.html | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 45a2d206c..e3980a639 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.139 + image: interlegis/sapl:3.1.140 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/templates/base.html b/sapl/templates/base.html index b5a4d1098..59f9919f1 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -184,7 +184,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.139 + Release: 3.1.140

diff --git a/setup.py b/setup.py index 29e5d94f8..aa79dc5b8 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.139', + version='3.1.140', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 0008b1c2775f966e91499d0fc289305a89066cdd Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 28 Dec 2018 11:30:22 -0200 Subject: [PATCH 035/222] Reposiciona Solr para depois do migrate --- start.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/start.sh b/start.sh index a94cea7a5..e55739436 100755 --- a/start.sh +++ b/start.sh @@ -38,7 +38,7 @@ create_env() { echo "SERVER_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "USE_SOLR = ""${USE_SOLR-False}" >> $FILENAME echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-'sapl_$RANDOM'}" >> $FILENAME - echo "SOLR_URL = ""${SOLR_URL-'http://saplsolr:8983'}" >> $FILENAME + echo "SOLR_URL = ""${SOLR_URL-'http://localhost:8983'}" >> $FILENAME echo "[ENV FILE] done." @@ -50,9 +50,15 @@ create_env /bin/bash busy-wait.sh $DATABASE_URL + +# manage.py migrate --noinput nao funcionava +yes yes | python3 manage.py migrate +# python3 manage.py collectstatic --no-input + + ## SOLR USE_SOLR="${USE_SOLR:=False}" -SOLR_URL="${SOLR_URL:='http://saplsolr:8983'}" +SOLR_URL="${SOLR_URL:='http://localhost:8983'}" SOLR_COLLECTION="${SOLR_COLLECTION:='sapl_$RANDOM'}" NUM_SHARDS=${NUM_SHARDS:=1} @@ -78,11 +84,6 @@ else echo "Suporte a SOLR não inicializado." fi -# manage.py migrate --noinput nao funcionava -yes yes | python3 manage.py migrate -# python3 manage.py collectstatic --no-input - - echo "Criando usuário admin..." user_created=$(python3 create_admin.py 2>&1) From 91548dd61662ede9cf09760ed9b304c4cbbb61f1 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 1 Jan 2019 14:13:49 -0200 Subject: [PATCH 036/222] Pass Solr URL as parameter to shell script --- check_solr.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/check_solr.sh b/check_solr.sh index 17ce5fe65..b3c4760c4 100644 --- a/check_solr.sh +++ b/check_solr.sh @@ -1,5 +1,9 @@ #!/bin/bash +# Pass the base SOLR URL as parameter, i.e., bash check_solr http://localhost:8983 + +SOLR_URL=$1 + echo "Waiting for solr connection at $SOLR_URL ..." while true; do echo "$SOLR_URL/solr/admin/collections?action=LIST" From 0208c832ca429615b47209dc5817efa5798a08e0 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 1 Jan 2019 14:14:48 -0200 Subject: [PATCH 037/222] Pass Solr URL as param to check_solr script --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index e55739436..1c87a6d1b 100755 --- a/start.sh +++ b/start.sh @@ -76,7 +76,7 @@ if [ "${USE_SOLR-False}" == "True" ]; then echo "MAX SHARDS PER NODE: $MAX_SHARDS_PER_NODE" echo "=========================================" - /bin/bash check_solr.sh + /bin/bash check_solr.sh $SOLR_URL python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE & # python3 manage.py rebuild_index --noinput & From cb82810a51beed926b687dfa299c4a8716fb3794 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 1 Jan 2019 15:02:36 -0200 Subject: [PATCH 038/222] =?UTF-8?q?Customiza=20par=C3=A2metros=20do=20Solr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/start.sh b/start.sh index 1c87a6d1b..fb9a7bddd 100755 --- a/start.sh +++ b/start.sh @@ -37,8 +37,8 @@ create_env() { echo "DEFAULT_FROM_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "SERVER_EMAIL = ""${EMAIL_HOST_USER-''}" >> $FILENAME echo "USE_SOLR = ""${USE_SOLR-False}" >> $FILENAME - echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-'sapl_$RANDOM'}" >> $FILENAME - echo "SOLR_URL = ""${SOLR_URL-'http://localhost:8983'}" >> $FILENAME + echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-sapl}" >> $FILENAME + echo "SOLR_URL = ""${SOLR_URL-http://localhost:8983}" >> $FILENAME echo "[ENV FILE] done." @@ -58,8 +58,8 @@ yes yes | python3 manage.py migrate ## SOLR USE_SOLR="${USE_SOLR:=False}" -SOLR_URL="${SOLR_URL:='http://localhost:8983'}" -SOLR_COLLECTION="${SOLR_COLLECTION:='sapl_$RANDOM'}" +SOLR_URL="${SOLR_URL:=http://localhost:8983}" +SOLR_COLLECTION="${SOLR_COLLECTION:=sapl}" NUM_SHARDS=${NUM_SHARDS:=1} RF=${RF:=1} From 512147014b8a997207750b29cbf6feb131171b6e Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 1 Jan 2019 16:20:59 -0200 Subject: [PATCH 039/222] HOT-FIX: ajusta o ano para 2019 --- .../migrations/0034_auto_20190101_1618.py | 35 +++++++++++++++++++ .../migrations/0018_auto_20190101_1618.py | 25 +++++++++++++ .../migrations/0011_auto_20190101_1618.py | 25 +++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 sapl/materia/migrations/0034_auto_20190101_1618.py create mode 100644 sapl/norma/migrations/0018_auto_20190101_1618.py create mode 100644 sapl/protocoloadm/migrations/0011_auto_20190101_1618.py diff --git a/sapl/materia/migrations/0034_auto_20190101_1618.py b/sapl/materia/migrations/0034_auto_20190101_1618.py new file mode 100644 index 000000000..4c90de970 --- /dev/null +++ b/sapl/materia/migrations/0034_auto_20190101_1618.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-01 18:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0033_auto_20181030_1039'), + ] + + operations = [ + migrations.AlterField( + model_name='materialegislativa', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='materialegislativa', + name='ano_origem_externa', + field=models.PositiveSmallIntegerField(blank=True, choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], null=True, verbose_name='Ano'), + ), + migrations.AlterField( + model_name='numeracao', + name='ano_materia', + field=models.PositiveSmallIntegerField(choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='proposicao', + name='ano', + field=models.PositiveSmallIntegerField(blank=True, choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], default=None, null=True, verbose_name='Ano'), + ), + ] diff --git a/sapl/norma/migrations/0018_auto_20190101_1618.py b/sapl/norma/migrations/0018_auto_20190101_1618.py new file mode 100644 index 000000000..e2fa03289 --- /dev/null +++ b/sapl/norma/migrations/0018_auto_20190101_1618.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-01 18:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('norma', '0017_normaestatisticas'), + ] + + operations = [ + migrations.AlterField( + model_name='anexonormajuridica', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='normajuridica', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + ] diff --git a/sapl/protocoloadm/migrations/0011_auto_20190101_1618.py b/sapl/protocoloadm/migrations/0011_auto_20190101_1618.py new file mode 100644 index 000000000..5f3d7c51d --- /dev/null +++ b/sapl/protocoloadm/migrations/0011_auto_20190101_1618.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-01 18:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0010_auto_20181212_1900'), + ] + + operations = [ + migrations.AlterField( + model_name='documentoadministrativo', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='protocolo', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano do Protocolo'), + ), + ] From bf45e90eb5118130025be76d6fd00300a2554dd9 Mon Sep 17 00:00:00 2001 From: Edward de Oliveira Date: Tue, 1 Jan 2019 16:24:02 -0200 Subject: [PATCH 040/222] HOT-FIX: bump python version for TravisCI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f54ee6d20..9f1c2e55d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: - - 3.5 + - 3.7 services: - postgresql From 2073305da76fd64dc47d256c9b69a677a677f949 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Fri, 4 Jan 2019 08:59:30 -0200 Subject: [PATCH 041/222] Fix #2442 --- sapl/api/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sapl/api/forms.py b/sapl/api/forms.py index b9ad11aca..14a6ef114 100644 --- a/sapl/api/forms.py +++ b/sapl/api/forms.py @@ -100,9 +100,9 @@ class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet): 'tipo', 'nome', ] - def filter_q(self, queryset, name,value): - return SaplGenericRelationSearchFilterSet.filter_q( - self, queryset, value).distinct('nome').order_by('nome') + def filter_q(self, queryset, name, value): + return super().filter_q( + queryset, name, value).distinct('nome').order_by('nome') class AutorSearchForFieldFilterSet(AutorChoiceFilterSet): From f8c38d6ac246a17dcbb2425c4a1bd96ea45e1081 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Fri, 4 Jan 2019 09:20:19 -0200 Subject: [PATCH 042/222] =?UTF-8?q?ajustes=20de=20pep8=20feito=20IDE=20em?= =?UTF-8?q?=20arquivos=20que=20ser=C3=A3o=20alterados=20no=20pr=C3=B3ximo?= =?UTF-8?q?=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/forms.py | 189 ++++++++++++++++++++----------------- sapl/norma/forms.py | 59 +++++++----- sapl/protocoloadm/forms.py | 88 ++++++++++------- sapl/sessao/forms.py | 56 ++++++----- 4 files changed, 223 insertions(+), 169 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 454cd9890..3c2c8c36e 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1,11 +1,11 @@ -import os import logging -import django_filters -from crispy_forms.bootstrap import Alert, FormActions, InlineRadios +import os + +from crispy_forms.bootstrap import Alert, InlineRadios from crispy_forms.helper import FormHelper from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, - Layout, Submit) + Layout) from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, ValidationError @@ -22,6 +22,7 @@ from django.utils.encoding import force_text from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +import django_filters import sapl from sapl.base.models import AppConfig, Autor, TipoAutor @@ -135,7 +136,8 @@ class MateriaSimplificadaForm(ModelForm): row1 = to_row([('tipo', 6), ('numero', 3), ('ano', 3)]) row2 = to_row([('data_apresentacao', 6), ('numero_protocolo', 6)]) - row3 = to_row([('regime_tramitacao', 6), ('em_tramitacao', 3), ('tipo_apresentacao', 3)]) + row3 = to_row([('regime_tramitacao', 6), + ('em_tramitacao', 3), ('tipo_apresentacao', 3)]) row4 = to_row([('ementa', 12)]) row5 = to_row([('texto_original', 12)]) @@ -162,7 +164,7 @@ class MateriaSimplificadaForm(ModelForm): if data_apresentacao.year != ano: self.logger.error("O ano da matéria ({}) é diferente" - " do ano na data de apresentação ({}).".format(ano, data_apresentacao.year)) + " do ano na data de apresentação ({}).".format(ano, data_apresentacao.year)) raise ValidationError("O ano da matéria não pode ser " "diferente do ano na data de apresentação") @@ -212,41 +214,42 @@ class MateriaLegislativaForm(ModelForm): protocolo_antigo = self.instance.numero_protocolo if protocolo: - if not Protocolo.objects.filter(numero=protocolo,ano=ano).exists(): + if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists(): self.logger.error("Protocolo %s/%s não" - " existe" % (protocolo, ano)) + " existe" % (protocolo, ano)) raise ValidationError(_('Protocolo %s/%s não' ' existe' % (protocolo, ano))) if protocolo_antigo != protocolo: exist_materia = MateriaLegislativa.objects.filter( - numero_protocolo=protocolo, - ano=ano).exists() + numero_protocolo=protocolo, + ano=ano).exists() exist_doc = DocumentoAdministrativo.objects.filter( - protocolo_id=protocolo, - ano=ano).exists() + protocolo_id=protocolo, + ano=ano).exists() if exist_materia or exist_doc: self.logger.error("Protocolo %s/%s ja possui" - " documento vinculado" - % (protocolo, ano)) + " documento vinculado" + % (protocolo, ano)) raise ValidationError(_('Protocolo %s/%s ja possui' ' documento vinculado' - % (protocolo, ano))) + % (protocolo, ano))) - p = Protocolo.objects.get(numero=protocolo,ano=ano) + p = Protocolo.objects.get(numero=protocolo, ano=ano) if p.tipo_materia != cleaned_data['tipo']: self.logger.error("Tipo do Protocolo ({}) deve ser o mesmo do Tipo Matéria ({})." - .format(cleaned_data['tipo'], p.tipo_materia)) - raise ValidationError(_('Tipo do Protocolo deve ser o mesmo do Tipo Matéria')) + .format(cleaned_data['tipo'], p.tipo_materia)) + raise ValidationError( + _('Tipo do Protocolo deve ser o mesmo do Tipo Matéria')) if data_apresentacao.year != ano: self.logger.error("O ano da matéria ({}) é diferente " - "do ano na data de apresentação ({})." - .format(ano, data_apresentacao.year)) + "do ano na data de apresentação ({})." + .format(ano, data_apresentacao.year)) raise ValidationError(_("O ano da matéria não pode ser " - "diferente do ano na data de apresentação")) + "diferente do ano na data de apresentação")) ano_origem_externa = cleaned_data['ano_origem_externa'] data_origem_externa = cleaned_data['data_origem_externa'] @@ -254,11 +257,11 @@ class MateriaLegislativaForm(ModelForm): if ano_origem_externa and data_origem_externa and \ ano_origem_externa != data_origem_externa.year: self.logger.error("O ano de origem externa da matéria ({}) é " - " diferente do ano na data de origem externa ({})." - .format(ano_origem_externa, data_origem_externa)) + " diferente do ano na data de origem externa ({})." + .format(ano_origem_externa, data_origem_externa)) raise ValidationError(_("O ano de origem externa da matéria não " - "pode ser diferente do ano na data de " - "origem externa")) + "pode ser diferente do ano na data de " + "origem externa")) return cleaned_data @@ -280,6 +283,7 @@ class MateriaLegislativaForm(ModelForm): return materia + class UnidadeTramitacaoForm(ModelForm): logger = logging.getLogger(__name__) @@ -379,8 +383,8 @@ class RelatoriaForm(ModelForm): comissao = Comissao.objects.get(id=self.initial['comissao']) except ObjectDoesNotExist as e: self.logger.error("Objeto Comissao não encontrado com id={} " - ".A localização atual deve ser uma comissão. " - .format(self.initial['comissao']) + str(e)) + ".A localização atual deve ser uma comissão. " + .format(self.initial['comissao']) + str(e)) msg = _('A localização atual deve ser uma comissão.') raise ValidationError(msg) else: @@ -441,15 +445,15 @@ class TramitacaoForm(ModelForm): destino = ultima_tramitacao.unidade_tramitacao_destino if (destino != self.cleaned_data['unidade_tramitacao_local']): self.logger.error("A origem da nova tramitação ({}) não é igual ao " - "destino da última adicionada ({})!" - .format(self.cleaned_data['unidade_tramitacao_local'], destino)) + "destino da última adicionada ({})!" + .format(self.cleaned_data['unidade_tramitacao_local'], destino)) msg = _('A origem da nova tramitação deve ser igual ao ' 'destino da última adicionada!') raise ValidationError(msg) if cleaned_data['data_tramitacao'] > timezone.now().date(): self.logger.error('A data de tramitação informada ({}) não é ' + - 'menor ou igual a data de hoje!'.format(cleaned_data['data_tramitacao'])) + 'menor ou igual a data de hoje!'.format(cleaned_data['data_tramitacao'])) msg = _( 'A data de tramitação deve ser ' + 'menor ou igual a data de hoje!') @@ -460,8 +464,8 @@ class TramitacaoForm(ModelForm): msg = _('A data da nova tramitação deve ser ' + 'maior que a data da última tramitação!') self.logger.error("A data da nova tramitação ({}) deve ser " - "maior que a data da última tramitação ({})!" - .format(data_tram_form, ultima_tramitacao.data_tramitacao)) + "maior que a data da última tramitação ({})!" + .format(data_tram_form, ultima_tramitacao.data_tramitacao)) raise ValidationError(msg) if data_enc_form: @@ -469,8 +473,8 @@ class TramitacaoForm(ModelForm): msg = _('A data de encaminhamento deve ser ' + 'maior que a data de tramitação!') self.logger.error("A data de encaminhamento ({}) deve ser " - "maior que a data de tramitação! ({})" - .format(data_enc_form, data_tram_form)) + "maior que a data de tramitação! ({})" + .format(data_enc_form, data_tram_form)) raise ValidationError(msg) if data_prazo_form: @@ -478,8 +482,8 @@ class TramitacaoForm(ModelForm): msg = _('A data fim de prazo deve ser ' + 'maior que a data de tramitação!') self.logger.error("A data fim de prazo ({}) deve ser " + - "maior que a data de tramitação ({})!" - .format(data_prazo_form, data_tram_form)) + "maior que a data de tramitação ({})!" + .format(data_prazo_form, data_tram_form)) raise ValidationError(msg) return cleaned_data @@ -529,10 +533,10 @@ class TramitacaoUpdateForm(TramitacaoForm): if self.cleaned_data['unidade_tramitacao_destino'] != \ self.instance.unidade_tramitacao_destino: self.logger.error("Você não pode mudar a Unidade de Destino desta " - "tramitação para {}, pois irá conflitar com a Unidade " - "Local da tramitação seguinte ({})." - .format(self.cleaned_data['unidade_tramitacao_destino'], - self.instance.unidade_tramitacao_destino)) + "tramitação para {}, pois irá conflitar com a Unidade " + "Local da tramitação seguinte ({})." + .format(self.cleaned_data['unidade_tramitacao_destino'], + self.instance.unidade_tramitacao_destino)) raise ValidationError( 'Você não pode mudar a Unidade de Destino desta ' 'tramitação, pois irá conflitar com a Unidade ' @@ -589,15 +593,15 @@ class LegislacaoCitadaForm(ModelForm): try: self.logger.debug("Tentando obter objeto NormalJuridica (numero={}, ano={}, tipo={})." - .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) norma = NormaJuridica.objects.get( numero=cleaned_data['numero'], ano=cleaned_data['ano'], tipo=cleaned_data['tipo']) except ObjectDoesNotExist: self.logger.error("A norma a ser inclusa (numero={}, ano={}, tipo={}) " - "não existe no cadastro de Normas." - .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + "não existe no cadastro de Normas." + .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) msg = _('A norma a ser inclusa não existe no cadastro' ' de Normas.') raise ValidationError(msg) @@ -643,6 +647,7 @@ class LegislacaoCitadaForm(ModelForm): class NumeracaoForm(ModelForm): logger = logging.getLogger(__name__) + class Meta: model = Numeracao fields = ['tipo_materia', @@ -658,8 +663,8 @@ class NumeracaoForm(ModelForm): try: self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}. tipo={})." - .format(self.cleaned_data['numero_materia'], - self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia'])) + .format(self.cleaned_data['numero_materia'], + self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia'])) MateriaLegislativa.objects.get( numero=self.cleaned_data['numero_materia'], ano=self.cleaned_data['ano_materia'], @@ -668,8 +673,8 @@ class NumeracaoForm(ModelForm): msg = _('A matéria a ser inclusa não existe no cadastro' ' de matérias legislativas.') self.logger.error("A MateriaLegislativa a ser inclusa (numero={}, ano={}. tipo={}) não existe no cadastro de matérias legislativas." - .format(self.cleaned_data['numero_materia'], - self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia'])) + .format(self.cleaned_data['numero_materia'], + self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia'])) raise ValidationError(msg) if Numeracao.objects.filter( @@ -680,8 +685,8 @@ class NumeracaoForm(ModelForm): ).exists(): msg = _('Essa numeração já foi cadastrada.') self.logger.error("Essa numeração (materia={}, tipo_materia={}, ano_materia={}, numero_materia={}) " - "já foi cadastrada.".format(self.instance.materia, self.cleaned_data['tipo_materia'], - self.cleaned_data['ano_materia'], self.cleaned_data['numero_materia'])) + "já foi cadastrada.".format(self.instance.materia, self.cleaned_data['tipo_materia'], + self.cleaned_data['ano_materia'], self.cleaned_data['numero_materia'])) raise ValidationError(msg) return self.cleaned_data @@ -716,7 +721,7 @@ class AnexadaForm(ModelForm): try: self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})." - .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) materia_anexada = MateriaLegislativa.objects.get( numero=cleaned_data['numero'], ano=cleaned_data['ano'], @@ -725,7 +730,7 @@ class AnexadaForm(ModelForm): msg = _('A MateriaLegislativa a ser anexada (numero={}, ano={}, tipo={}) não existe no cadastro' ' de matérias legislativas.'.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) self.logger.error("A matéria a ser anexada não existe no cadastro" - " de matérias legislativas.") + " de matérias legislativas.") raise ValidationError(msg) materia_principal = self.instance.materia_principal @@ -971,7 +976,8 @@ class AutoriaForm(ModelForm): if ((not pk and autorias.exists()) or (pk and autorias.exclude(pk=pk).exists())): - self.logger.error("Esse Autor (pk={}) já foi cadastrado.".format(pk)) + self.logger.error( + "Esse Autor (pk={}) já foi cadastrado.".format(pk)) raise ValidationError(_('Esse Autor já foi cadastrado.')) return cd @@ -1022,7 +1028,8 @@ class AutoriaMultiCreateForm(Form): del self.errors['autores'] if 'autor' not in cd or not cd['autor'].exists(): - self.logger.error("Ao menos um autor deve ser selecionado para inclusão") + self.logger.error( + "Ao menos um autor deve ser selecionado para inclusão") raise ValidationError( _('Ao menos um autor deve ser selecionado para inclusão')) @@ -1204,7 +1211,7 @@ class TipoProposicaoForm(ModelForm): if not content_type.model_class().objects.filter( pk=cd['tipo_conteudo_related']).exists(): self.logger.error("O Registro definido (%s) não está na base de %s." - % (cd['tipo_conteudo_related'], content_type)) + % (cd['tipo_conteudo_related'], content_type)) raise ValidationError( _('O Registro definido (%s) não está na base de %s.' ) % (cd['tipo_conteudo_related'], content_type)) @@ -1377,11 +1384,11 @@ class ProposicaoForm(forms.ModelForm): 'texto_original', 7 if self.texto_articulado_proposicao else 12))) fields.append(to_column((Fieldset(_('Outras informações - Vincular a Matéria Legislativa Existente'), - to_column(('tipo_materia', 12)), - to_column(('numero_materia', 6)), - to_column(('ano_materia', 6)) - ), 12)), - ) + to_column(('tipo_materia', 12)), + to_column(('numero_materia', 6)), + to_column(('ano_materia', 6)) + ), 12)), + ) self.helper = FormHelper() self.helper.layout = SaplFormLayout(*fields) @@ -1410,9 +1417,10 @@ class ProposicaoForm(forms.ModelForm): texto_original = self.cleaned_data.get('texto_original', False) if texto_original and texto_original.size > MAX_DOC_UPLOAD_SIZE: max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) - self.logger.error("- Arquivo muito grande. ( > {0}MB )".format(max_size)) + self.logger.error( + "- Arquivo muito grande. ( > {0}MB )".format(max_size)) raise ValidationError( - "Arquivo muito grande. ( > {0}MB )".format(max_size)) + "Arquivo muito grande. ( > {0}MB )".format(max_size)) return texto_original def gerar_hash(self, inst, receber_recibo): @@ -1443,7 +1451,7 @@ class ProposicaoForm(forms.ModelForm): if tm and am and nm: try: self.logger.debug("Tentando obter objeto MateriaLegislativa (tipo_id={}, ano={}, numero={})." - .format(tm, am, nm)) + .format(tm, am, nm)) materia_de_vinculo = MateriaLegislativa.objects.get( tipo_id=tm, ano=am, @@ -1451,11 +1459,11 @@ class ProposicaoForm(forms.ModelForm): ) except ObjectDoesNotExist: self.logger.error("Objeto MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) não existe!" - .format(tm, am, nm)) + .format(tm, am, nm)) raise ValidationError(_('Matéria Vinculada não existe!')) else: self.logger.info("MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) com sucesso." - .format(tm, am, nm)) + .format(tm, am, nm)) cd['materia_de_vinculo'] = materia_de_vinculo return cd @@ -1479,7 +1487,6 @@ class ProposicaoForm(forms.ModelForm): inst.texto_original.delete() self.gerar_hash(inst, receber_recibo) - return super().save(commit) inst.ano = timezone.now().year @@ -1732,8 +1739,8 @@ class ConfirmarProposicaoForm(ProposicaoForm): if not numeracao: self.logger.error("A sequência de numeração (por ano ou geral)" - " não foi configurada para a aplicação em " - "tabelas auxiliares") + " não foi configurada para a aplicação em " + "tabelas auxiliares") raise ValidationError("A sequência de numeração (por ano ou geral)" " não foi configurada para a aplicação em " "tabelas auxiliares") @@ -1751,7 +1758,7 @@ class ConfirmarProposicaoForm(ProposicaoForm): elif self.instance.tipo.content_type.model_class( ) == TipoDocumento and not cd['materia_de_vinculo']: self.logger.error("Documentos não podem ser incorporados sem definir " - "para qual Matéria Legislativa ele se destina.") + "para qual Matéria Legislativa ele se destina.") raise ValidationError( _('Documentos não podem ser incorporados sem definir ' 'para qual Matéria Legislativa ele se destina.')) @@ -1803,7 +1810,8 @@ class ConfirmarProposicaoForm(ProposicaoForm): numeracao = None try: - self.logger.debug("Tentando obter modelo de sequência de numeração.") + self.logger.debug( + "Tentando obter modelo de sequência de numeração.") numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao except AttributeError as e: @@ -1829,12 +1837,14 @@ class ConfirmarProposicaoForm(ProposicaoForm): tipo=tipo).aggregate( Max('numero')) elif numeracao == 'U': - numero = MateriaLegislativa.objects.filter(tipo=tipo).aggregate(Max('numero')) + numero = MateriaLegislativa.objects.filter( + tipo=tipo).aggregate(Max('numero')) if numeracao is None: numero['numero__max'] = 0 - max_numero = numero['numero__max'] + 1 if numero['numero__max'] else 1 + max_numero = numero['numero__max'] + \ + 1 if numero['numero__max'] else 1 # dados básicos materia = MateriaLegislativa() @@ -1974,7 +1984,8 @@ class ConfirmarProposicaoForm(ProposicaoForm): protocolo.tipo_protocolo = '1' - protocolo.interessado = str(proposicao.autor)[:200] # tamanho máximo 200 + protocolo.interessado = str(proposicao.autor)[ + :200] # tamanho máximo 200 protocolo.autor = proposicao.autor protocolo.assunto_ementa = proposicao.descricao protocolo.numero_paginas = cd['numero_de_paginas'] @@ -2083,7 +2094,7 @@ class EtiquetaPesquisaForm(forms.Form): if (not cleaned_data['data_inicial'] or not cleaned_data['data_final']): self.logger.error("Caso pesquise por data, os campos de Data Incial e " - "Data Final devem ser preenchidos obrigatoriamente") + "Data Final devem ser preenchidos obrigatoriamente") raise ValidationError(_( 'Caso pesquise por data, os campos de Data Incial e ' + 'Data Final devem ser preenchidos obrigatoriamente')) @@ -2091,7 +2102,7 @@ class EtiquetaPesquisaForm(forms.Form): # a inicial elif 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'])) + .format(cleaned_data['data_final'], cleaned_data['data_inicial'])) raise ValidationError(_( 'A Data Final não pode ser menor que a Data Inicial')) @@ -2200,22 +2211,22 @@ class ExcluirTramitacaoEmLote(forms.Form): logger = logging.getLogger(__name__) data_tramitacao = forms.DateField(required=True, - label=_('Data da Tramitação')) + label=_('Data da Tramitação')) unidade_tramitacao_local = forms.ModelChoiceField(label=_('Unidade Local'), - required=True, - queryset=UnidadeTramitacao.objects.all(), - empty_label='------') + required=True, + queryset=UnidadeTramitacao.objects.all(), + empty_label='------') unidade_tramitacao_destino = forms.ModelChoiceField(label=_('Unidade Destino'), - required=True, - queryset=UnidadeTramitacao.objects.all(), - empty_label='------') + required=True, + queryset=UnidadeTramitacao.objects.all(), + empty_label='------') status = forms.ModelChoiceField(label=_('Status'), - required=True, - queryset=StatusTramitacao.objects.all(), - empty_label='------') + required=True, + queryset=StatusTramitacao.objects.all(), + empty_label='------') def clean(self): super(ExcluirTramitacaoEmLote, self).clean() @@ -2231,15 +2242,15 @@ class ExcluirTramitacaoEmLote(forms.Form): status = cleaned_data['status'] tramitacao_set = Tramitacao.objects.filter(data_tramitacao=data_tramitacao, - unidade_tramitacao_local=unidade_tramitacao_local, - unidade_tramitacao_destino=unidade_tramitacao_destino, - status=status) + unidade_tramitacao_local=unidade_tramitacao_local, + unidade_tramitacao_destino=unidade_tramitacao_destino, + status=status) if not tramitacao_set.exists(): self.logger.error("Não existem tramitações com os dados informados " " (data_tramitacao={}, unidade_tramitacao_local={})." "unidade_tramitacao_destino={}, status={})." .format(data_tramitacao, unidade_tramitacao_local, - unidade_tramitacao_destino, status)) + unidade_tramitacao_destino, status)) raise forms.ValidationError( _("Não existem tramitações com os dados informados.")) @@ -2250,7 +2261,7 @@ class ExcluirTramitacaoEmLote(forms.Form): row1 = to_row( [('data_tramitacao', 6), - ('status', 6),]) + ('status', 6), ]) row2 = to_row( [('unidade_tramitacao_local', 6), ('unidade_tramitacao_destino', 6)]) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 7cd8368f7..3429e1267 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -1,6 +1,6 @@ -import django_filters import logging + from crispy_forms.helper import FormHelper from crispy_forms.layout import Fieldset, Layout from django import forms @@ -9,6 +9,7 @@ from django.db import models from django.forms import ModelForm, widgets, ModelChoiceField from django.utils import timezone 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 @@ -73,7 +74,7 @@ class NormaFilterSet(django_filters.FilterSet): row2 = to_row([('data', 6), ('data_publicacao', 6)]) row3 = to_row([('ementa', 6), ('assuntos', 6)]) row4 = to_row([('data_vigencia', 12)]) - row5 = to_row([('o',6), ('indexacao', 6)]) + row5 = to_row([('o', 6), ('indexacao', 6)]) self.form.helper = FormHelper() self.form.helper.form_method = 'GET' @@ -131,9 +132,8 @@ class NormaJuridicaForm(ModelForm): 'assuntos'] widgets = {'assuntos': widgets.CheckboxSelectMultiple} - def clean(self): - + cleaned_data = super(NormaJuridicaForm, self).clean() if not self.is_valid(): @@ -142,8 +142,10 @@ class NormaJuridicaForm(ModelForm): import re has_digits = re.sub('[^0-9]', '', cleaned_data['numero']) if not has_digits: - self.logger.error("Número de norma ({}) não pode conter somente letras.".format(cleaned_data['numero'])) - raise ValidationError('Número de norma não pode conter somente letras') + self.logger.error("Número de norma ({}) não pode conter somente letras.".format( + cleaned_data['numero'])) + raise ValidationError( + 'Número de norma não pode conter somente letras') if self.instance.numero != cleaned_data['numero']: norma = NormaJuridica.objects.filter(ano=cleaned_data['ano'], @@ -157,7 +159,7 @@ class NormaJuridicaForm(ModelForm): "e Número no sistema") if (cleaned_data['tipo_materia'] and cleaned_data['numero_materia'] and - cleaned_data['ano_materia']): + cleaned_data['ano_materia']): try: self.logger.debug("Tentando obter objeto MateriaLegislativa com tipo={}, numero={}, ano={}." .format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia'])) @@ -168,9 +170,9 @@ class NormaJuridicaForm(ModelForm): except ObjectDoesNotExist: self.logger.error("Matéria Legislativa %s/%s (%s) é inexistente." % ( - self.cleaned_data['numero_materia'], - self.cleaned_data['ano_materia'], - cleaned_data['tipo_materia'].descricao)) + self.cleaned_data['numero_materia'], + self.cleaned_data['ano_materia'], + cleaned_data['tipo_materia'].descricao)) raise forms.ValidationError( _("Matéria Legislativa %s/%s (%s) é inexistente." % ( self.cleaned_data['numero_materia'], @@ -178,7 +180,7 @@ class NormaJuridicaForm(ModelForm): cleaned_data['tipo_materia'].descricao))) else: self.logger.info("MateriaLegislativa com tipo={}, numero={}, ano={} obtida com sucesso." - .format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia'])) + .format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia'])) cleaned_data['materia'] = materia else: @@ -198,10 +200,11 @@ class NormaJuridicaForm(ModelForm): texto_integral = self.cleaned_data.get('texto_integral', False) if texto_integral and texto_integral.size > MAX_DOC_UPLOAD_SIZE: max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) - tam_fornecido = str( texto_integral.size / (1024*1024) ) - self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format(tam_fornecido, max_size)) + tam_fornecido = str(texto_integral.size / (1024 * 1024)) + self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format( + tam_fornecido, max_size)) raise ValidationError( - "Arquivo muito grande. ( > {0}MB )".format(max_size)) + "Arquivo muito grande. ( > {0}MB )".format(max_size)) return texto_integral def save(self, commit=False): @@ -256,11 +259,13 @@ class AutoriaNormaForm(ModelForm): if ((not pk and autorias.exists()) or (pk and autorias.exclude(pk=pk).exists())): - self.logger.error("Autor ({}) já foi cadastrado.".format(cd['autor'])) + self.logger.error( + "Autor ({}) já foi cadastrado.".format(cd['autor'])) raise ValidationError(_('Esse Autor já foi cadastrado.')) return cd + class AnexoNormaJuridicaForm(ModelForm): class Meta: model = AnexoNormaJuridica @@ -270,6 +275,7 @@ class AnexoNormaJuridicaForm(ModelForm): } logger = logging.getLogger(__name__) + def clean(self): cleaned_data = super(AnexoNormaJuridicaForm, self).clean() if not self.is_valid(): @@ -277,10 +283,11 @@ class AnexoNormaJuridicaForm(ModelForm): anexo_arquivo = self.cleaned_data.get('anexo_arquivo', False) if anexo_arquivo and anexo_arquivo.size > MAX_DOC_UPLOAD_SIZE: max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024)) - tam_fornecido = str( anexo_arquivo.size / (1024*1024) ) - self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format(tam_fornecido, max_size)) + tam_fornecido = str(anexo_arquivo.size / (1024 * 1024)) + self.logger.error("Arquivo muito grande ({}MB). ( Tamanho máximo permitido: {}MB )".format( + tam_fornecido, max_size)) raise ValidationError( - "Arquivo muito grande. ( > {0}MB )".format(max_size)) + "Arquivo muito grande. ( > {0}MB )".format(max_size)) return cleaned_data def save(self, commit=False): @@ -294,7 +301,6 @@ class AnexoNormaJuridicaForm(ModelForm): return anexo - class NormaRelacionadaForm(ModelForm): tipo = forms.ModelChoiceField( @@ -310,6 +316,7 @@ class NormaRelacionadaForm(ModelForm): widget=forms.Textarea(attrs={'disabled': 'disabled'})) logger = logging.getLogger(__name__) + class Meta: model = NormaRelacionada fields = ['tipo', 'numero', 'ano', 'ementa', 'tipo_vinculo'] @@ -325,17 +332,20 @@ class NormaRelacionadaForm(ModelForm): cleaned_data = self.cleaned_data try: - self.logger.debug("Tentando obter objeto NormaJuridica com numero={}, ano={}, tipo={}.".format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + self.logger.debug("Tentando obter objeto NormaJuridica com numero={}, ano={}, tipo={}.".format( + cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) norma_relacionada = NormaJuridica.objects.get( numero=cleaned_data['numero'], ano=cleaned_data['ano'], tipo=cleaned_data['tipo']) except ObjectDoesNotExist: - self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} não existe.".format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} não existe.".format( + cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) msg = _('A norma a ser relacionada não existe.') raise ValidationError(msg) else: - self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} obtida com sucesso.".format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) + self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} obtida com sucesso.".format( + cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) cleaned_data['norma_relacionada'] = norma_relacionada return cleaned_data @@ -408,7 +418,8 @@ class NormaPesquisaSimplesForm(forms.Form): if (data_inicial and data_final and data_inicial > data_final): - self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(data_final, data_inicial)) + self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format( + data_final, data_inicial)) raise ValidationError(_( 'A Data Final não pode ser menor que a Data Inicial')) else: @@ -416,7 +427,7 @@ class NormaPesquisaSimplesForm(forms.Form): condicao2 = not data_inicial and data_final if condicao1 or condicao2: self.logger.error("Caso pesquise por data, os campos de Data Inicial e " - "Data Final devem ser preenchidos obrigatoriamente") + "Data Final devem ser preenchidos obrigatoriamente") raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e ' + 'Data Final devem ser preenchidos obrigatoriamente')) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 97cab4eee..bd017fc8e 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -1,6 +1,6 @@ -import django_filters import logging + from crispy_forms.bootstrap import InlineRadios from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout @@ -12,6 +12,7 @@ from django.db.models import Max from django.forms import ModelForm from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +import django_filters from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row @@ -25,8 +26,11 @@ from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, Protocolo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) -TIPOS_PROTOCOLO = [('0', 'Recebido'), ('1', 'Enviado'), ('2', 'Interno'), ('', '---------')] -TIPOS_PROTOCOLO_CREATE = [('0', 'Recebido'), ('1', 'Enviado'), ('2', 'Interno')] + +TIPOS_PROTOCOLO = [('0', 'Recebido'), ('1', 'Enviado'), + ('2', 'Interno'), ('', '---------')] +TIPOS_PROTOCOLO_CREATE = [ + ('0', 'Recebido'), ('1', 'Enviado'), ('2', 'Interno')] NATUREZA_PROCESSO = [('', '---------'), ('0', 'Administrativo'), @@ -41,6 +45,7 @@ EM_TRAMITACAO = [('', '---------'), (0, 'Sim'), (1, 'Não')] + class AcompanhamentoDocumentoForm(ModelForm): class Meta: @@ -253,10 +258,12 @@ class AnularProcoloAdmForm(ModelForm): ano = cleaned_data['ano'] try: - self.logger.debug("Tentando obter Protocolo com numero={} e ano={}.".format(numero, ano)) + self.logger.debug( + "Tentando obter Protocolo com numero={} e ano={}.".format(numero, ano)) protocolo = Protocolo.objects.get(numero=numero, ano=ano) if protocolo.anulado: - self.logger.error("Protocolo %s/%s já encontra-se anulado" % (numero, ano)) + self.logger.error( + "Protocolo %s/%s já encontra-se anulado" % (numero, ano)) raise forms.ValidationError( _("Protocolo %s/%s já encontra-se anulado") % (numero, ano)) @@ -341,7 +348,8 @@ class ProtocoloDocumentForm(ModelForm): observacao = forms.CharField(required=False, 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 @@ -431,7 +439,8 @@ class ProtocoloMateriaForm(ModelForm): assunto_ementa = forms.CharField(required=True, 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 @@ -450,13 +459,16 @@ class ProtocoloMateriaForm(ModelForm): def clean_autor(self): autor_field = self.cleaned_data['autor'] try: - self.logger.debug("Tentando obter Autor com id={}.".format(autor_field.id)) + self.logger.debug( + "Tentando obter Autor com id={}.".format(autor_field.id)) autor = Autor.objects.get(id=autor_field.id) except ObjectDoesNotExist: - self.logger.error("Autor com id={} não encontrado. Definido como None.".format(autor_field.id)) + self.logger.error( + "Autor com id={} não encontrado. Definido como None.".format(autor_field.id)) autor_field = None else: - self.logger.info("Autor com id={} encontrado com sucesso.".format(autor_field.id)) + self.logger.info( + "Autor com id={} encontrado com sucesso.".format(autor_field.id)) autor_field = autor return autor_field @@ -471,7 +483,8 @@ class ProtocoloMateriaForm(ModelForm): if data['vincular_materia'] == 'True': try: if not data['ano_materia'] or not data['numero_materia']: - self.logger.error("Não foram informados o número ou ano da matéria a ser vinculada") + self.logger.error( + "Não foram informados o número ou ano da matéria a ser vinculada") raise ValidationError( 'Favor informar o número e ano da matéria a ser vinculada') self.logger.debug("Tentando obter MateriaLegislativa com ano={}, numero={} e data={}." @@ -481,13 +494,14 @@ class ProtocoloMateriaForm(ModelForm): tipo=data['tipo_materia']) if self.materia.numero_protocolo: self.logger.error("MateriaLegislativa informada já possui o protocolo {}/{} vinculado." - .format(self.materia.numero_protocolo, self.materia.ano)) + .format(self.materia.numero_protocolo, self.materia.ano)) raise ValidationError(_('Matéria Legislativa informada já possui o protocolo {}/{} vinculado.' .format(self.materia.numero_protocolo, self.materia.ano))) except ObjectDoesNotExist: self.logger.error("MateriaLegislativa informada (ano={}, numero={} e data={}) não existente." .format(data['ano_materia'], data['numero_materia'], data['tipo_materia'])) - raise ValidationError(_('Matéria Legislativa informada não existente.')) + raise ValidationError( + _('Matéria Legislativa informada não existente.')) return data @@ -520,9 +534,9 @@ class ProtocoloMateriaForm(ModelForm): ), Fieldset(_('Número do Protocolo (Apenas se quiser que a numeração comece' ' a partir do número a ser informado)'), - row5, - HTML(" "), - form_actions(label=_('Protocolar Matéria'))) + row5, + HTML(" "), + form_actions(label=_('Protocolar Matéria'))) ) super(ProtocoloMateriaForm, self).__init__( @@ -703,9 +717,9 @@ class DocumentoAdministrativoForm(ModelForm): get_field('numero').verbose_name) restrito = forms.ChoiceField(label=_('Acesso Restrito'), - widget=forms.RadioSelect(), - choices=YES_NO_CHOICES, - initial=False) + widget=forms.RadioSelect(), + choices=YES_NO_CHOICES, + initial=False) class Meta: model = DocumentoAdministrativo @@ -746,8 +760,8 @@ class DocumentoAdministrativoForm(ModelForm): # não permite atualizar para numero/ano/tipo existente if self.instance.pk: mudanca_doc = numero_documento != self.instance.numero \ - or ano_documento != self.instance.ano \ - or tipo_documento != self.instance.tipo.pk + or ano_documento != self.instance.ano \ + or tipo_documento != self.instance.tipo.pk if not self.instance.pk or mudanca_doc: doc_exists = DocumentoAdministrativo.objects.filter(numero=numero_documento, @@ -773,7 +787,8 @@ class DocumentoAdministrativoForm(ModelForm): numero_protocolo, ano_protocolo)) raise ValidationError(msg) except MultipleObjectsReturned: - self.logger.error("Existe mais de um Protocolo com este ano ({}) e número ({}).".format(ano_protocolo,numero_protocolo)) + self.logger.error("Existe mais de um Protocolo com este ano ({}) e número ({}).".format( + ano_protocolo, numero_protocolo)) msg = _( 'Existe mais de um Protocolo com este ano e número.' % ( numero_protocolo, ano_protocolo)) @@ -784,12 +799,12 @@ class DocumentoAdministrativoForm(ModelForm): if str(protocolo_antigo) != numero_protocolo: exist_materia = MateriaLegislativa.objects.filter( - numero_protocolo=numero_protocolo, - ano=ano_protocolo).exists() + numero_protocolo=numero_protocolo, + ano=ano_protocolo).exists() exist_doc = DocumentoAdministrativo.objects.filter( - protocolo__numero=numero_protocolo, - protocolo__ano=ano_protocolo).exists() + protocolo__numero=numero_protocolo, + protocolo__ano=ano_protocolo).exists() if exist_materia or exist_doc: self.logger.error('Protocolo com numero=%s e ano=%s já possui' ' documento vinculado' % (numero_protocolo, ano_protocolo)) @@ -871,13 +886,16 @@ class DesvincularDocumentoForm(ModelForm): try: self.logger.debug("Tentando obter DocumentoAdministrativo com numero={}, ano={} e tipo={}." .format(numero, ano, tipo)) - documento = DocumentoAdministrativo.objects.get(numero=numero, ano=ano, tipo=tipo) + documento = DocumentoAdministrativo.objects.get( + numero=numero, ano=ano, tipo=tipo) if not documento.protocolo: - self.logger.error("DocumentoAdministrativo %s %s/%s não se encontra vinculado a nenhum protocolo." % (tipo, numero, ano)) + self.logger.error( + "DocumentoAdministrativo %s %s/%s não se encontra vinculado a nenhum protocolo." % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não se encontra vinculado a nenhum protocolo" % (tipo, numero, ano))) except ObjectDoesNotExist: - self.logger.error("DocumentoAdministrativo %s %s/%s não existe" % (tipo, numero, ano)) + self.logger.error( + "DocumentoAdministrativo %s %s/%s não existe" % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não existe" % (tipo, numero, ano))) @@ -939,13 +957,16 @@ class DesvincularMateriaForm(forms.Form): try: self.logger.info("Tentando obter MateriaLegislativa com numero={}, ano={} e tipo={}." .format(numero, ano, tipo)) - materia = MateriaLegislativa.objects.get(numero=numero, ano=ano, tipo=tipo) + materia = MateriaLegislativa.objects.get( + numero=numero, ano=ano, tipo=tipo) if not materia.numero_protocolo: - self.logger.error("MateriaLegislativa %s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano)) + self.logger.error( + "MateriaLegislativa %s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano))) except ObjectDoesNotExist: - self.logger.error("MateriaLegislativa %s %s/%s não existe" % (tipo, numero, ano)) + self.logger.error( + "MateriaLegislativa %s %s/%s não existe" % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não existe" % (tipo, numero, ano))) @@ -999,6 +1020,7 @@ def filtra_tramitacao_adm_destino_and_status(status, destino): unidade_tramitacao_destino=destino).distinct().values_list( 'documento_id', flat=True) + class FichaPesquisaAdmForm(forms.Form): logger = logging.getLogger(__name__) @@ -1074,4 +1096,4 @@ class FichaSelecionaAdmForm(forms.Form): row1, form_actions(label='Gerar Impresso') ) - ) \ No newline at end of file + ) diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 87f7b9c47..e508a0608 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -1,9 +1,9 @@ -from django.contrib import messages from datetime import datetime from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Button, Fieldset, Layout from django import forms +from django.contrib import messages from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db import transaction @@ -23,6 +23,7 @@ from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, MateriaPesquisaOrderingFilter, autor_label, autor_modal, timezone) + from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia, Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoJustificativa, TipoResultadoVotacao, @@ -218,11 +219,11 @@ class RetiradaPautaForm(ModelForm): def __init__(self, *args, **kwargs): row1 = to_row([('tipo_de_retirada', 5), - ('parlamentar', 4), - ('data', 3)]) + ('parlamentar', 4), + ('data', 3)]) row2 = to_row([('ordem', 6), - ('expediente', 6)]) - row3 = to_row([('observacao',12)]) + ('expediente', 6)]) + row3 = to_row([('observacao', 12)]) self.helper = FormHelper() self.helper.layout = SaplFormLayout( @@ -232,8 +233,10 @@ class RetiradaPautaForm(ModelForm): q = Q(sessao_plenaria=kwargs['initial']['sessao_plenaria']) ordens = OrdemDia.objects.filter(q) expedientes = ExpedienteMateria.objects.filter(q) - retiradas_ordem = [r.ordem for r in RetiradaPauta.objects.filter(q, ordem__in=ordens)] - retiradas_expediente = [r.expediente for r in RetiradaPauta.objects.filter(q, expediente__in=expedientes)] + retiradas_ordem = [ + r.ordem for r in RetiradaPauta.objects.filter(q, ordem__in=ordens)] + retiradas_expediente = [r.expediente for r in RetiradaPauta.objects.filter( + q, expediente__in=expedientes)] setOrdem = set(ordens) - set(retiradas_ordem) setExpediente = set(expedientes) - set(retiradas_expediente) @@ -264,19 +267,23 @@ class RetiradaPautaForm(ModelForm): sessao_plenaria = self.instance.sessao_plenaria if self.cleaned_data['data'] < sessao_plenaria.data_inicio: - raise ValidationError(_("Data de retirada de pauta anterior à abertura da Sessão.")) + raise ValidationError( + _("Data de retirada de pauta anterior à abertura da Sessão.")) if sessao_plenaria.data_fim and self.cleaned_data['data'] > sessao_plenaria.data_fim: - raise ValidationError(_("Data de retirada de pauta posterior ao encerramento da Sessão.")) + raise ValidationError( + _("Data de retirada de pauta posterior ao encerramento da Sessão.")) if self.cleaned_data['ordem'] and self.cleaned_data['ordem'].registrovotacao_set.exists(): - raise ValidationError(_("Essa matéria já foi votada, portanto não pode ser retirada de pauta.")) + raise ValidationError( + _("Essa matéria já foi votada, portanto não pode ser retirada de pauta.")) elif self.cleaned_data['expediente'] and self.cleaned_data['expediente'].registrovotacao_set.exists(): - raise ValidationError(_("Essa matéria já foi votada, portanto não pode ser retirada de pauta.")) + raise ValidationError( + _("Essa matéria já foi votada, portanto não pode ser retirada de pauta.")) return self.cleaned_data def save(self, commit=False): - retirada = super(RetiradaPautaForm, self).save(commit=False) + retirada = super(RetiradaPautaForm, self).save(commit=commit) if retirada.ordem: retirada.materia = retirada.ordem.materia elif retirada.expediente: @@ -284,6 +291,7 @@ class RetiradaPautaForm(ModelForm): retirada.save() return retirada + class BancadaForm(ModelForm): class Meta: @@ -522,10 +530,12 @@ class VotacaoForm(forms.Form): votos_sim = forms.IntegerField(label='Sim') votos_nao = forms.IntegerField(label='Não') abstencoes = forms.IntegerField(label='Abstenções') - total_presentes = forms.IntegerField(required=False, widget=forms.HiddenInput()) - voto_presidente = forms.IntegerField(label='A totalização inclui o voto do Presidente?') + total_presentes = forms.IntegerField( + required=False, widget=forms.HiddenInput()) + voto_presidente = forms.IntegerField( + label='A totalização inclui o voto do Presidente?') total_votos = forms.IntegerField(required=False, label='total') - observacao = forms.CharField(required=False , label='Observação') + observacao = forms.CharField(required=False, label='Observação') resultado_votacao = forms.CharField(label='Resultado da Votação') def clean(self): @@ -544,14 +554,15 @@ class VotacaoForm(forms.Form): qtde_presentes -= 1 if qtde_presentes and qtde_votos != qtde_presentes: - raise ValidationError('O total de votos não corresponde com a quantidade de presentes!') + raise ValidationError( + 'O total de votos não corresponde com a quantidade de presentes!') return cleaned_data # def save(self, commit=False): # #TODO Verificar se esse códido é utilizado - # votacao = super(VotacaoForm, self).save(commit) + # votacao = super(VotacaoForm, self).save(commit) # votacao.materia = self.cleaned_data['materia'] # votacao.save() # return votacao @@ -764,7 +775,7 @@ class ResumoOrdenacaoForm(forms.Form): decimo = forms.ChoiceField(label='10°', choices=ORDENACAO_RESUMO) decimo_primeiro = forms.ChoiceField(label='11°', - choices=ORDENACAO_RESUMO) + choices=ORDENACAO_RESUMO) def __init__(self, *args, **kwargs): super(ResumoOrdenacaoForm, self).__init__(*args, **kwargs) @@ -796,7 +807,7 @@ class ResumoOrdenacaoForm(forms.Form): self.helper.layout = Layout( Fieldset(_(''), row1, row2, row3, row4, row5, - row6, row7, row8, row9, row10,row11, + row6, row7, row8, row9, row10, row11, form_actions(label='Atualizar')) ) @@ -875,7 +886,6 @@ class JustificativaAusenciaForm(ModelForm): legislatura=legislatura).order_by('parlamentar__nome_parlamentar') parlamentares = [m.parlamentar for m in mandato] - super(JustificativaAusenciaForm, self).__init__( *args, **kwargs) @@ -900,7 +910,7 @@ class JustificativaAusenciaForm(ModelForm): ("0", "------------")] + [(p.id, p) for p in setFinal] def clean(self): - cleaned_data = super(JustificativaAusenciaForm, self).clean() + super(JustificativaAusenciaForm, self).clean() if not self.is_valid(): return self.cleaned_data @@ -913,7 +923,7 @@ class JustificativaAusenciaForm(ModelForm): else: return self.cleaned_data - def save(self, commit=False): + def save(self): justificativa = super().save(True) @@ -996,4 +1006,4 @@ class VotacaoEmBlocoFilterSet(MateriaLegislativaFilterSet): HTML(autor_modal), row4, row5, row6, row7, row8, row9, form_actions(label='Pesquisar')) - ) \ No newline at end of file + ) From 812a9e2ba06117e2ee373882f91eb4d71ffa0a91 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Fri, 4 Jan 2019 09:34:53 -0200 Subject: [PATCH 043/222] retira empty label duplicado de choices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a nova versão do django_filter addicionada ao sapl já gerencia os empty labels. Adicioná-los manualmente estava fazendo com os fossem duplicados. --- sapl/materia/forms.py | 6 +----- sapl/norma/forms.py | 8 ++------ sapl/protocoloadm/forms.py | 8 ++------ sapl/sessao/forms.py | 6 +++--- sapl/utils.py | 5 +++++ 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 3c2c8c36e..63941e2c4 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -51,10 +51,6 @@ from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, TipoMateriaLegislativa, Tramitacao, UnidadeTramitacao) -def ANO_CHOICES(): - return [('', '---------')] + RANGE_ANOS - - def em_tramitacao(): return [('', 'Tanto Faz'), (1, 'Sim'), @@ -764,7 +760,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano da Matéria', - choices=ANO_CHOICES) + choices=RANGE_ANOS) autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput()) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 3429e1267..bdac45d89 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -21,10 +21,6 @@ from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelac TipoNormaJuridica, AutoriaNorma) -def ANO_CHOICES(): - return [('', '---------')] + RANGE_ANOS - - def get_esferas(): return [('E', 'Estadual'), ('F', 'Federal'), @@ -44,7 +40,7 @@ class NormaFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano', - choices=ANO_CHOICES) + choices=RANGE_ANOS) ementa = django_filters.CharFilter(lookup_expr='icontains') @@ -103,7 +99,7 @@ class NormaJuridicaForm(ModelForm): ano_materia = forms.ChoiceField( label='Ano Matéria', required=False, - choices=ANO_CHOICES, + choices=RANGE_ANOS, widget=forms.Select(attrs={'autocomplete': 'off'}) ) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index bd017fc8e..76f3a4986 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -37,10 +37,6 @@ NATUREZA_PROCESSO = [('', '---------'), ('1', 'Legislativo')] -def ANO_CHOICES(): - return [('', '---------')] + RANGE_ANOS - - EM_TRAMITACAO = [('', '---------'), (0, 'Sim'), (1, 'Não')] @@ -73,7 +69,7 @@ class ProtocoloFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano', - choices=ANO_CHOICES) + choices=RANGE_ANOS) assunto_ementa = django_filters.CharFilter(lookup_expr='icontains') @@ -160,7 +156,7 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano', - choices=ANO_CHOICES) + choices=RANGE_ANOS) tramitacao = django_filters.ChoiceFilter(required=False, label='Em Tramitação?', diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index e508a0608..a09f04053 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -43,11 +43,11 @@ def recupera_anos(): def ANO_CHOICES(): - return [('', '---------')] + recupera_anos() + return recupera_anos() -MES_CHOICES = [('', '---------')] + RANGE_MESES -DIA_CHOICES = [('', '---------')] + RANGE_DIAS_MES +MES_CHOICES = RANGE_MESES +DIA_CHOICES = RANGE_DIAS_MES ORDENACAO_RESUMO = [('cont_mult', 'Conteúdo Multimídia'), diff --git a/sapl/utils.py b/sapl/utils.py index 77e1cec2d..7b00b3f9e 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -322,6 +322,11 @@ LISTA_DE_UFS = [ RANGE_ANOS = [(year, year) for year in range(timezone.now().year, 1889, -1)] + +def ANO_CHOICES(): + return [('', '---------')] + RANGE_ANOS + + RANGE_MESES = [ (1, 'Janeiro'), (2, 'Fevereiro'), From 2078b4c7e46d380f4995a087d1fe8bd0388414c0 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Fri, 4 Jan 2019 10:26:13 -0200 Subject: [PATCH 044/222] Fix #1659 --- sapl/base/forms.py | 156 ++++++++++-------- sapl/materia/forms.py | 7 +- .../migrations/0035_auto_20190104_1021.py | 35 ++++ sapl/materia/models.py | 9 +- sapl/norma/forms.py | 8 +- .../migrations/0019_auto_20190104_1021.py | 25 +++ sapl/protocoloadm/forms.py | 5 +- .../migrations/0012_auto_20190104_1021.py | 25 +++ sapl/sessao/forms.py | 26 +-- sapl/utils.py | 48 +++++- 10 files changed, 240 insertions(+), 104 deletions(-) create mode 100644 sapl/materia/migrations/0035_auto_20190104_1021.py create mode 100644 sapl/norma/migrations/0019_auto_20190104_1021.py create mode 100644 sapl/protocoloadm/migrations/0012_auto_20190104_1021.py diff --git a/sapl/base/forms.py b/sapl/base/forms.py index a82dcab53..ec1a70d61 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -1,4 +1,3 @@ -import django_filters import logging from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton @@ -14,15 +13,17 @@ from django.core.exceptions import ValidationError from django.db import models, transaction from django.db.models import Q from django.forms import Form, ModelForm -from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat +from django.utils.translation import ugettext_lazy as _ +import django_filters +from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica from sapl.base.models import Autor, TipoAutor +from sapl.comissoes.models import Reuniao, Comissao 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.materia.models import ( + MateriaLegislativa, UnidadeTramitacao, StatusTramitacao) from sapl.norma.models import (NormaJuridica) from sapl.parlamentares.models import SessaoLegislativa from sapl.sessao.models import SessaoPlenaria @@ -30,10 +31,12 @@ from sapl.settings import MAX_IMAGE_UPLOAD_SIZE from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, ChoiceWithoutValidationField, ImageThumbnailFileInput, RangeWidgetOverride, autor_label, autor_modal, - models_with_gr_for_model, qs_override_django_filter) + models_with_gr_for_model, qs_override_django_filter, + choice_anos_com_normas) from .models import AppConfig, CasaLegislativa + ACTION_CREATE_USERS_AUTOR_CHOICE = [ ('A', _('Associar um usuário existente')), ('N', _('Autor sem Usuário de Acesso ao Sapl')), @@ -84,7 +87,8 @@ class UsuarioCreateForm(ModelForm): data = self.cleaned_data if data['password1'] != data['password2']: - self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format(data['password1'], data['password2'])) + self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format( + data['password1'], data['password2'])) raise ValidationError('Senhas informadas são diferentes') return data @@ -121,8 +125,10 @@ class UsuarioEditForm(ModelForm): # ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] ROLES = [] - password1 = forms.CharField(required=False, widget=forms.PasswordInput, label='Senha') - password2 = forms.CharField(required=False, widget=forms.PasswordInput, label='Confirmar senha') + password1 = forms.CharField( + required=False, widget=forms.PasswordInput, label='Senha') + password2 = forms.CharField( + required=False, widget=forms.PasswordInput, label='Confirmar senha') user_active = forms.ChoiceField(choices=YES_NO_CHOICES, required=True, label="Usuário ativo?", initial='True') roles = forms.MultipleChoiceField( @@ -159,19 +165,22 @@ class UsuarioEditForm(ModelForm): data = self.cleaned_data if data['password1'] and data['password1'] != data['password2']: - self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format(data['password1'], data['password2'])) + self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format( + data['password1'], data['password2'])) raise ValidationError('Senhas informadas são diferentes') return data + class SessaoLegislativaForm(ModelForm): logger = logging.getLogger(__name__) + class Meta: model = SessaoLegislativa exclude = [] def clean(self): - + cleaned_data = super(SessaoLegislativaForm, self).clean() if not self.is_valid(): @@ -186,13 +195,18 @@ class SessaoLegislativaForm(ModelForm): data_fim_leg = legislatura.data_fim 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 + # 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 - segundo_caso = Q(data_inicio__lt=data_inicio, data_fim__range=(data_inicio, data_fim)) - # Caso onde a data_fim está entre o início e o fim de uma Sessão já existente - terceiro_caso = Q(data_inicio__range=(data_inicio, data_fim), data_fim__gt=data_fim) - sessoes_existentes = SessaoLegislativa.objects.filter(primeiro_caso|segundo_caso|terceiro_caso).\ + # Caso onde a data_inicio está entre o início e o fim de uma Sessão já + # existente + segundo_caso = Q(data_inicio__lt=data_inicio, + data_fim__range=(data_inicio, data_fim)) + # Caso onde a data_fim está entre o início e o fim de uma Sessão já + # existente + terceiro_caso = Q(data_inicio__range=( + data_inicio, data_fim), data_fim__gt=data_fim) + sessoes_existentes = SessaoLegislativa.objects.filter(primeiro_caso | segundo_caso | terceiro_caso).\ exclude(pk=pk) if sessoes_existentes: @@ -216,39 +230,41 @@ class SessaoLegislativaForm(ModelForm): if numero <= ult and flag_edit: self.logger.error('O número da SessaoLegislativa ({}) é menor ou igual ' - 'que o de Sessões Legislativas passadas ({})'.format(numero, ult)) + 'que o de Sessões Legislativas passadas ({})'.format(numero, ult)) 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: + data_inicio > data_fim_leg: self.logger.error('A data de início ({}) da SessaoLegislativa está compreendida ' - 'fora da data início ({}) e fim ({}) da Legislatura ' - 'selecionada'.format(data_inicio, data_inicio_leg, data_fim_leg)) + 'fora da data início ({}) e fim ({}) da Legislatura ' + 'selecionada'.format(data_inicio, data_inicio_leg, data_fim_leg)) raise ValidationError('A data de início da Sessão Legislativa deve estar compreendida ' 'entre a data início e fim da Legislatura selecionada') if data_fim > data_fim_leg or \ - data_fim < data_inicio_leg: + data_fim < data_inicio_leg: self.logger.error('A data de fim ({}) da SessaoLegislativa está compreendida ' - 'fora da data início ({}) e fim ({}) da Legislatura ' - 'selecionada.'.format(data_fim, data_inicio_leg, data_fim_leg)) + 'fora da data início ({}) e fim ({}) da Legislatura ' + 'selecionada.'.format(data_fim, data_inicio_leg, data_fim_leg)) raise ValidationError('A data de fim da Sessão Legislativa deve estar compreendida ' 'entre a data início e fim da Legislatura selecionada') if data_inicio > data_fim: - self.logger.error('Data início ({}) superior à data fim ({}).'.format(data_inicio, data_fim)) - raise ValidationError('Data início não pode ser superior à data fim') + self.logger.error( + 'Data início ({}) superior à data fim ({}).'.format(data_inicio, data_fim)) + raise ValidationError( + 'Data início não pode ser superior à data fim') data_inicio_intervalo = cleaned_data['data_inicio_intervalo'] data_fim_intervalo = cleaned_data['data_fim_intervalo'] if data_inicio_intervalo and data_fim_intervalo and \ - data_inicio_intervalo > data_fim_intervalo: - self.logger.error('Data início de intervalo ({}) superior à ' - 'data fim de intervalo ({}).'.format(data_inicio_intervalo, data_fim_intervalo)) - raise ValidationError('Data início de intervalo não pode ser ' - 'superior à data fim de intervalo') + data_inicio_intervalo > data_fim_intervalo: + self.logger.error('Data início de intervalo ({}) superior à ' + 'data fim de intervalo ({}).'.format(data_inicio_intervalo, data_fim_intervalo)) + raise ValidationError('Data início de intervalo não pode ser ' + 'superior à data fim de intervalo') if data_inicio_intervalo: if data_inicio_intervalo < data_inicio or \ @@ -256,9 +272,9 @@ class SessaoLegislativaForm(ModelForm): data_inicio_intervalo > data_fim or \ data_inicio_intervalo > data_fim_leg: self.logger.error('A data de início do intervalo ({}) não está compreendida entre ' - 'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da ' - 'própria Sessão Legislativa ({} e {}).' - .format(data_inicio_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim)) + 'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da ' + 'própria Sessão Legislativa ({} e {}).' + .format(data_inicio_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim)) 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') @@ -268,9 +284,9 @@ class SessaoLegislativaForm(ModelForm): data_fim_intervalo < data_inicio or \ data_fim_intervalo < data_inicio_leg: self.logger.error('A data de fim do intervalo ({}) não está compreendida entre ' - 'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da ' - 'própria Sessão Legislativa ({} e {}).' - .format(data_fim_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim)) + 'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da ' + 'própria Sessão Legislativa ({} e {}).' + .format(data_fim_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim)) raise ValidationError('A data de fim do intervalo deve estar compreendida entre ' 'as datas de início e fim tanto da Legislatura quanto da ' 'própria Sessão Legislativa') @@ -464,7 +480,8 @@ class AutorForm(ModelForm): def valida_igualdade(self, texto1, texto2, msg): if texto1 != texto2: - self.logger.error('Textos diferentes. ("{}" e "{}")'.format(texto1, texto2)) + self.logger.error( + 'Textos diferentes. ("{}" e "{}")'.format(texto1, texto2)) raise ValidationError(msg) return True @@ -479,7 +496,7 @@ class AutorForm(ModelForm): if 'action_user' not in cd or not cd['action_user']: self.logger.error('Não Informado se o Autor terá usuário ' - 'vinculado para acesso ao Sistema.') + 'vinculado para acesso ao Sistema.') raise ValidationError(_('Informe se o Autor terá usuário ' 'vinculado para acesso ao Sistema.')) @@ -490,9 +507,9 @@ class AutorForm(ModelForm): get_user_model().USERNAME_FIELD) != cd['username']: if 'status_user' not in cd or not cd['status_user']: self.logger.error('Foi trocado ou removido o usuário deste Autor ({}), ' - 'mas não foi informado como se deve proceder ' - 'com o usuário que está sendo desvinculado? ({})' - .format(cd['username'], get_user_model().USERNAME_FIELD)) + 'mas não foi informado como se deve proceder ' + 'com o usuário que está sendo desvinculado? ({})' + .format(cd['username'], get_user_model().USERNAME_FIELD)) raise ValidationError( _('Foi trocado ou removido o usuário deste Autor, ' 'mas não foi informado como se deve proceder ' @@ -509,7 +526,8 @@ class AutorForm(ModelForm): if cd['action_user'] == 'A': param_username = {get_user_model().USERNAME_FIELD: cd['username']} if not User.objects.filter(**param_username).exists(): - self.logger.error('Não existe usuário com username "%s". ' % cd['username']) + self.logger.error( + 'Não existe usuário com username "%s". ' % cd['username']) raise ValidationError( _('Não existe usuário com username "%s". ' 'Para utilizar esse username você deve selecionar ' @@ -524,7 +542,8 @@ class AutorForm(ModelForm): param_username = { 'user__' + get_user_model().USERNAME_FIELD: cd['username']} if qs_autor.filter(**param_username).exists(): - self.logger.error('Já existe um Autor para este usuário ({}).'.format(cd['username'])) + self.logger.error( + 'Já existe um Autor para este usuário ({}).'.format(cd['username'])) raise ValidationError( _('Já existe um Autor para este usuário.')) @@ -548,7 +567,7 @@ class AutorForm(ModelForm): else: if 'autor_related' not in cd or not cd['autor_related']: self.logger.error('Registro de %s não escolhido para ser ' - 'vinculado ao cadastro de Autor' % tipo.descricao) + 'vinculado ao cadastro de Autor' % tipo.descricao) raise ValidationError( _('Um registro de %s deve ser escolhido para ser ' 'vinculado ao cadastro de Autor') % tipo.descricao) @@ -556,7 +575,7 @@ class AutorForm(ModelForm): if not tipo.content_type.model_class().objects.filter( pk=cd['autor_related']).exists(): self.logger.error('O Registro definido (%s-%s) não está na base ' - 'de %s.' % (cd['autor_related'], cd['q'], tipo.descricao)) + 'de %s.' % (cd['autor_related'], cd['q'], tipo.descricao)) raise ValidationError( _('O Registro definido (%s-%s) não está na base de %s.' ) % (cd['autor_related'], cd['q'], tipo.descricao)) @@ -567,7 +586,7 @@ class AutorForm(ModelForm): if qs_autor_selected.exists(): autor = qs_autor_selected.first() self.logger.error('Já existe um autor Cadastrado para ' - '%s' % autor.autor_related) + '%s' % autor.autor_related) raise ValidationError( _('Já existe um autor Cadastrado para %s' ) % autor.autor_related) @@ -692,7 +711,7 @@ class RelatorioNormasMesFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, label='Ano da Norma', - choices=RANGE_ANOS) + choices=choice_anos_com_normas) class Meta: filter_overrides = {models.DateField: { @@ -703,7 +722,7 @@ class RelatorioNormasMesFilterSet(django_filters.FilterSet): }} model = NormaJuridica fields = ['ano'] - + def __init__(self, *args, **kwargs): super(RelatorioNormasMesFilterSet, self).__init__( *args, **kwargs) @@ -738,11 +757,10 @@ class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet): 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 @@ -885,7 +903,7 @@ class RelatorioReuniaoFilterSet(django_filters.FilterSet): class Meta: model = Reuniao fields = ['comissao', 'data', - 'nome','tema'] + 'nome', 'tema'] def __init__(self, *args, **kwargs): super(RelatorioReuniaoFilterSet, self).__init__( @@ -905,6 +923,7 @@ class RelatorioReuniaoFilterSet(django_filters.FilterSet): form_actions(label='Pesquisar')) ) + class RelatorioAudienciaFilterSet(django_filters.FilterSet): @property @@ -935,7 +954,6 @@ class RelatorioAudienciaFilterSet(django_filters.FilterSet): ) - class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, @@ -955,7 +973,6 @@ class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet): parent = super(RelatorioMateriasTramitacaoilterSet, self).qs return parent.distinct().order_by('-ano', 'tipo', '-numero') - class Meta: model = MateriaLegislativa fields = ['ano', 'tipo', 'tramitacao__unidade_tramitacao_destino', @@ -1143,7 +1160,6 @@ class ConfiguracoesAppForm(ModelForm): self.fields['cronometro_ordem'].widget.attrs['class'] = 'cronometro' self.fields['cronometro_consideracoes'].widget.attrs['class'] = 'cronometro' - def clean_mostrar_brasao_painel(self): mostrar_brasao_painel = self.cleaned_data.get( 'mostrar_brasao_painel', False) @@ -1155,7 +1171,7 @@ class ConfiguracoesAppForm(ModelForm): if (not bool(casa.logotipo) and mostrar_brasao_painel): self.logger.error('Não há logitipo configurado para esta ' - 'CasaLegislativa ({}).'.format(casa)) + 'CasaLegislativa ({}).'.format(casa)) raise ValidationError("Não há logitipo configurado para esta " "Casa legislativa.") @@ -1190,7 +1206,7 @@ class RecuperarSenhaForm(PasswordResetForm): if not email_existente: msg = 'Não existe nenhum usuário cadastrado com este e-mail.' self.logger.error('Não existe nenhum usuário cadastrado com este e-mail ({}).' - .format(self.data['email'])) + .format(self.data['email'])) raise ValidationError(msg) return self.cleaned_data @@ -1257,33 +1273,41 @@ class AlterarSenhaForm(Form): new_password2 = data['new_password2'] if new_password1 != new_password2: - self.logger.error("'Nova Senha' ({}) diferente de 'Confirmar Senha' ({})".format(new_password1, new_password2)) - raise ValidationError("'Nova Senha' diferente de 'Confirmar Senha'") + self.logger.error("'Nova Senha' ({}) diferente de 'Confirmar Senha' ({})".format( + new_password1, new_password2)) + raise ValidationError( + "'Nova Senha' diferente de 'Confirmar Senha'") # TODO: colocar mais regras como: tamanho mínimo, # TODO: caracteres alfanuméricos, maiúsculas (?), # TODO: senha atual igual a senha anterior, etc if len(new_password1) < 6: - self.logger.error('A senha informada ({}) não tem o mínimo de 6 caracteres.'.format(new_password1)) - raise ValidationError("A senha informada deve ter no mínimo 6 caracteres") + self.logger.error( + 'A senha informada ({}) não tem o mínimo de 6 caracteres.'.format(new_password1)) + raise ValidationError( + "A senha informada deve ter no mínimo 6 caracteres") username = data['username'] old_password = data['old_password'] user = User.objects.get(username=username) if user.is_anonymous(): - self.logger.error('Não é possível alterar senha de usuário anônimo ({}).'.format(username)) - raise ValidationError("Não é possível alterar senha de usuário anônimo") + self.logger.error( + 'Não é possível alterar senha de usuário anônimo ({}).'.format(username)) + raise ValidationError( + "Não é possível alterar senha de usuário anônimo") if not user.check_password(old_password): self.logger.error('Senha atual informada ({}) não confere ' - 'com a senha armazenada.'.format(old_password)) + 'com a senha armazenada.'.format(old_password)) raise ValidationError("Senha atual informada não confere " "com a senha armazenada") if user.check_password(new_password1): - self.logger.error('Nova senha ({}) igual à senha anterior.'.format(new_password1)) - raise ValidationError("Nova senha não pode ser igual à senha anterior") + self.logger.error( + 'Nova senha ({}) igual à senha anterior.'.format(new_password1)) + raise ValidationError( + "Nova senha não pode ser igual à senha anterior") return self.cleaned_data diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 63941e2c4..01814f723 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -40,11 +40,12 @@ from sapl.norma.models import (LegislacaoCitada, NormaJuridica, from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo from sapl.settings import MAX_DOC_UPLOAD_SIZE -from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO, +from sapl.utils import (YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO, ChoiceWithoutValidationField, MateriaPesquisaOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, gerar_hash_arquivo, - models_with_gr_for_model, qs_override_django_filter) + models_with_gr_for_model, qs_override_django_filter, + choice_anos_com_materias) from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, DocumentoAcessorio, Numeracao, Proposicao, Relatoria, @@ -760,7 +761,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano da Matéria', - choices=RANGE_ANOS) + choices=choice_anos_com_materias) autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput()) diff --git a/sapl/materia/migrations/0035_auto_20190104_1021.py b/sapl/materia/migrations/0035_auto_20190104_1021.py new file mode 100644 index 000000000..655b8c692 --- /dev/null +++ b/sapl/materia/migrations/0035_auto_20190104_1021.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-04 12:21 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0034_auto_20190101_1618'), + ] + + operations = [ + migrations.AlterField( + model_name='materialegislativa', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='materialegislativa', + name='ano_origem_externa', + field=models.PositiveSmallIntegerField(blank=True, choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], null=True, verbose_name='Ano'), + ), + migrations.AlterField( + model_name='numeracao', + name='ano_materia', + field=models.PositiveSmallIntegerField(choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='proposicao', + name='ano', + field=models.PositiveSmallIntegerField(blank=True, choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], default=None, null=True, verbose_name='Ano'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index cfcb71ffc..e48446aee 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -2,7 +2,6 @@ from django.contrib.auth.models import Group from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist,MultipleObjectsReturned from django.db import models from django.db.models.functions import Concat from django.template import defaultfilters @@ -269,9 +268,9 @@ class MateriaLegislativa(models.Model): if protocolo.timestamp: return protocolo.timestamp.date() elif protocolo.data: - return protocolo.data + return protocolo.data - return '' + return '' def delete(self, using=None, keep_parents=False): if self.texto_original: @@ -728,8 +727,8 @@ class Proposicao(models.Model): observacao = models.TextField( blank=True, verbose_name=_('Observação')) cancelado = models.BooleanField(verbose_name=_('Cancelada ?'), - choices=YES_NO_CHOICES, - default=False) + choices=YES_NO_CHOICES, + default=False) """# Ao ser recebida, irá gerar uma nova matéria ou um documento acessorio # de uma já existente diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index bdac45d89..55541b48f 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -13,9 +13,11 @@ import django_filters from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import form_actions, to_row +from sapl.materia.forms import choice_anos_com_materias from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.settings import MAX_DOC_UPLOAD_SIZE -from sapl.utils import NormaPesquisaOrderingFilter, RANGE_ANOS, RangeWidgetOverride +from sapl.utils import NormaPesquisaOrderingFilter, RangeWidgetOverride,\ + choice_anos_com_normas from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, TipoNormaJuridica, AutoriaNorma) @@ -40,7 +42,7 @@ class NormaFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano', - choices=RANGE_ANOS) + choices=choice_anos_com_normas) ementa = django_filters.CharFilter(lookup_expr='icontains') @@ -99,7 +101,7 @@ class NormaJuridicaForm(ModelForm): ano_materia = forms.ChoiceField( label='Ano Matéria', required=False, - choices=RANGE_ANOS, + choices=choice_anos_com_materias, widget=forms.Select(attrs={'autocomplete': 'off'}) ) diff --git a/sapl/norma/migrations/0019_auto_20190104_1021.py b/sapl/norma/migrations/0019_auto_20190104_1021.py new file mode 100644 index 000000000..b11fc4235 --- /dev/null +++ b/sapl/norma/migrations/0019_auto_20190104_1021.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-04 12:21 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('norma', '0018_auto_20190101_1618'), + ] + + operations = [ + migrations.AlterField( + model_name='anexonormajuridica', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='normajuridica', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + ] diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 76f3a4986..63474be8e 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -19,7 +19,8 @@ from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, - RangeWidgetOverride, autor_label, autor_modal) + RangeWidgetOverride, autor_label, autor_modal, + choice_anos_com_protocolo) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, @@ -69,7 +70,7 @@ class ProtocoloFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=False, label='Ano', - choices=RANGE_ANOS) + choices=choice_anos_com_protocolo) assunto_ementa = django_filters.CharFilter(lookup_expr='icontains') diff --git a/sapl/protocoloadm/migrations/0012_auto_20190104_1021.py b/sapl/protocoloadm/migrations/0012_auto_20190104_1021.py new file mode 100644 index 000000000..356b578a8 --- /dev/null +++ b/sapl/protocoloadm/migrations/0012_auto_20190104_1021.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-04 12:21 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0011_auto_20190101_1618'), + ] + + operations = [ + migrations.AlterField( + model_name='documentoadministrativo', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano'), + ), + migrations.AlterField( + model_name='protocolo', + name='ano', + field=models.PositiveSmallIntegerField(choices=[(2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], verbose_name='Ano do Protocolo'), + ), + ] diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index a09f04053..35d49e277 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -22,7 +22,7 @@ from sapl.materia.models import (MateriaLegislativa, StatusTramitacao, from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, MateriaPesquisaOrderingFilter, autor_label, - autor_modal, timezone) + autor_modal, timezone, choice_anos_com_sessaoplenaria) from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia, Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, @@ -30,22 +30,6 @@ from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia, OcorrenciaSessao, RegistroVotacao, RetiradaPauta, TipoRetiradaPauta) -def recupera_anos(): - try: - anos_list = SessaoPlenaria.objects.all().dates('data_inicio', 'year') - # a listagem deve ser em ordem descrescente, mas por algum motivo - # a adicao de .order_by acima depois do all() nao surte efeito - # apos a adicao do .dates(), por isso o reversed() abaixo - anos = [(k.year, k.year) for k in reversed(anos_list)] - return anos - except Exception: - return [] - - -def ANO_CHOICES(): - return recupera_anos() - - MES_CHOICES = RANGE_MESES DIA_CHOICES = RANGE_DIAS_MES @@ -580,9 +564,11 @@ class VotacaoEditForm(forms.Form): class SessaoPlenariaFilterSet(django_filters.FilterSet): - data_inicio__year = django_filters.ChoiceFilter(required=False, - label='Ano', - choices=ANO_CHOICES) + data_inicio__year = django_filters.ChoiceFilter( + required=False, + label='Ano', + choices=choice_anos_com_sessaoplenaria + ) data_inicio__month = django_filters.ChoiceFilter(required=False, label='Mês', choices=MES_CHOICES) diff --git a/sapl/utils.py b/sapl/utils.py index 7b00b3f9e..5dabd2cf6 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -319,14 +319,10 @@ LISTA_DE_UFS = [ ('EX', 'Exterior'), ] -RANGE_ANOS = [(year, year) for year in range(timezone.now().year, +RANGE_ANOS = [(year, year) for year in range(timezone.now().year + 1, 1889, -1)] -def ANO_CHOICES(): - return [('', '---------')] + RANGE_ANOS - - RANGE_MESES = [ (1, 'Janeiro'), (2, 'Fevereiro'), @@ -344,6 +340,48 @@ RANGE_MESES = [ RANGE_DIAS_MES = [(n, n) for n in range(1, 32)] + +def ANO_CHOICES(): + return [('', '---------')] + RANGE_ANOS + + +def choice_anos(model): + try: + anos_list = model.objects.all().distinct( + 'ano').order_by('-ano').values_list('ano', 'ano') + return anos_list + except Exception: + return [] + + +def choice_anos_com_materias(): + from sapl.materia.models import MateriaLegislativa + return choice_anos(MateriaLegislativa) + + +def choice_anos_com_normas(): + from sapl.norma.models import NormaJuridica + return choice_anos(NormaJuridica) + + +def choice_anos_com_protocolo(): + from sapl.protocoloadm.models import Protocolo + return choice_anos(Protocolo) + + +def choice_anos_com_sessaoplenaria(): + try: + from sapl.sessao.models import SessaoPlenaria + anos_list = SessaoPlenaria.objects.all().dates('data_inicio', 'year') + # a listagem deve ser em ordem descrescente, mas por algum motivo + # a adicao de .order_by acima depois do all() nao surte efeito + # apos a adicao do .dates(), por isso o reversed() abaixo + anos = [(k.year, k.year) for k in reversed(anos_list)] + return anos + except Exception: + return [] + + TIPOS_TEXTO_PERMITIDOS = ( 'application/vnd.oasis.opendocument.text', 'application/x-vnd.oasis.opendocument.text', From dcb45e8909c48a662ccd4c8d4d72076bd9bc6d49 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Fri, 4 Jan 2019 10:41:33 -0200 Subject: [PATCH 045/222] =?UTF-8?q?ajusta=20choice=5Fanos=20em=20relat?= =?UTF-8?q?=C3=B3rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/forms.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index ec1a70d61..5aa3315fb 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -32,7 +32,7 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, ChoiceWithoutValidationField, ImageThumbnailFileInput, RangeWidgetOverride, autor_label, autor_modal, models_with_gr_for_model, qs_override_django_filter, - choice_anos_com_normas) + choice_anos_com_normas, choice_anos_com_materias) from .models import AppConfig, CasaLegislativa @@ -749,7 +749,7 @@ class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, label='Ano da Norma', - choices=RANGE_ANOS) + choices=choice_anos_com_normas) vigencia = forms.ChoiceField( label=_('Vigência'), @@ -958,7 +958,7 @@ class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, label='Ano da Matéria', - choices=RANGE_ANOS) + choices=choice_anos_com_materias) tramitacao__unidade_tramitacao_destino = django_filters.ModelChoiceFilter( queryset=UnidadeTramitacao.objects.all(), @@ -1002,7 +1002,7 @@ class RelatorioMateriasPorAnoAutorTipoFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, label='Ano da Matéria', - choices=RANGE_ANOS) + choices=choice_anos_com_materias) class Meta: model = MateriaLegislativa From f204483ad13c1bfe1ab171aee71984c0f9716420 Mon Sep 17 00:00:00 2001 From: Edward de Oliveira Date: Fri, 4 Jan 2019 22:33:38 -0200 Subject: [PATCH 046/222] HOT-FIX: disable haystack signal by default --- sapl/settings.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sapl/settings.py b/sapl/settings.py index dba421f72..80bf18273 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -100,8 +100,7 @@ INSTALLED_APPS = ( # FTS = Full Text Search # Desabilita a indexação textual até encontramos uma solução para a issue # https://github.com/interlegis/sapl/issues/2055 -#HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' # Disable auto index -HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' # Disable auto index SEARCH_BACKEND = 'haystack.backends.whoosh_backend.WhooshEngine' SEARCH_URL = ('PATH', PROJECT_DIR.child('whoosh')) @@ -111,10 +110,10 @@ SOLR_URL = config('SOLR_URL', cast=str, default='http://localhost:8983') SOLR_COLLECTION = config('SOLR_COLLECTION', cast=str, default='sapl') if USE_SOLR: + HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' #enable auto-index SEARCH_BACKEND = 'haystack.backends.solr_backend.SolrEngine' SEARCH_URL = ('URL', '{}/solr/{}'.format(SOLR_URL, SOLR_COLLECTION)) - # BATCH_SIZE: default is 1000 if omitted, avoid Too Large Entity Body errors HAYSTACK_CONNECTIONS = { 'default': { From 10fd2cc57ebb0db9f8bdb7b2cf7721e00043673d Mon Sep 17 00:00:00 2001 From: Edward de Oliveira Date: Fri, 4 Jan 2019 22:38:52 -0200 Subject: [PATCH 047/222] Revert "HOT-FIX: bump python version for TravisCI" This reverts commit bf45e90eb5118130025be76d6fd00300a2554dd9. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9f1c2e55d..f54ee6d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: - - 3.7 + - 3.5 services: - postgresql From ebce6a1647216fec36bed5262006585012091e0e Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 00:03:25 -0200 Subject: [PATCH 048/222] HOT-FIX: converte queryset para list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no caso da criação de um banco novo, os models ainda não existem no banco e não é possivel fazer a consulta que é feita ao subir o código do sapl pelo proprio migrate. --- sapl/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/utils.py b/sapl/utils.py index 5dabd2cf6..c812fdcb9 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -349,7 +349,7 @@ def choice_anos(model): try: anos_list = model.objects.all().distinct( 'ano').order_by('-ano').values_list('ano', 'ano') - return anos_list + return list(anos_list) except Exception: return [] From 912683f24409574dc111dc9396adfbd2a6f6a136 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 00:34:42 -0200 Subject: [PATCH 049/222] =?UTF-8?q?HOT-FIX:=20corrige=20testes=20em=20mat?= =?UTF-8?q?=C3=A9ria=20e=20norma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/tests/test_materia.py | 11 +++++++---- sapl/norma/tests/test_norma.py | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/sapl/materia/tests/test_materia.py b/sapl/materia/tests/test_materia.py index 4af9df7ea..80f3f244f 100644 --- a/sapl/materia/tests/test_materia.py +++ b/sapl/materia/tests/test_materia.py @@ -1,10 +1,10 @@ -import pytest from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.core.urlresolvers import reverse from django.db.models import Max from model_mommy import mommy +import pytest from sapl.base.models import Autor, TipoAutor from sapl.comissoes.models import Comissao, TipoComissao @@ -528,11 +528,13 @@ def test_numeracao_materia_legislativa_por_legislatura(admin_client): ) # Cria uma materia na legislatura1 - tipo_materia = mommy.make(TipoMateriaLegislativa, id=1, sequencia_numeracao='L') + tipo_materia = mommy.make(TipoMateriaLegislativa, + id=1, sequencia_numeracao='L') materia = mommy.make(MateriaLegislativa, tipo=tipo_materia, ano=2017, - numero=1 + numero=1, + data_apresentacao='2017-03-05' ) url = reverse('sapl.materia:recuperar_materia') @@ -556,7 +558,8 @@ def test_numeracao_materia_legislativa_por_legislatura(admin_client): def test_numeracao_materia_legislativa_por_ano(admin_client): # Cria uma materia - tipo_materia = mommy.make(TipoMateriaLegislativa, id=1, sequencia_numeracao='A') + tipo_materia = mommy.make(TipoMateriaLegislativa, + id=1, sequencia_numeracao='A') materia = mommy.make(MateriaLegislativa, tipo=tipo_materia, ano=2017, diff --git a/sapl/norma/tests/test_norma.py b/sapl/norma/tests/test_norma.py index 5c2a76a6a..277ed47ed 100644 --- a/sapl/norma/tests/test_norma.py +++ b/sapl/norma/tests/test_norma.py @@ -1,13 +1,13 @@ -import pytest from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy +import pytest +from sapl.base.models import AppConfig from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.norma.forms import (NormaJuridicaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm) from sapl.norma.models import NormaJuridica, TipoNormaJuridica -from sapl.base.models import AppConfig @pytest.mark.django_db(transaction=False) @@ -81,6 +81,15 @@ def test_norma_juridica_materia_inexistente(): tipo = mommy.make(TipoNormaJuridica) tipo_materia = mommy.make(TipoMateriaLegislativa, descricao='VETO') + # cria uma matéria qualquer em 2017 pois, no teste, o campo ano_materia + # está vazio + materia = mommy.make(MateriaLegislativa, + tipo=tipo_materia, + ano=2017, + numero=1, + data_apresentacao='2017-03-05' + ) + form = NormaJuridicaForm(data={'tipo': str(tipo.pk), 'numero': '1', 'ano': '2017', @@ -94,7 +103,8 @@ def test_norma_juridica_materia_inexistente(): assert not form.is_valid() - assert form.errors['__all__'] == [_("Matéria Legislativa 2/2017 (VETO) é inexistente.")] + assert form.errors['__all__'] == [ + _("Matéria Legislativa 2/2017 (VETO) é inexistente.")] @pytest.mark.django_db(transaction=False) From 2c13a13f8b6d564d11e2729bf7f19af92067a9eb Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 01:00:19 -0200 Subject: [PATCH 050/222] bump pyyaml --- requirements/requirements.txt | 9 +++++---- setup.py | 11 ++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index bb93e9f0e..3c4d2e135 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,7 +1,6 @@ dj-database-url==0.4.1 django-haystack==2.6.0 django>=1.10,<1.11 -git+git://github.com/rubgombar1/django-admin-bootstrapped.git django-bootstrap3==7.0.1 django-bower==5.2.0 django-braces==1.9.0 @@ -14,15 +13,13 @@ django-floppyforms==1.6.2 django-model-utils==3.1.1 django-sass-processor==0.5.8 djangorestframework==3.4.0 -git+git://github.com/jasperlittle/django-rest-framework-docs easy-thumbnails==2.5 django-image-cropping==1.2 -git+git://github.com/interlegis/trml2pdf.git libsass==0.11.1 psycopg2-binary==2.7.4 python-decouple==3.0 pytz==2016.4 -pyyaml==3.11 +pyyaml==4.2b1 rtyaml==0.0.3 textract==1.5.0 unipath==1.1 @@ -34,3 +31,7 @@ WeasyPrint==0.42 whoosh==2.7.4 django-speedinfo==1.3.5 django-reversion-compare==0.8.4 + +git+git://github.com/interlegis/trml2pdf.git +git+git://github.com/jasperlittle/django-rest-framework-docs +git+git://github.com/rubgombar1/django-admin-bootstrapped.git \ No newline at end of file diff --git a/setup.py b/setup.py index aa79dc5b8..6b7c5a248 100644 --- a/setup.py +++ b/setup.py @@ -12,11 +12,6 @@ install_requires = [ 'dj-database-url==0.4.1', 'django-haystack==2.6.0', 'django>=1.10,<1.11', - # 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-bootstrap3==7.0.1', 'django-bower==5.2.0', 'django-braces==1.9.0', @@ -32,12 +27,11 @@ install_requires = [ 'drfdocs', 'easy-thumbnails==2.5', 'django-image-cropping==1.1.0', - # 'git+git://github.com/interlegis/trml2pdf.git', 'libsass==0.11.1', 'psycopg2==2.7.4', 'python-decouple==3.0', 'pytz==2016.4', - 'pyyaml==3.11', + 'pyyaml==4.2b1', 'rtyaml==0.0.3', 'textract==1.5.0', 'unipath==1.1', @@ -49,6 +43,9 @@ install_requires = [ 'whoosh==2.7.4', 'django-speedinfo==1.3.5', 'django-reversion-compare==0.8.4' + # 'git+git://github.com/interlegis/trml2pdf.git', + # 'git+git://github.com/jasperlittle/django-rest-framework-docs' + # 'git+git://github.com/rubgombar1/django-admin-bootstrapped.git'' ] setup( name='interlegis-sapl', From 0124d4daeefcf89e093a4a13c93ceebc0a0631fe Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 01:43:31 -0200 Subject: [PATCH 051/222] =?UTF-8?q?corrige=20erro=20no=20filtro=20de=20pos?= =?UTF-8?q?s=C3=ADveis=20autores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/api/forms.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sapl/api/forms.py b/sapl/api/forms.py index 14a6ef114..fecfbf598 100644 --- a/sapl/api/forms.py +++ b/sapl/api/forms.py @@ -160,14 +160,12 @@ class AutoresPossiveisFilterSet(FilterSet): tipo = self.form.cleaned_data['tipo'] \ if 'tipo' in self.form.cleaned_data else None - if not tipo and not data_relativa: + if not tipo: return qs - if tipo: - # não precisa de try except, já foi validado em filter_tipo - tipo = TipoAutor.objects.get(pk=tipo) - if not tipo.content_type: - return qs + tipo = TipoAutor.objects.get(pk=tipo) + if not tipo.content_type: + return qs filter_for_model = 'filter_%s' % tipo.content_type.model From f4eccaa4c7e0b76d7f73beedc1cc6c54c2cb89f6 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 02:10:46 -0200 Subject: [PATCH 052/222] =?UTF-8?q?corrige=20checkbox=20limpar=20nos=20cam?= =?UTF-8?q?pos=20de=20adi=C3=A7=C3=A3o=20de=20arquivos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/static/js/app.js | 12 + sapl/static/styles/app.css | 503 ------------- sapl/static/styles/app.scss | 47 +- sapl/static/styles/compilacao.css | 1136 ----------------------------- 4 files changed, 16 insertions(+), 1682 deletions(-) delete mode 100644 sapl/static/styles/app.css delete mode 100644 sapl/static/styles/compilacao.css diff --git a/sapl/static/js/app.js b/sapl/static/js/app.js index 4341cb784..48777c0e3 100644 --- a/sapl/static/js/app.js +++ b/sapl/static/js/app.js @@ -195,10 +195,22 @@ function OptionalCustomFrontEnd() { if (this.type === "checkbox") { _label.prepend(_this); + + var _div = _label.closest('.checkbox'); + if (_div.length == 0) { + _label.addClass('checkbox-inline') + } + _this.checkbox(); } else if (this.type === "radio") { _label.prepend(_this); + + var _div = _label.closest('.radio'); + if (_div.length == 0) { + _label.addClass('radio-inline') + } + _this.radio(); } diff --git a/sapl/static/styles/app.css b/sapl/static/styles/app.css deleted file mode 100644 index 3561a3e06..000000000 --- a/sapl/static/styles/app.css +++ /dev/null @@ -1,503 +0,0 @@ -.container-home { - position: relative; - padding: 2em 1.5em 1.5em 1.5em; - max-width: 1000px; - margin: 0 auto; } - .container-home a:hover { - color: #444; - -webkit-transition: 0.3s ease-in; - -moz-transition: 0.3s ease-in; - -o-transition: 0.3s ease-in; } - .container-home #homeIndex { - text-align: center; } - .container-home .homeBanner span { - color: white; - font-size: 32px; - font-weight: 600; - display: inline-block; - vertical-align: middle; - padding: 2px 45px 4px; - border: 2px solid; } - .container-home .homeBanner::after { - display: inline-block; - vertical-align: middle; - height: 100%; } - .container-home .homeBlock { - display: inline-block; - position: relative; - background-color: #F3F3F3; - width: 190px; - height: 260px; - margin: 3px; - text-align: center; - font-size: 0; - overflow: hidden; } - .container-home .homeBlock > a { - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; } - .container-home .homeBlock::after { - content: ''; - display: inline-block; - vertical-align: middle; - height: 100%; - overflow: visible; - clear: none; - visibility: initial; } - .container-home .homeContent { - position: relative; - padding: 10px; - text-align: justify; - font-size: 14px; - color: #FFF; - opacity: 0; - transition: opacity 0.5s ease; - display: inline-block; - vertical-align: middle; } - .container-home .homeContent p { - display: block; - line-height: 13px; - font-size: 80%; - color: white; } - .container-home .homeIcon { - position: relative; - display: inline-block; - width: 105px; - height: 105px; - border-radius: 50%; - background: #364347; - z-index: 1; } - .container-home .homeIcon::before { - content: ''; - position: absolute; - width: 100%; - height: 100%; - border-radius: 50%; - background: #364347; - top: 0; - left: 0; - transform: scale(0.95); - transition: transform 0.6s ease; } - .container-home .homeIcon img { - position: absolute; - margin: auto; - top: 0; - bottom: 0; - right: 0; - left: 0; - transition: opacity 0.4s 0.4s ease; } - .container-home .homeFront { - position: absolute; - top: 46%; - width: 100%; - font-size: 0; - transform: translateY(-60%); } - .container-home .homeFront h2 { - position: absolute; - margin-top: 18px; - font-size: 22px; - font-weight: 700; - color: #595959 !important; - width: 100%; - padding: 0 6%; - z-index: 0; } - .container-home .homeTitle { - display: block; - height: 32px; - text-align: center; - width: 100%; - opacity: 0; - transition: opacity 0.4s ease; } - .container-home .homeTitle::before { - content: ''; - display: inline-block; - vertical-align: middle; - height: 100%; } - .container-home .homeTitle h2 { - display: inline-block; - vertical-align: middle; - max-width: 110px; - font-size: 14px; - color: white !important; - line-height: 1em; } - .container-home .homeTitle img { - display: inline-block; - vertical-align: middle; - height: 30px; - margin-right: 5px; } - .container-home .homeBlock:hover .homeIcon::before { - transform: scale(3.6) translateY(7px); } - .container-home .homeBlock:hover .homeContent { - opacity: 1; - transition-delay: 0.2s; } - .container-home .homeBlock:hover .homeIcon img { - opacity: 0; - transition-duration: 0.2s; - transition-delay: 0s; } - .container-home .homeBlock:hover .homeTitle { - opacity: 1; } - -html { - position: relative; - min-height: 100%; } - -body { - margin-bottom: 160px; } - -h1, h2, h3, h4, h5, h6, form, dl, dt, dd, p, div, img, a { - margin: 0; - padding: 0; } - -h1, .h1 { - font-size: 30px; } - -h2, .h2 { - font-size: 24px; } - -h3, .h3 { - font-size: 20px; } - -h4, .h4 { - font-size: 16px; } - -h5, .h5 { - font-size: 14px; } - -h6, .h6 { - font-size: 12px; } - -p { - margin: 0.5em 0; } - p .control-label { - font-weight: bold; } - -label { - margin-bottom: 0; - line-height: 1; } - -fieldset fieldset { - font-size: 95%; } - fieldset fieldset legend { - font-size: 18px; } - -.page-header { - margin: 20px 0px 10px; } - -.caret.top { - transform: rotate(180deg); } - -.btn:hover, .btn:focus { - color: inherit; } - -.btn-default.btn-excluir { - color: #d9534f; } - .btn-default.btn-excluir:hover { - color: #fff; - border-color: #de6764; - background-color: #de6764; } - -.btn-cancel-iframe { - position: relative; - text-align: right; - opacity: 0.5; } - .btn-cancel-iframe:hover { - opacity: 1; } - .btn-cancel-iframe a { - padding: 10px; - display: inline-block; } - -.legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: #333333; - border: 0; - border-bottom: 1px solid #e5e5e5; - clear: both; } - -.grid-gutter-width-right { - margin-right: 15px; } - -.controls-file { - padding: 10px; - border: 1px solid #d6e1e5; - border-radius: 4px; } - .controls-file label.checkbox-inline { - margin: 0px; - display: block; } - -.help-block-danger { - margin: 15px; - padding: 15px; - border: 2px dashed #f00; } - -.control-label { - margin: 0; } - -.form-control-static { - padding-top: 0; - min-height: auto; } - .form-control-static img { - max-width: 100%; } - -.pagination { - padding-top: 25px; } - -.modal .alert { - margin-bottom: 0; } - -.avatar-parlamentar { - height: 128px; - width: 128px; - margin: 0 auto; - display: table; } - -.masthead { - padding: 10px; } - .masthead .nav { - clear: both; } - .masthead .navbar-brand { - padding: 0px; - color: inherit; - font-size: 24px; } - .masthead .navbar-brand img.img-responsive { - height: 95px; - margin-right: 15px; - display: inline-block; } - .masthead .navbar-brand small { - color: #93A4AA; - font-size: 75%; - line-height: 25px; } - .masthead .navbar-brand .vcenter { - display: inline-block; - vertical-align: middle; - float: none; - padding: 10px; } - -nav.navbar { - margin-bottom: 0; - border-radius: 0; - font-size: 15px; } - -nav .navbar-nav > li > a { - padding-top: 0px; - padding-bottom: 0px; - line-height: 75px; } - nav .navbar-nav > li > a:hover { - background-color: #23527c; } - -nav .navbar-nav > li:nth-child(2) > .dropdown-menu { - right: auto; } - -nav .navbar-nav:last-child > li:last-child a { - padding-right: 0px; } - -.controls-radio-checkbox { - padding: 0px; - border: 1px solid #d6e1e5; - border-radius: 4px; - min-height: 20px; } - .controls-radio-checkbox .checkbox, .controls-radio-checkbox .radio, .controls-radio-checkbox .checkbox-inline, .controls-radio-checkbox .radio-inline { - padding: 8px 8px 8px 36px; - margin: 0; - line-height: 1.6; - display: block; } - .controls-radio-checkbox .checkbox:hover, .controls-radio-checkbox .radio:hover, .controls-radio-checkbox .checkbox-inline:hover, .controls-radio-checkbox .radio-inline:hover { - background-color: #d6e1e5; } - .controls-radio-checkbox .checkbox .icons, .controls-radio-checkbox .radio .icons, .controls-radio-checkbox .checkbox-inline .icons, .controls-radio-checkbox .radio-inline .icons { - top: auto; - left: 8px; } - .controls-radio-checkbox .checkbox-inline, .controls-radio-checkbox .radio-inline { - display: inline-block; } - .controls-radio-checkbox .help-block { - margin: 15px; - padding: 15px; - border: 2px dashed #d6e1e5; } - -.controls-radio-checkbox__old { - padding: 0px; - border: 1px solid #d6e1e5; - border-radius: 4px; - min-height: 20px; } - .controls-radio-checkbox__old label { - padding: 0; - line-height: 2.7; - padding-left: 36px; } - .controls-radio-checkbox__old label .icons { - top: 8px; - left: 8px; } - .controls-radio-checkbox__old label.checkbox-inline, .controls-radio-checkbox__old label.radio-inline { - padding-right: 8px; } - .controls-radio-checkbox__old label.checkbox-inline .icons, .controls-radio-checkbox__old label.radio-inline .icons { - top: 8px; - left: 8px; } - .controls-radio-checkbox__old .checkbox, .controls-radio-checkbox__old .radio, .controls-radio-checkbox__old .checkbox-inline, .controls-radio-checkbox__old .radio-inline { - margin: 0; } - .controls-radio-checkbox__old .checkbox:hover, .controls-radio-checkbox__old .radio:hover, .controls-radio-checkbox__old .checkbox-inline:hover, .controls-radio-checkbox__old .radio-inline:hover { - background-color: #d6e1e5; } - -.manual, .manual ul { - padding-left: 1.5em; - list-style-type: none; - margin-top: 0; - font-size: 100%; } - -.manual li { - display: list-item; - line-height: 1.5em; - padding-right: 0; } - .manual li a { - background-color: transparent; - border: none; - border-radius: none; - padding: 0; } - -.container-tabaux .sidebar-tabaux { - background: #fafafa; - margin-top: -70px; - padding: 10px; - border: 1px solid #eee; } - .container-tabaux .sidebar-tabaux .navbar-right { - margin: 0; } - .container-tabaux .sidebar-tabaux .nav-pills > li + li { - margin-left: 0px; } - .container-tabaux .sidebar-tabaux li { - width: 100%; } - .container-tabaux .sidebar-tabaux span { - display: none; } - .container-tabaux .sidebar-tabaux .dropdown-menu { - padding: 0px; - right: 10px; - margin-top: -5px; - overflow: hidden; } - .container-tabaux .sidebar-tabaux .dropdown-menu a { - border: 0px; } - -.container-tabaux ul { - list-style: none; - padding: 0; } - -.container-tabaux .list { - font-family: "SourceSansProSemiBold", Helvetica, Arial, sans-serif; - font-size: 0px; - display: table; - width: 100%; - margin: 0; } - .container-tabaux .list ul { - display: table; - width: 100%; - margin: 0; } - .container-tabaux .list li { - width: calc(50%); - display: inline-block; - position: relative; } - .container-tabaux .list > li { - width: 100%; - border-bottom: 1px solid #eee; - padding-bottom: 20px; - margin-bottom: 20px; } - .container-tabaux .list .head_title { - color: #364347; - font-size: 2.4rem; - text-transform: none; } - .container-tabaux .list a span { - display: none; } - -#styleparlamentar { - border: 0px solid #d6e1e5; - border-top-color: #d6e1e5; - border-right-color: #d6e1e5; - border-bottom-color: #d6e1e5; - border-left-color: #d6e1e5; - border-image-source: initial; - border-image-slice: initial; - border-image-repeat: initial; - font-size: 16px; - line-height: 1.467; - padding: 7px 12px; - height: 40px; - -webkit-appearance: none; - border-radius: 4px; - -webkit-box-shadow: none; - box-shadow: none; - margin-left: 1.0em; } - -.footer { - background: #364347; - color: white; - text-align: center; - position: absolute; - width: 100%; - bottom: 0px; } - .footer p { - color: white; - margin-top: 10px; } - .footer .container { - padding-top: 25px; } - -@media (max-width: 1199px) { - nav .container { - width: auto !important; } - .navbar-nav > li > a { - padding-left: 10.71429px; - padding-right: 10.71429px; } } - -@media (max-width: 1091px) { - .container { - width: auto; } - .navbar-nav > li > a { - padding-left: 7.5px; - padding-right: 7.5px; } - .masthead .navbar-brand { - font-size: 22px; } - .masthead .navbar-brand img.img-responsive { - height: 60px; - margin-right: 7.5px; } } - -@media (max-width: 991px) { - body { - margin: 0; } - .footer { - position: relative; } - .caret { - margin-left: 1px; } - .navbar-nav > li > a { - padding-left: 4px; - padding-right: 4px; } } - -@media (max-width: 767px) { - nav .navbar-nav > li > a { - line-height: 2.5; } - nav .navbar-right { - position: absolute; - top: 0; - margin: 10px; } - nav .navbar-right > li { - vertical-align: top; - display: inline-block; } - nav .navbar-right > li a { - padding-left: 10px; - padding-right: 10px; } - nav .navbar-right .pesquisa.open ul { - position: absolute; } - nav .navbar-right .navbar-form { - margin: 8px 0; } - .table { - width: auto; - white-space: normal; - display: block; - overflow-x: auto; } } - -@media (min-width: 1092px) and (max-width: 1199px) { - .container { - width: 1070px; } } - -@media print { - a[href]:after { - content: none !important; } } diff --git a/sapl/static/styles/app.scss b/sapl/static/styles/app.scss index 57736d3a7..a0540b8e1 100644 --- a/sapl/static/styles/app.scss +++ b/sapl/static/styles/app.scss @@ -110,16 +110,6 @@ fieldset { margin-right: $grid-gutter-width / 2; } -.controls-file { - padding: 10px; - border: 1px solid #d6e1e5; - border-radius: 4px; - label.checkbox-inline { - margin: 0px; - display: block; - } -} - .help-block-danger { margin: $grid-gutter-width / 2; padding: $grid-gutter-width / 2; @@ -217,12 +207,11 @@ nav { } } -.controls-radio-checkbox { +.controls-radio-checkbox, .controls-file { padding: 0px; border: 1px solid #d6e1e5; border-radius: 4px; min-height: 20px; - .checkbox, .radio, .checkbox-inline, .radio-inline { padding: 8px 8px 8px 36px; @@ -247,36 +236,6 @@ nav { padding: $grid-gutter-width / 2; border: 2px dashed #d6e1e5; } - -} - .controls-radio-checkbox__old { - padding: 0px; - border: 1px solid #d6e1e5; - border-radius: 4px; - min-height: 20px; - label { - padding: 0; - line-height: 2.7; - padding-left: 36px; - .icons { - top: 8px; - left: 8px; - } - - &.checkbox-inline, &.radio-inline, { - padding-right: 8px; - .icons { - top: 8px; - left: 8px; - } - } - } - .checkbox, .radio, .checkbox-inline, .radio-inline { - margin: 0; - &:hover { - background-color: #d6e1e5; - } - } } .manual { @@ -298,7 +257,9 @@ nav { } } } - +.controls-file { + padding: 15px; +} .container-tabaux { .sidebar-tabaux { background: #fafafa; diff --git a/sapl/static/styles/compilacao.css b/sapl/static/styles/compilacao.css deleted file mode 100644 index 557ef057a..000000000 --- a/sapl/static/styles/compilacao.css +++ /dev/null @@ -1,1136 +0,0 @@ -a:link:after, a:visited:after { - content: ""; } - -.test_import:nth-child(even) { - background-color: #ccc; } - -#wait_message { - display: block; - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: rgba(220, 220, 220, 0.75); - z-index: 99; } - #wait_message #msg { - position: relative; - margin: 20% auto; - padding: 1.2em 2em; - max-width: 600px; - text-align: center; - font-size: 1.5em; - color: #677; - border: 1px solid #eee; - background-color: #fff !important; - box-shadow: 0 1px 2px #999; } - -.text-center { - text-align: center; } - -.cp-notify { - z-index: 9999; - position: fixed; - top: 2em; - left: 50%; - min-width: 600px; - transform: translate(-50%, 0); - transition: all 0.4s ease; - opacity: 0.97; } - .cp-notify.hide { - opacity: 0; - top: -1000px; - display: block !important; - transition: all 0.4s ease; } - .cp-notify .message { - padding: 1em; - border: 2px solid rgba(0, 0, 0, 0.1); - border-radius: 4px; - color: rgba(0, 0, 0, 0.6); - line-height: 1em; - font-size: 1.3em; - text-align: center; - box-shadow: 0 0 100px rgba(0, 0, 0, 0.2); } - -.cp { - /* and dpt */ } - .cp .desativado .dtxt, .cp .dpt .dptt > a.desativado .dtxt, .cp .desativado .dtxt *, .cp .dpt .dptt > a.desativado .dtxt *, .cp .desativado .dpt-link, .cp .dpt .dptt > a.desativado .dpt-link, .cp .desativado .dpt-link *, .cp .dpt .dptt > a.desativado .dpt-link * { - text-decoration: line-through; - color: #999 !important; } - .cp .desativado .dtxt table, .cp .dpt .dptt > a.desativado .dtxt table, .cp .desativado .dtxt table td, .cp .dpt .dptt > a.desativado .dtxt table td, .cp .desativado .dtxt * table, .cp .dpt .dptt > a.desativado .dtxt * table, .cp .desativado .dtxt * table td, .cp .dpt .dptt > a.desativado .dtxt * table td, .cp .desativado .dpt-link table, .cp .dpt .dptt > a.desativado .dpt-link table, .cp .desativado .dpt-link table td, .cp .dpt .dptt > a.desativado .dpt-link table td, .cp .desativado .dpt-link * table, .cp .dpt .dptt > a.desativado .dpt-link * table, .cp .desativado .dpt-link * table td, .cp .dpt .dptt > a.desativado .dpt-link * table td { - border: 1px dotted #ccc; } - .cp a { - text-decoration: none; - cursor: pointer; } - .cp .diff .desativado, .cp .diff .dpt .dptt > a.desativado, .cp .dpt .diff .dptt > a.desativado, .cp .diff .desativado *, .cp .diff .dpt .dptt > a.desativado *, .cp .dpt .diff .dptt > a.desativado * { - text-decoration: line-through; - color: #ddd !important; - font-size: 90%; } - .cp .diff .added { - color: #04DE2C; } - .cp .dpt { - font-size: 1em; - position: relative; } - .cp .dpt.indent { - padding-left: 1em; } - .cp .dpt .ementa { - padding: 2em 0em 2em 35%; - font-weight: bold; } - .cp .dpt .titulo_generico, .cp .dpt .anexo, .cp .dpt .disp_preliminares, .cp .dpt .disp_gerais, .cp .dpt .disp_transitorias, .cp .dpt .disp_finais, .cp .dpt .parte, .cp .dpt .livro, .cp .dpt .titulo, .cp .dpt .capitulo, .cp .dpt .secao, .cp .dpt .subsecao, .cp .dpt .itemsecao { - text-align: center; - margin-bottom: 1em; - font-size: 1.15em; - margin-top: 3em; } - .cp .dpt .titulo { - margin-top: 2em; } - .cp .dpt .capitulo { - margin-top: 1.5em; - font-size: 1.15em; } - .cp .dpt .secao { - margin-top: 1.2em; - margin-bottom: 0.7em; - font-weight: bold; - font-size: 1.15em; } - .cp .dpt .subsecao, - .cp .dpt .itemsecao { - margin-top: 1em; - margin-bottom: 0.6em; - font-weight: bold; - font-size: 1.15em; } - .cp .dpt .artigo { - font-size: 1.15em; - float: left; } - .cp .dpt .artigo .dptt { - position: relative; } - .cp .dpt .caput { - margin-top: 0.3333em; - font-size: 1.15em; } - .cp .dpt .paragrafo { - font-size: 1.1em; - margin-top: 0.2222em; } - .cp .dpt .inciso { - font-size: 1.1em; - margin-top: 0.1667em; } - .cp .dpt .alinea { - font-size: 1.0em; - margin-top: 2px; } - .cp .dpt .item { - font-size: 1.0em; - margin-top: 2px; } - .cp .dpt .assinatura { - margin-top: 0.6em; - font-size: 1.15em; } - .cp .dpt .fecho_lei { - margin-top: 0.6em; - font-size: 1.15em; } - .cp .dpt .page-break { - page-break-before: always; } - .cp .dpt .bloco_alteracao { - padding-left: 10%; - font-style: italic; - color: #018; } - .cp .dpt .bloco_alteracao a { - text-decoration: underline; } - .cp .dpt .bloco_alteracao a, .cp .dpt .bloco_alteracao table, .cp .dpt .bloco_alteracao table td { - color: #018 !important; } - .cp .dpt .dn { - /* Notas de Dispositivo*/ - font-weight: normal; - position: relative; - font-size: 70%; } - .cp .dpt .dn p, .cp .dpt .dn ul { - font-weight: normal; - margin: 0 0 0 0; - list-style: none; - padding: 0; } - .cp .dpt .dn .dnl { - /* Lista Notas de Dispositivo*/ - display: block; - text-align: left !important; } - .cp .dpt .dn .dnl * { - display: inline; } - .cp .dpt .dn .dnl .bullet { - padding: 0 0.333em; - display: inline-block; } - .cp .dpt .dn .dnl .dnli { - min-height: 2.5em; } - .cp .dpt .dn .dnl .dnli:hover ul { - transition: opacity 0.5s linear, clip 0s 0.3s; - clip: auto; - opacity: 1; - background: rgba(230, 230, 230, 0.9); } - .cp .dpt .dn .dnl .dnli ul { - transition: opacity 0.5s linear, clip 0s 0.3s; - clip: rect(0, 0, 0, 0); - opacity: 0; - position: absolute; - background: transparent; - right: 0; - padding: 0.2em 0.5em 0em 0.5em; - border: 1px solid #c7e3d3; - border-top: 0px; - font-size: 1.5rem; } - .cp .dpt .dn .dnl .dnli ul li { - display: table-cell; - color: #aaa; } - .cp .dpt .dn .dnl .dnli ul li:hover { - color: #787; } - .cp .dpt .dn .dnl .dnli ul li:hover a { - color: #27AE60 !important; } - .cp .dpt .dn .dnl .dnli ul li .nowner { - color: #27AE60 !important; } - .cp .dpt .dn .dnl .dnli .ntitulo { - font-weight: bold; - color: #03A203; - text-decoration: none; } - .cp .dpt .dn .dnl .dnli .ntitulo a { - color: #294 !important; } - .cp .dpt .dn .dnl .dnli .ntexto { - color: #06D806; } - .cp .dpt .dn .dnl .dnli .ntexto a { - color: #03A203 !important; } - .cp .dpt .dn .dnl:hover { - display: block; } - .cp .dpt .dn .dnl:hover * { - display: block; } - .cp .dpt .dn .dnl:hover > .bullet { - display: none; } - .cp .dpt .dn .dnl:hover .dnli { - margin-top: 0.5em; - border-top: 1px solid #c7e3d3; } - .cp .dpt .dptt { - clear: left; } - .cp .dpt .dptt > a { - color: #000000; } - .cp .dpt .dptt > a.nota-alteracao { - color: #02baf2; - font-size: 0.75em; } - .cp .dpt .dptt > a.nota-alteracao:hover { - text-decoration: underline; } - .cp .dpt .dptt .dne { - position: absolute; - display: block; - right: 0; - left: 0; - top: 0; - height: 0; - transform: scaleX(0); - transform-origin: right; - transition: all 0.3s ease; - border-top: 1px solid #2980B9; } - .cp .dpt .dptt .dne ul.btns-action { - list-style: none; - padding: 0; - position: absolute; - right: 0; - background-color: #2980B9; } - .cp .dpt .dptt .dne ul.btns-action li { - float: left; } - .cp .dpt .dptt .dne ul.btns-action li:hover { - background-color: rgba(0, 0, 0, 0.1); } - .cp .dpt .dptt .dne ul.btns-action li a { - color: white; - padding: 0.15em 1em 0; - display: inline-block; } - .cp .dpt .dptt .dne-nota { - position: relative; - transform: scaleX(1); - height: auto; - border-top: 0px; } - .cp .dpt .dptt .dne-nota ul.btns-action { - display: none; } - .cp .dpt .dptt .dne-nota .dne-form { - margin: 1em -2em 0em; - text-align: left; - font-size: 1.6rem; } - .cp .dpt .dptt:hover .dne { - height: 0.1667rem; - transform: scaleX(1); - transition-delay: 1s; } - .cp .dpt .dptt:hover .dne-nota { - height: auto; - transition-delay: 0s; } - .cp .tipo-vigencias { - list-style: none; - position: fixed; - bottom: 0px; - left: 50%; - transform: translate(-50%, 0); - margin: 0; - padding: 0; - background-color: #2980B9; - z-index: 1000; - opacity: 0.9; - transition: all 0.3s ease-in-out; } - .cp .tipo-vigencias li { - display: inline-block; - border-left: 1px solid #fff; - float: left; } - .cp .tipo-vigencias li a { - color: white; - padding: 0.3em 1em 0; - display: inline-block; - font-size: 110%; - cursor: pointer; } - .cp .tipo-vigencias li a.selected { - background-color: rgba(0, 0, 0, 0.5); } - .cp .tipo-vigencias li:hover { - background-color: rgba(0, 0, 0, 0.2); } - .cp .tipo-vigencias:hover { - opacity: 1; } - -/* end cp */ -.cp.cpe { - /* fim .dpt */ - /* fim dpt-alts */ } - .cp.cpe .desativado, .cp.cpe .dpt .dptt > a.desativado { - text-decoration: line-through; - color: #999 !important; } - .cp.cpe .desativado table, .cp.cpe .dpt .dptt > a.desativado table, .cp.cpe .desativado table td, .cp.cpe .dpt .dptt > a.desativado table td { - border: 1px dotted #ccc; } - .cp.cpe .desativado a.nota-alteracao * { - color: #02baf2 !important; } - .cp.cpe .dpt { - display: block; } - .cp.cpe .dpt > .dpt-actions-fixed { - position: absolute; - right: -0.8em; - top: -0.8em; - z-index: 3; - opacity: 0; } - .cp.cpe .dpt > .dpt-actions-fixed .activate { - display: none; } - .cp.cpe .dpt > .dpt-actions-fixed .deactivate { - display: inline; } - .cp.cpe .dpt > .dpt-actions-fixed .btn-dpt-edit.btn-default { - color: #333; } - .cp.cpe .dpt > .dpt-actions-fixed .btn-dpt-edit.btn-default:hover { - color: #fff; - background-color: #02baf2; } - .cp.cpe .dpt > .dpt-actions, .cp.cpe .dpt > .dpt-actions-bottom { - display: none; } - .cp.cpe .dpt > .dpt-text { - cursor: text; - min-height: 30px; - border: 1px solid transparent; } - .cp.cpe .dpt > .dpt-text:hover, .cp.cpe .dpt > .dpt-text.hover-fixed { - background-color: rgba(0, 0, 0, 0.01); - color: #2980B9; - border: 1px solid #eee; - transition: color 0.3s ease; } - .cp.cpe .dpt > .dpt-text.artigo { - float: none; } - .cp.cpe .dpt > .dpt-text a.link-rotulo { - color: #000; } - .cp.cpe .dpt:hover > .dpt-actions-fixed { - opacity: 1; } - .cp.cpe .dpt:hover > .dpt-actions-fixed:hover ~ .dpt-text { - background-color: rgba(0, 0, 0, 0.01); - color: #2980B9; - border: 1px solid #eee; - transition: color 0.3s ease; } - .cp.cpe .dpt .semtexto { - font-weight: bold; - color: #9aaed6; } - .cp.cpe .dpt .semtexto:hover { - color: #5f76a4; } - .cp.cpe .dpt-alts { - margin: 0; - margin-bottom: 1em; - padding: 0; - background-color: transparent; - min-height: 100px; - border: 2px dashed #fff; } - .cp.cpe .dpt-alts:hover { - border-color: #d9ddde; } - .cp.cpe .dpt-alts:empty { - border-color: #ddd; } - .cp.cpe .dpt-alts.drag { - width: 100% !important; - border-color: #d9ddde; } - .cp.cpe .dpt-alts.drag .dpt { - transition-duration: 0s !important; } - .cp.cpe .dpt-alts .dpt { - width: 100% !important; - box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); - padding: 0; - margin: 0; - background-color: #edf0f1; - height: auto !important; - min-height: 2em; - z-index: 1; } - .cp.cpe .dpt-alts .dpt:not(:first-child) { - border-top: 1px solid white; } - .cp.cpe .dpt-alts .dpt > .dpt-text { - padding: 0.3em 1em; - margin-top: 0; - margin-bottom: 0; } - .cp.cpe .dpt-alts .dpt > .dpt-text a.link-rotulo { - text-decoration: underline; } - .cp.cpe .dpt-alts .dpt-selected.dpt { - margin: 0em -0.5em; } - .cp.cpe .dpt-selected.dpt { - width: auto !important; - margin: 1em -0.5em; - border: 1px solid #fad46b !important; - padding: 0; - background-color: #fafafa; - border-radius: 3px; - z-index: 4; } - .cp.cpe .dpt-selected.dpt > .dpt-text { - border: 1px solid transparent; } - .cp.cpe .dpt-selected.dpt > .dpt-text:hover { - border: 1px solid transparent; - background-color: transparent; } - .cp.cpe .dpt-selected.dpt > .dpt-form { - margin-bottom: 0em; } - .cp.cpe .dpt-selected.dpt > .dpt-actions, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom { - display: table; - background-color: #e5e5e5; - padding: 1em; - margin-bottom: 0em; - width: 100%; } - .cp.cpe .dpt-selected.dpt > .dpt-actions > .btn-action, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom > .btn-action { - display: table-cell; - float: none; } - .cp.cpe .dpt-selected.dpt > .dpt-actions .btn-excluir, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .btn-excluir, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar { - display: inline-block; - opacity: 0.3; } - .cp.cpe .dpt-selected.dpt > .dpt-actions .btn-excluir:hover, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar:hover, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions .csform .actions_inserts > li > a.btn-salvar:hover, .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .btn-excluir:hover, .cp.cpe .cp.cpe1_old_apagar .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar:hover, .cp.cpe1_old_apagar .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom .csform .actions_inserts > li > a.btn-salvar:hover { - opacity: 1; } - .cp.cpe .dpt-selected.dpt > .dpt-actions-bottom { - margin: 0; } - .cp.cpe .dpt-selected .dpt-block { - border-top: 1px solid #e5e5e5 !important; - opacity: 0.6; - transition: opacity 0.4s ease; } - .cp.cpe .dpt-selected .dpt-block:hover { - opacity: 1; } - .cp.cpe .dpt-selected .dpt:only-child { - /*border-bottom: 1px solid #e5e5e5 !important;*/ } - .cp.cpe .dpt-selected .dpt:not(:last-child) { - /*border-bottom: 1px solid #e5e5e5 !important;*/ } - .cp.cpe .dpt-selected .dpt-text { - opacity: 0.7; - margin: 0; - padding: 0.7em; } - .cp.cpe .dpt-selected .dpt-text:hover { - opacity: 1; - background-color: #f5f5f5; } - .cp.cpe .dpt-selected .dpt-alts { - margin: 1em; } - .cp.cpe .dpt-selected .dpt-alts .dpt { - box-shadow: 0 0 0; } - .cp.cpe .dpt-selected > .dpt-actions-fixed { - opacity: 1; - top: -12px; - right: 0.5em; } - .cp.cpe .dpt-selected > .dpt-actions-fixed .activate { - display: inline; } - .cp.cpe .dpt-selected > .dpt-actions-fixed .deactivate { - display: none; } - .cp.cpe .dpt-selected > .dpt-actions-fixed .btn-dpt-edit { - padding-top: 2px; - padding-bottom: 1px; } - .cp.cpe .dpt-selected > .dpt-actions-fixed .btn-dpt-edit.btn-default { - background-color: #fad46b; - border: 1px solid #fad46b; } - .cp.cpe .dpt-selected .dropdown-menu.dropdown-menu-left { - right: auto !important; - left: 0; - padding: 2px 0; } - .cp.cpe .dpt-selected .dropdown-menu.dropdown-menu-left > .top.arrow { - right: 88%; - left: auto; } - .cp.cpe .dpt-selected .dropdown-menu li a { - padding-top: 2px; - padding-bottom: 2px; } - .cp.cpe .dpt-selected .btn-group .radius-right { - border-bottom-right-radius: 4px !important; - border-top-right-radius: 4px !important; } - .cp.cpe .dpt-selected:hover > .dpt-actions-fixed { - opacity: 1; } - -.cp.cpe1_old_apagar { - margin-bottom: 15em; - /* fim dpt */ - /* fim dpt-selected */ } - .cp.cpe1_old_apagar .desativado, .cp.cpe1_old_apagar .dpt .dptt > a.desativado, .cp.cpe1_old_apagar .desativado *, .cp.cpe1_old_apagar .dpt .dptt > a.desativado * { - text-decoration: line-through; - color: #999 !important; } - .cp.cpe1_old_apagar .desativado table, .cp.cpe1_old_apagar .dpt .dptt > a.desativado table, .cp.cpe1_old_apagar .desativado table td, .cp.cpe1_old_apagar .dpt .dptt > a.desativado table td, .cp.cpe1_old_apagar .desativado * table, .cp.cpe1_old_apagar .dpt .dptt > a.desativado * table, .cp.cpe1_old_apagar .desativado * table td, .cp.cpe1_old_apagar .dpt .dptt > a.desativado * table td { - border: 1px dotted #ccc; } - .cp.cpe1_old_apagar a { - text-decoration: none; - cursor: pointer; } - .cp.cpe1_old_apagar .dpt { - position: relative; - display: block; } - .cp.cpe1_old_apagar .dpt .semtexto { - font-weight: bold; - color: #BFD1F6; } - .cp.cpe1_old_apagar .dpt .artigo { - float: none; } - .cp.cpe1_old_apagar .dpt .caput { - margin-top: 0; } - .cp.cpe1_old_apagar .dpt > .actions_right, .cp.cpe1_old_apagar .dpt-selected .csform .dpt > .actions_left { - color: #fff; - right: 0em; - position: absolute; - opacity: 0; - transition: all 0.4s ease-in-out; - z-index: 1000; } - .cp.cpe1_old_apagar .dpt > .actions_right a.btn-bloco, .cp.cpe1_old_apagar .dpt-selected .csform .dpt > .actions_left a.btn-bloco { - background-color: #3498db; - color: #ffffff !important; - padding: 8px 18px 6px; - display: inline-block; - line-height: 1; - float: right; } - .cp.cpe1_old_apagar .dpt > .actions_right a.btn-bloco:hover, .cp.cpe1_old_apagar .dpt-selected .csform .dpt > .actions_left a.btn-bloco:hover { - opacity: 1; - background-image: -webkit-linear-gradient(top, #1c81c4, #0b6dad); - background-image: -moz-linear-gradient(top, #1c81c4, #0b6dad); - background-image: -ms-linear-gradient(top, #1c81c4, #0b6dad); - background-image: -o-linear-gradient(top, #1c81c4, #0b6dad); - background-image: linear-gradient(to bottom, #1c81c4, #0b6dad); } - .cp.cpe1_old_apagar .dpt:hover > .actions_right, .cp.cpe1_old_apagar .dpt-selected .csform .dpt:hover > .actions_left { - opacity: 1; } - .cp.cpe1_old_apagar .dpt .bloco { - display: block; - clear: both; } - .cp.cpe1_old_apagar .dpt .bloco *:hover { - color: #27AE60; } - .cp.cpe1_old_apagar .dpt .bloco .de { - cursor: pointer; } - .cp.cpe1_old_apagar .dpt .articulacao { - border-top: 2px solid #e5e5e5; - margin: 2em 0; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao { - margin: 1em 0; - padding: 0em; - background-color: transparent; - min-height: 100px; - border: 2px dashed #fff; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao:hover { - border-color: #d9ddde; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao.drag { - width: 100% !important; - border-color: #d9ddde; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao.drag .dpt { - transition-duration: 0s !important; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt { - width: 100% !important; - box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); - padding: 0.3em 1em; - margin: 0; - background-color: #edf0f1; - z-index: 1; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt:not(:first-child) { - border-top: 1px solid white; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt.ui-draggable div { - cursor: pointer; } - .cp.cpe1_old_apagar .dpt .bloco_alteracao .dpt.dpt-comp-selected { - transition: all 0.3s ease; - width: auto !important; - margin: 2em -3.7em; - box-shadow: 0 0 6px rgba(0, 0, 0, 0.16), 0 6px 12px rgba(0, 0, 0, 0.32); } - .cp.cpe1_old_apagar .dpt-selected { - font-size: 1em; - border: 0px solid #CCC; - margin: 1em -1.8em 1em -1.8em; - padding: 2.2em 2.2em 1.6em 2.2em; - box-shadow: -4px 15px 15px rgba(0, 0, 0, 0.1), 0px 6px 6px rgba(0, 0, 0, 0.23); - background-image: -webkit-linear-gradient(top, #eaeaee, #ddd); - background-image: -moz-linear-gradient(top, #eaeaee, #ddd); - background-image: -ms-linear-gradient(top, #eaeaee, #ddd); - background-image: -o-linear-gradient(top, #eaeaee, #ddd); - background-image: linear-gradient(to bottom, #eaeaee, #ddd); - /* fim csform*/ } - .cp.cpe1_old_apagar .dpt-selected ul { - list-style: none; - margin: 0; - padding: 0; } - .cp.cpe1_old_apagar .dpt-selected .semtexto { - color: #999; } - .cp.cpe1_old_apagar .dpt-selected .bloco { - opacity: 0.5; } - .cp.cpe1_old_apagar .dpt-selected .bloco:hover { - opacity: 1; } - .cp.cpe1_old_apagar .dpt-selected .bloco a:hover { - background: transparent; } - .cp.cpe1_old_apagar .dpt-selected > .bloco { - opacity: 1; - margin: 1em; } - .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao { - margin: 0; - padding: 1em; - border: 0 transparent; - background-image: -webkit-linear-gradient(top, #eaeaee, #ddd); - background-image: -moz-linear-gradient(top, #eaeaee, #ddd); - background-image: -ms-linear-gradient(top, #eaeaee, #ddd); - background-image: -o-linear-gradient(top, #eaeaee, #ddd); - background-image: linear-gradient(to bottom, #eaeaee, #ddd); } - .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao:hover { - border-color: transparent; } - .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao.drag { - width: 100% !important; } - .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao.drag .dpt { - transition-duration: 0s !important; } - .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao .dpt { - width: auto !important; - transition: all 0.3s ease; - background-color: white; } - .cp.cpe1_old_apagar .dpt-selected .bloco_alteracao .dpt:not(:first-child) { - border-top: 0px solid white; } - .cp.cpe1_old_apagar .dpt-selected > .dpt { - padding: 0; } - .cp.cpe1_old_apagar .dpt-selected > .dpt:last-child { - padding-bottom: 1em; } - .cp.cpe1_old_apagar .dpt-selected > .actions_right a.btn-bloco, .cp.cpe1_old_apagar .dpt-selected .csform .dpt-selected > .actions_left a.btn-bloco { - display: none; } - .cp.cpe1_old_apagar .dpt-selected .csform { - /* compilacao simple form */ - display: block; - clear: both; - z-index: 9; - position: static; - /* actions_inserts */ } - .cp.cpe1_old_apagar .dpt-selected .csform .btns-action { - -webkit-animation: fadeIn 1s ease-in-out; - -moz-animation: fadeIn 1s ease-in-out; - -o-animation: fadeIn 1s ease-in-out; - opacity: 1; - position: absolute; - display: table; - transition: all 0.4s ease-in-out; } - .cp.cpe1_old_apagar .dpt-selected .csform .btns-action a { - color: #16407c; - display: block; - background: transparent; - vertical-align: middle; - text-align: center; - font-weight: normal; - text-shadow: 0 0 10px rgba(0, 0, 0, 0.3); - padding: 0.33em 0.4em; } - .cp.cpe1_old_apagar .dpt-selected .csform .btns-action > li { - position: relative; - display: table-cell; - vertical-align: top; } - .cp.cpe1_old_apagar .dpt-selected .csform .btns-action > li:hover { - background-color: rgba(255, 255, 255, 0.5); } - .cp.cpe1_old_apagar .dpt-selected .csform .btns-action > li:hover > a { - text-shadow: 0 0 5px #777; - color: #0a5; } - .cp.cpe1_old_apagar .dpt-selected .csform .label_status { - position: absolute; - bottom: 0; - right: 0; - color: #889; - padding: 0.3em; - font-size: 80%; - text-align: right; - z-index: 15; - display: table; } - .cp.cpe1_old_apagar .dpt-selected .csform .label_status li { - display: table-cell; - padding: 0 0.5em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents { - z-index: 11; - top: 0em; - left: 0em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents a { - padding: 0.62em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents div, .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents li { - font-size: 80%; - display: table-cell; - vertical-align: middle; - border-right: 1px solid #CCC; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents div { - padding: 0 0.4em; - font-stretch: condensed; - font-variant: small-caps; - font-weight: bold; - text-shadow: 0 0 10px #fff; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_parents > li:hover a { - color: #16407c; - font-weight: normal; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_top, .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom { - top: 0em; - right: 0em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_top a, .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom a { - padding-right: 1em; - padding-left: 1em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_top li, .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom li { - display: table-cell; - vertical-align: middle; - border-left: 1px solid #CCC; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom { - top: auto; - left: 0; - bottom: 0; - display: inline-block; - border-top: 1px solid #CCC; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom a { - padding: 0 0.4em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_bottom li { - border: 0px; - border-right: 1px solid #CCC; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_right, .cp.cpe1_old_apagar .dpt-selected .csform .actions_left { - top: 2.2em; - right: 0em; - bottom: 0; - display: block; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_right li, .cp.cpe1_old_apagar .dpt-selected .csform .actions_left li { - width: 2.2em; - display: block; - border-bottom: 1px solid #CCC; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_right li:first-child, .cp.cpe1_old_apagar .dpt-selected .csform .actions_left li:first-child { - border-top: 1px solid #CCC; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_left { - right: auto; - left: 0em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts { - background: transparent; - position: relative; - z-index: 19; - display: table; - width: 100%; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li { - display: table-cell; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li:hover > a { - background-image: -webkit-linear-gradient(top, #1c81c4, #0b6dad); - background-image: -moz-linear-gradient(top, #1c81c4, #0b6dad); - background-image: -ms-linear-gradient(top, #1c81c4, #0b6dad); - background-image: -o-linear-gradient(top, #1c81c4, #0b6dad); - background-image: linear-gradient(to bottom, #1c81c4, #0b6dad); } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a { - background-image: -webkit-linear-gradient(top, #3498DB, #2980C9); - background-image: -moz-linear-gradient(top, #3498DB, #2980C9); - background-image: -ms-linear-gradient(top, #3498DB, #2980C9); - background-image: -o-linear-gradient(top, #3498DB, #2980C9); - background-image: linear-gradient(to bottom, #3498DB, #2980C9); - border-right: 1px solid #fff; - padding: 0.2em; - display: block; - color: white; - text-align: center; - white-space: nowrap; - /* btn-excluir */ } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-excluir, .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar { - text-align: left; - background: #A70808; - color: #c99; - padding-left: 1.7em; - position: relative; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-excluir:hover, .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar:hover { - background-color: #c70808; - color: #ecc; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-excluir::before, .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before { - z-index: 20; - position: absolute; - background: url(/static/img/icon_delete_white.png) no-repeat 50% 50%; - content: ""; - top: 0; - left: 0; - display: block; - color: black; - margin-left: 0.4em; - height: 100%; - width: 2em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar { - background: #1f8b4d; - color: white; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar:hover { - background: #2d9c5c; - color: white; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before { - background: url(/static/img/icon_save_white.png) no-repeat 50% 50%; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a span { - padding: 0 0.7em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li:last-child > a { - border-right: 0px solid #fff; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > ul li:nth-child(even) a { - background: #3385CA; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > ul li a { - border-right: 1px solid #fff; - display: block; - color: white; - background: #2980C9; - font-size: 80%; - padding: 0.23em 1em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > ul li a:hover { - background: #0a5ea4; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior { - table-layout: fixed; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul { - transform: translateY(30px); - transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; - clip: rect(0, 0, 0, 0); - opacity: 0; - position: absolute; - margin-left: 0.5em; - box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); - -webkit-transition-delay: 0.4s; - /* Safari */ - transition-delay: 0.4s; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul li a { - border-right: 0px !important; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul li:first-child::before { - border-width: 0.375rem; - border-style: inset inset solid; - content: ""; - display: block; - height: 0px; - width: 0px; - border-color: transparent transparent #3385CA; - position: absolute; - top: -0.71rem; - left: 0.9375rem; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul li:first-child:hover::before { - border-color: transparent transparent #0A5EA4; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior > ul::after { - content: ""; - position: absolute; - z-index: -1; - left: 0; - top: rem-calc(-25px); - height: rem-calc(25px); - width: 100%; - transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.add_prior:hover > ul { - transform: translateY(7px); - transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; - opacity: 1; - clip: rect(-100px, 2000px, 2000px, -100px); } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir { - display: block; - position: static; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul { - transform: translateY(30px); - transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; - clip: rect(0, 0, 0, 0); - opacity: 0; - position: absolute; - margin-left: 0.5em; - box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); - -webkit-transition-delay: 0.4s; - /* Safari */ - transition-delay: 0.4s; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li a { - border-right: 0px !important; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child::before { - border-width: 0.375rem; - border-style: inset inset solid; - content: ""; - display: block; - height: 0px; - width: 0px; - border-color: transparent transparent #3385CA; - position: absolute; - top: -0.71rem; - left: 0.9375rem; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child:hover::before { - border-color: transparent transparent #0A5EA4; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul::after { - content: ""; - position: absolute; - z-index: -1; - left: 0; - top: rem-calc(-25px); - height: rem-calc(25px); - width: 100%; - transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir:hover > ul { - transform: translateY(7px); - transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; - opacity: 1; - clip: rect(-100px, 2000px, 2000px, -100px); } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul { - right: 0.5em; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li a { - background-color: #A70808; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li a:hover { - background: #c70808; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child::before { - border-color: transparent transparent #A70808; - right: 10%; - left: auto; } - .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child:hover::before { - border-color: transparent transparent #c70808; } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo { - z-index: 2000; } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul { - transform: translateY(30px); - transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; - clip: rect(0, 0, 0, 0); - opacity: 0; - position: absolute; - margin-left: 0.5em; - box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); - -webkit-transition-delay: 0.4s; - /* Safari */ - transition-delay: 0.4s; } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul li a, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul li a { - border-right: 0px !important; } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul li:first-child::before, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul li:first-child::before { - border-width: 0.375rem; - border-style: inset inset solid; - content: ""; - display: block; - height: 0px; - width: 0px; - border-color: transparent transparent #3385CA; - position: absolute; - top: -0.71rem; - left: 0.9375rem; } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul li:first-child:hover::before, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul li:first-child:hover::before { - border-color: transparent transparent #0A5EA4; } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li > ul::after, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li > ul::after { - content: ""; - position: absolute; - z-index: -1; - left: 0; - top: rem-calc(-25px); - height: rem-calc(25px); - width: 100%; - transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li:hover > ul, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li:hover > ul { - transform: translateY(7px); - transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; - opacity: 1; - clip: rect(-100px, 2000px, 2000px, -100px); } - .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante > li.menu_excluir > ul li:first-child::before, .cp.cpe1_old_apagar .dpt-selected .csform .menu_flutuante_fixo > li.menu_excluir > ul li:first-child::before { - right: auto; - left: 0.9375rem; } - .cp.cpe1_old_apagar .dpt-selected .csform textarea { - margin: 0; - resize: vertical; - min-height: 12.6em; - border: 0px; - font-size: 120%; - width: 100%; } - .cp.cpe1_old_apagar .dpt-selected .csform textarea:focus { - background: #fff; } - .cp.cpe1_old_apagar .dpt-selected .csform textarea::-webkit-input-placeholder { - color: #c70808; - opacity: 0.6; - font-size: 80%; } - .cp.cpe1_old_apagar .dpt-selected .csform textarea:-moz-placeholder { - /* Firefox 18- */ - color: #c70808; } - .cp.cpe1_old_apagar .dpt-selected .csform textarea::-moz-placeholder { - /* Firefox 19+ */ - color: #c70808; } - .cp.cpe1_old_apagar .dpt-selected .csform textarea:-ms-input-placeholder { - color: #c70808; - opacity: 0.6; } - .cp.cpe1_old_apagar .selected { - background-color: rgba(255, 255, 255, 0.5); } - .cp.cpe1_old_apagar .selected a:hover { - color: #16407c !important; - font-weight: normal !important; } - -.result-busca-dispositivo, .lista-dispositivo { - padding: 0 0 1em; - min-height: 3em; } - .result-busca-dispositivo ul, .lista-dispositivo ul { - list-style: none; - margin: 0; - padding: 1em 0 0; - transition: all 2s linear; - clear: both; } - .result-busca-dispositivo ul li, .lista-dispositivo ul li { - display: table; - border-collapse: separate; - border-bottom: 1px solid white; - width: 100%; } - .result-busca-dispositivo ul li.ta_title, .lista-dispositivo ul li.ta_title { - background-color: rgba(0, 0, 0, 0.15); - border-radius: 4px 4px 0 0; - width: 100%; } - .result-busca-dispositivo ul li:last-child .itemlabel, .lista-dispositivo ul li:last-child .itemlabel { - border-radius: 0 0 4px 0px; - margin: 0px; } - .result-busca-dispositivo ul li:last-child .iteminput, .lista-dispositivo ul li:last-child .iteminput { - border-radius: 0 0 0px 4px; } - .result-busca-dispositivo ul li .iteminput, .lista-dispositivo ul li .iteminput { - background-color: rgba(0, 0, 0, 0.1); - border-right: 1px solid white; - display: table-cell; - padding: 0.5em; - vertical-align: middle; - text-align: center; } - .result-busca-dispositivo ul li .iteminput input, .lista-dispositivo ul li .iteminput input { - margin: 0; } - .result-busca-dispositivo ul li .itemlabel, .lista-dispositivo ul li .itemlabel { - background-color: rgba(0, 0, 0, 0.1); - display: table-cell; - padding: 0.5em; - vertical-align: middle; - width: 100%; } - .result-busca-dispositivo ul li .itemlabel .artigo, .lista-dispositivo ul li .itemlabel .artigo { - float: none; } - .result-busca-dispositivo .nomenclatura_heranca, .lista-dispositivo .nomenclatura_heranca { - font-size: 90%; - color: #057dba; - display: inline; } - -.lista-dispositivo.controls-radio-checkbox { - border: 0px; } - -.label_vigencia { - border-top: 1px solid white; - display: inline-block; - color: #555; } - .label_vigencia span { - color: gray; } - -.cp-nav-parents > .dropdown-menu { - left: 0; - right: auto; } - .cp-nav-parents > .dropdown-menu::before { - content: ''; - position: absolute; - top: -11px; - width: 100%; - height: 11px; } - -.cp-nav-parents:hover > .dropdown-menu { - display: block; } - -.table-notificacoes tbody tr td { - border-top: 1px solid white; - padding: 5px; - vertical-align: middle; } - .table-notificacoes tbody tr td ul { - margin: 0px; - /*padding: 0px; - list-style: none;*/ } - .table-notificacoes tbody tr td ul li:hover { - background-color: rgba(0, 0, 0, 0.1); } - -.btn-modal-open { - float: right; } - -.class_color_container { - background: #ddd !important; } - -.clear { - clear: both; } - -.mce-tinymce.mce-container { - border: 1px solid #ccc !important; - margin-right: 2px; } - -.mce-btn button:hover { - background-color: rgba(0, 0, 0, 0.1) !important; - text-shadow: 0 0 5px #fff; - box-shadow: 0 0 5px #777; } - -.mce-menu { - background: #eee !important; } - -.displaynone { - display: none !important; } - -@media only screen and (max-width: 800px) { - .cp .fixed { - z-index: 98; - position: relative; } - .cp.cpe1 .dpt-selected { - margin: 1em 0; } - .cp.cpe1 .dpt-selected .csform .actions_parents, .cp.cpe1 .dpt-selected .csform .label_status { - font-size: 80%; - position: static !important; - display: block !important; - padding: 0em; - height: auto !important; - left: 0; - right: auto; - text-align: left; } - .cp.cpe1 .dpt-selected .csform .actions_parents div, .cp.cpe1 .dpt-selected .csform .actions_parents li, .cp.cpe1 .dpt-selected .csform .label_status div, .cp.cpe1 .dpt-selected .csform .label_status li { - display: inline-block !important; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul { - transform: translateY(30px); - transition: transform 0.1s linear, opacity 0.1s linear, clip 0s 0.3s; - clip: rect(0, 0, 0, 0); - opacity: 0; - position: absolute; - margin-left: 0.5em; - box-shadow: 0px 6px 18px rgba(0, 0, 0, 0.19), 0px 2px 6px rgba(0, 0, 0, 0.23); - -webkit-transition-delay: 0.4s; - /* Safari */ - transition-delay: 0.4s; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul li a { - border-right: 0px !important; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul li:first-child::before { - border-width: 0.375rem; - border-style: inset inset solid; - content: ""; - display: block; - height: 0px; - width: 0px; - border-color: transparent transparent #3385CA; - position: absolute; - top: -0.71rem; - left: 0.9375rem; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul li:first-child:hover::before { - border-color: transparent transparent #0A5EA4; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > ul::after { - content: ""; - position: absolute; - z-index: -1; - left: 0; - top: rem-calc(-25px); - height: rem-calc(25px); - width: 100%; - transition: all 0.3s cubic-bezier(0.55, 0, 0.1, 1); } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li:hover > ul { - transform: translateY(7px); - transition: transform 0.4s linear, opacity 0.4s linear, clip 0s 0.2s; - opacity: 1; - clip: rect(-100px, 2000px, 2000px, -100px); } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a span { - display: none; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-excluir, .cp.cpe1 .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1_old_apagar .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar, .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar { - padding-left: 0; - min-width: 1em; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-excluir::before, .cp.cpe1 .cp.cpe1_old_apagar .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before, .cp.cpe1_old_apagar .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before, .cp.cpe1 .dpt-selected .csform .actions_inserts > li > a.btn-salvar::before { - width: 100%; - margin: 0; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_in, .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_next, .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_prior { - position: static; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_in > ul { - left: 1em !important; - right: 1em !important; - margin-left: 0; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_in > ul li:first-child::before { - left: 37%; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_next > ul { - left: 0 !important; - right: 1em !important; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_prior > ul { - left: 1em !important; - right: 0 !important; - margin-left: 0; - margin-right: 0.5em; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.add_prior > ul li:first-child::before { - right: 42%; - left: auto; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.menu_excluir > ul { - left: 10% !important; - right: 0 !important; - margin-left: 0; - margin-right: 0.5em; } - .cp.cpe1 .dpt-selected .csform .actions_inserts > li.menu_excluir > ul li:first-child::before { - right: 0; - left: auto; } } - -@media print { - .cp .vigencias, .toggle-topbar, .menu-icon, .button, .tipo-vigencias, .dne { - display: none; } - #btn_font_menos, #btn_font_mais { - display: none; } - .container { - width: 100%; } } From 9d62e1e626acdd7ed6a67d90030f9488e04f6f7b Mon Sep 17 00:00:00 2001 From: Edward de Oliveira Date: Sat, 5 Jan 2019 04:58:15 -0200 Subject: [PATCH 053/222] HOT-FIX: fix env var in docker-compose.yml --- docker-compose.yml | 2 +- solr/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index e3980a639..b379cf46c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,8 +17,8 @@ sapl: ADMIN_PASSWORD: interlegis ADMIN_EMAIL: email@dominio.net DEBUG: 'False' - USE_TLS: 'False' EMAIL_PORT: 587 + EMAIL_USE_TLS: 'False' EMAIL_HOST: smtp.dominio.net EMAIL_HOST_USER: usuariosmtp EMAIL_HOST_PASSWORD: senhasmtp diff --git a/solr/docker-compose.yml b/solr/docker-compose.yml index 2f97a7e10..8d331443e 100644 --- a/solr/docker-compose.yml +++ b/solr/docker-compose.yml @@ -31,8 +31,8 @@ services: ADMIN_PASSWORD: interlegis ADMIN_EMAIL: email@dominio.net DEBUG: 'False' - USE_TLS: 'False' EMAIL_PORT: 587 + EMAIL_USE_TLS: 'False' EMAIL_HOST: smtp.dominio.net EMAIL_HOST_USER: usuariosmtp EMAIL_HOST_PASSWORD: senhasmtp From 5fff880249d48d968c5a1bd13a27f7c624ecfd40 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 04:43:53 -0200 Subject: [PATCH 054/222] =?UTF-8?q?Refatora=20formul=C3=A1rio=20de=20pesqu?= =?UTF-8?q?isa=20de=20mat=C3=A9rias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/forms.py | 153 ++++++++++++----- .../migrations/0036_auto_20190106_0330.py | 41 +++++ sapl/materia/models.py | 16 +- sapl/materia/views.py | 80 +++++---- sapl/parlamentares/models.py | 3 +- .../materia/materialegislativa_filter.html | 156 +++++++++--------- 6 files changed, 292 insertions(+), 157 deletions(-) create mode 100644 sapl/materia/migrations/0036_auto_20190106_0330.py diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 01814f723..06d5bada8 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -12,7 +12,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.files.base import File from django.core.urlresolvers import reverse from django.db import models, transaction -from django.db.models import Max +from django.db.models import Max, Q, F from django.forms import ModelChoiceField, ModelForm, widgets from django.forms.forms import Form from django.forms.models import ModelMultipleChoiceField @@ -37,7 +37,7 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, UnidadeTramitacao) from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) -from sapl.parlamentares.models import Legislatura +from sapl.parlamentares.models import Legislatura, Partido from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.utils import (YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO, @@ -52,12 +52,19 @@ from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, TipoMateriaLegislativa, Tramitacao, UnidadeTramitacao) -def em_tramitacao(): +def CHOICE_TRAMITACAO(): return [('', 'Tanto Faz'), (1, 'Sim'), (0, 'Não')] +def CHOICE_TIPO_LISTAGEM(): + return [ + (1, _('Detalhada')), + (2, _('Simplificada')), + ] + + class AdicionarVariasAutoriasFilterSet(django_filters.FilterSet): class Meta: @@ -767,32 +774,43 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): autoria__primeiro_autor = django_filters.BooleanFilter( required=False, - label='Primeiro Autor', - widget=forms.HiddenInput()) + label=_('Primeiro Autor')) - ementa = django_filters.CharFilter(lookup_expr='icontains') + autoria__autor__parlamentar_set__filiacao__partido = django_filters.ModelChoiceFilter( + queryset=Partido.objects.all(), + label=_('Matérias por Partido')) + + ementa = django_filters.CharFilter( + label=_('Pesquisar expressões na ementa'), + method='filter_ementa' + ) indexacao = django_filters.CharFilter(lookup_expr='icontains', label=_('Indexação')) em_tramitacao = django_filters.ChoiceFilter(required=False, label='Em tramitação', - choices=em_tramitacao) + choices=CHOICE_TRAMITACAO) materiaassunto__assunto = django_filters.ModelChoiceFilter( queryset=AssuntoMateria.objects.all(), - label=_('Assunto da Matéria')) + label=_('Assunto')) numeracao__numero_materia = django_filters.NumberFilter( required=False, - label=_('Número do Processo')) + label=_('Número do processo')) + + o = MateriaPesquisaOrderingFilter(help_text='') - o = MateriaPesquisaOrderingFilter() + tipo_listagem = forms.ChoiceField( + required=True, + choices=CHOICE_TIPO_LISTAGEM, + label=_('Tipo da Listagem do Resultado da Pesquisa')) class Meta: filter_overrides = {models.DateField: { 'filter_class': django_filters.DateFromToRangeFilter, 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial Final')), + 'label': '%s (%s)' % (f.verbose_name, _('Inicial / Final')), 'widget': RangeWidgetOverride} }} model = MateriaLegislativa @@ -805,7 +823,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): 'data_publicacao', 'autoria__autor__tipo', 'autoria__primeiro_autor', - # FIXME 'autoria__autor__partido', + 'autoria__autor__parlamentar_set__filiacao__partido', 'relatoria__parlamentar_id', 'local_origem_externa', 'tramitacao__unidade_tramitacao_destino', @@ -814,16 +832,36 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): 'em_tramitacao', ] + def filter_ementa(self, queryset, name, value): + texto = value.split() + q = Q() + for t in texto: + q &= Q(ementa__icontains=t) + + return queryset.filter(q) + def __init__(self, *args, **kwargs): super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs) - self.filters['tipo'].label = 'Tipo de Matéria' - self.filters['autoria__autor__tipo'].label = 'Tipo de Autor' - # self.filters['autoria__autor__partido'].label = 'Partido do Autor' - self.filters['relatoria__parlamentar_id'].label = 'Relatoria' + # self.filters['tipo'].label = 'Tipo de Matéria' + self.filters[ + 'autoria__autor__parlamentar_set__filiacao__partido' + ].label = 'Partido do Autor' + + self.filters['autoria__autor__tipo'].label = _('Tipo de Autor') + self.filters['relatoria__parlamentar_id'].label = _('Relatoria') + self.filters['tramitacao__unidade_tramitacao_destino'].label = _( + 'Unidade de tramitação atual') + self.filters['tramitacao__status'].label = _( + 'Status da tramitação atual') + self.filters['tramitacao__status'].label = _( + 'Status da tramitação atual') + + self.filters['o'].label = _('Ordenação') + self.form.fields['tipo_listagem'] = self.tipo_listagem row1 = to_row( - [('tipo', 12)]) + [('tipo', 5), ('ementa', 7)]) row2 = to_row( [('numero', 3), ('numeracao__numero_materia', 3), @@ -832,47 +870,78 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): row3 = to_row( [('data_apresentacao', 6), ('data_publicacao', 6)]) - row4 = to_row( - [('autoria__autor', 0), - ('autoria__primeiro_autor', 0), - (Button('pesquisar', - 'Pesquisar Autor', - css_class='btn btn-primary btn-sm'), 2), - (Button('limpar', - 'limpar Autor', - css_class='btn btn-primary btn-sm'), 10)]) - row5 = to_row( - [('autoria__autor__tipo', 12), - # ('autoria__autor__partido', 6) - ]) + row4 = to_row([ + ('autoria__autor', 0), + (Button('pesquisar', + 'Pesquisar Autor', + css_class='btn btn-primary btn-sm'), 2), + (Button('limpar', + 'limpar Autor', + css_class='btn btn-primary btn-sm'), 2), + ('autoria__primeiro_autor', 2), + ('autoria__autor__tipo', 3), + ('autoria__autor__parlamentar_set__filiacao__partido', 3) + ]) row6 = to_row( [('relatoria__parlamentar_id', 6), ('local_origem_externa', 6)]) row7 = to_row( - [('tramitacao__unidade_tramitacao_destino', 6), - ('tramitacao__status', 6)]) - row8 = to_row( - [('em_tramitacao', 6), - ('o', 6)]) + [('tramitacao__unidade_tramitacao_destino', 5), + ('tramitacao__status', 5), + ('em_tramitacao', 2) + ]) row9 = to_row( [('materiaassunto__assunto', 6), ('indexacao', 6)]) - row10 = to_row( - [('ementa', 12)]) + + row8 = to_row( + [ + ('o', 8), + ('tipo_listagem', 4) + ]) self.form.helper = FormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( - Fieldset(_('Pesquisa de Matéria'), - row1, row2, row3, + Fieldset(_('Pesquisa Básica'), + row1, row2), + + Fieldset(_('Como listar os resultados da pesquisa'), + row8 + ), + Fieldset(_('Pesquisa Avançada'), + row3, HTML(autor_label), HTML(autor_modal), - row4, row5, row6, row7, row8, row9, row10, - form_actions(label='Pesquisar')) + row4, row6, row7, row9, + form_actions(label=_('Pesquisar'))) + + + ) @property def qs(self): - return qs_override_django_filter(self) + qs = qs_override_django_filter(self) + + if hasattr(self.form, 'cleaned_data') and self.form.cleaned_data[ + 'autoria__autor__parlamentar_set__filiacao__partido']: + + q_data_inicio_e_fim = Q(data_apresentacao__gte=F( + 'autoria__autor__parlamentar_set__filiacao__data'), + data_apresentacao__lte=F( + 'autoria__autor__parlamentar_set__filiacao__data_desfiliacao')) + + q_data_inicio = Q( + data_apresentacao__gte=F( + 'autoria__autor__parlamentar_set__filiacao__data'), + autoria__autor__parlamentar_set__filiacao__data_desfiliacao__isnull=True + ) + + qs = qs.filter( + q_data_inicio_e_fim | q_data_inicio + ) + + return qs def pega_ultima_tramitacao(): diff --git a/sapl/materia/migrations/0036_auto_20190106_0330.py b/sapl/materia/migrations/0036_auto_20190106_0330.py new file mode 100644 index 000000000..d8adb9678 --- /dev/null +++ b/sapl/materia/migrations/0036_auto_20190106_0330.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-06 05:30 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0035_auto_20190104_1021'), + ] + + operations = [ + migrations.AlterField( + model_name='materialegislativa', + name='data_apresentacao', + field=models.DateField(verbose_name='Data de Apresentação'), + ), + migrations.AlterField( + model_name='materialegislativa', + name='data_publicacao', + field=models.DateField(blank=True, null=True, verbose_name='Data de Publicação'), + ), + migrations.AlterField( + model_name='materialegislativa', + name='local_origem_externa', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='materia.Origem', verbose_name='Local de Origem'), + ), + migrations.AlterField( + model_name='materialegislativa', + name='numero_protocolo', + field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Número do Protocolo'), + ), + migrations.AlterField( + model_name='materialegislativa', + name='tipo', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='materia.TipoMateriaLegislativa', verbose_name='Tipo de Matéria Legislativa'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index e48446aee..221078811 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -142,15 +142,17 @@ def anexo_upload_path(instance, filename): @reversion.register() class MateriaLegislativa(models.Model): - tipo = models.ForeignKey(TipoMateriaLegislativa, - on_delete=models.PROTECT, - verbose_name=_('Tipo')) + tipo = models.ForeignKey( + TipoMateriaLegislativa, + on_delete=models.PROTECT, + verbose_name=TipoMateriaLegislativa._meta.verbose_name) numero = models.PositiveIntegerField(verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) numero_protocolo = models.PositiveIntegerField( - blank=True, null=True, verbose_name=_('Núm. Protocolo')) - data_apresentacao = models.DateField(verbose_name=_('Data Apresentação')) + blank=True, null=True, verbose_name=_('Número do Protocolo')) + data_apresentacao = models.DateField( + verbose_name=_('Data de Apresentação')) tipo_apresentacao = models.CharField( max_length=1, blank=True, verbose_name=_('Tipo de Apresentação'), @@ -160,7 +162,7 @@ class MateriaLegislativa(models.Model): on_delete=models.PROTECT, verbose_name=_('Regime Tramitação')) data_publicacao = models.DateField( - blank=True, null=True, verbose_name=_('Data Publicação')) + blank=True, null=True, verbose_name=_('Data de Publicação')) tipo_origem_externa = models.ForeignKey( TipoMateriaLegislativa, blank=True, @@ -176,7 +178,7 @@ class MateriaLegislativa(models.Model): blank=True, null=True, verbose_name=_('Data')) local_origem_externa = models.ForeignKey( Origem, blank=True, null=True, - on_delete=models.PROTECT, verbose_name=_('Local Origem')) + on_delete=models.PROTECT, verbose_name=_('Local de Origem')) apelido = models.CharField( max_length=50, blank=True, verbose_name=_('Apelido')) dias_prazo = models.PositiveIntegerField( diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 8af8a19e2..07911f09b 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1747,42 +1747,52 @@ class MateriaLegislativaPesquisaView(FilterView): kwargs = {'data': self.request.GET or None} - status_tramitacao = self.request.GET.get('tramitacao__status') - unidade_destino = self.request.GET.get( - 'tramitacao__unidade_tramitacao_destino') + tipo_listagem = self.request.GET.get('tipo_listagem', '1') + tipo_listagem = '1' if not tipo_listagem else tipo_listagem qs = self.get_queryset().distinct() + if tipo_listagem == '1': + + status_tramitacao = self.request.GET.get('tramitacao__status') + unidade_destino = self.request.GET.get( + 'tramitacao__unidade_tramitacao_destino') + + if status_tramitacao and unidade_destino: + lista = filtra_tramitacao_destino_and_status(status_tramitacao, + unidade_destino) + qs = qs.filter(id__in=lista).distinct() + + elif status_tramitacao: + lista = filtra_tramitacao_status(status_tramitacao) + qs = qs.filter(id__in=lista).distinct() + + elif unidade_destino: + lista = filtra_tramitacao_destino(unidade_destino) + qs = qs.filter(id__in=lista).distinct() + + qs = qs.prefetch_related("autoria_set", + "autoria_set__autor", + "numeracao_set", + "anexadas", + "tipo", + "texto_articulado", + "tramitacao_set", + "tramitacao_set__status", + "tramitacao_set__unidade_tramitacao_local", + "tramitacao_set__unidade_tramitacao_destino", + "normajuridica_set", + "registrovotacao_set", + "documentoacessorio_set") + else: - if status_tramitacao and unidade_destino: - lista = filtra_tramitacao_destino_and_status(status_tramitacao, - unidade_destino) - qs = qs.filter(id__in=lista).distinct() - - elif status_tramitacao: - lista = filtra_tramitacao_status(status_tramitacao) - qs = qs.filter(id__in=lista).distinct() - - elif unidade_destino: - lista = filtra_tramitacao_destino(unidade_destino) - qs = qs.filter(id__in=lista).distinct() + qs = qs.prefetch_related("autoria_set", + "numeracao_set", + "autoria_set__autor", + "tipo",) if 'o' in self.request.GET and not self.request.GET['o']: qs = qs.order_by('-ano', 'tipo__sigla', '-numero') - qs = qs.prefetch_related("autoria_set", - "autoria_set__autor", - "numeracao_set", - "anexadas", - "tipo", - "texto_articulado", - "tramitacao_set", - "tramitacao_set__status", - "tramitacao_set__unidade_tramitacao_local", - "tramitacao_set__unidade_tramitacao_destino", - "normajuridica_set", - "registrovotacao_set", - "documentoacessorio_set") - kwargs.update({ 'queryset': qs, }) @@ -1794,7 +1804,10 @@ class MateriaLegislativaPesquisaView(FilterView): context['title'] = _('Pesquisar Matéria Legislativa') - self.filterset.form.fields['o'].label = _('Ordenação') + tipo_listagem = self.request.GET.get('tipo_listagem', '1') + tipo_listagem = '1' if not tipo_listagem else tipo_listagem + + context['tipo_listagem'] = tipo_listagem qr = self.request.GET.copy() if 'page' in qr: @@ -1810,7 +1823,8 @@ class MateriaLegislativaPesquisaView(FilterView): context['show_results'] = show_results_filter_set(qr) - context['USE_SOLR'] = settings.USE_SOLR if hasattr(settings, 'USE_SOLR') else False + context['USE_SOLR'] = settings.USE_SOLR if hasattr( + settings, 'USE_SOLR') else False return context @@ -2067,12 +2081,12 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): for materia_id in marcadas: try: data_tramitacao = tz.localize(datetime.strptime( - request.POST['data_tramitacao'], "%d/%m/%Y")) + request.POST['data_tramitacao'], "%d/%m/%Y")) except ValueError: msg = _('Formato da data da tramitação incorreto.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - + t = Tramitacao( materia_id=materia_id, data_tramitacao=data_tramitacao, diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 60df66462..8c07914c4 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -1,10 +1,10 @@ -import reversion from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from image_cropping.fields import ImageCropField, ImageRatioField from model_utils import Choices +import reversion from sapl.base.models import Autor from sapl.decorators import vigencia_atual @@ -281,6 +281,7 @@ class Parlamentar(models.Model): ('nome_completo', '__icontains'), ('nome_parlamentar', '__icontains'), ('filiacao__partido__sigla', '__icontains'), + ('filiacao__partido', '__exact'), )) class Meta: diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index 5ff3eaee0..74e179d42 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -34,7 +34,11 @@ {% if paginator.count %} {% if paginator.count > 1 %} -

{% blocktrans with paginator.count as total_materias %}Pesquisa concluída com sucesso! Foram encontradas {{total_materias}} matérias.{% endblocktrans %}

+ {% if not tipo_listagem or tipo_listagem == '1' %} +

{% blocktrans with paginator.count as total_materias %}Pesquisa detalhada concluída com sucesso! Foram encontradas {{total_materias}} matérias.{% endblocktrans %}

+ {% else %} +

{% blocktrans with paginator.count as total_materias %}Pesquisa simplificada concluída com sucesso! Foram encontradas {{total_materias}} matérias.{% endblocktrans %}

+ {% endif %} {% elif paginator.count == 1 %}

{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}

{% endif %} @@ -63,92 +67,96 @@ {% endif %} {% if m.autoria_set.all %} - Autor: - {% for a in m.autoria_set.all %} + Autor: + {% for a in m.autoria_set.all %} {% if not forloop.first %}
{{a.autor}} {% else %}  {{a.autor}} {% endif %} - {% endfor %} -
- {% endif %} - {% if m.tramitacao_set.last.unidade_tramitacao_destino %} - Localização Atual:  {{m.tramitacao_set.last.unidade_tramitacao_destino}}
- {% endif %} - {% if m.tramitacao_set.last.status %} - Status:  {{m.tramitacao_set.last.status}}
- Data Fim Prazo (Tramitação): {{m.tramitacao_set.last.data_fim_prazo|default_if_none:""}}
- {% endif %} - {% if m.registrovotacao_set.exists %} - Data Votação: - {% for rv in m.registrovotacao_set.all %} - {% if rv.ordem %} - - {{ rv.ordem.sessao_plenaria.data_inicio }} - - {% elif rv.expediente %} - - {{ rv.expediente.sessao_plenaria.data_inicio }} - - {% endif %} -
- {% endfor %} - {% endif %} - {% if m.tramitacao_set.last.data_tramitacao %} - Data da última Tramitação:  {{m.tramitacao_set.last.data_tramitacao}}
- Ultima Ação:   {{m.tramitacao_set.last.texto}}
- {% endif %} - {% if m.anexo_de.exists %} - {% for a in m.materia_anexada_set.all %} - Matéria Anexadora:   - - {{ a.materia_principal }}  - - Data Anexação: {{a.data_anexacao}} -
{% endfor %} - {% endif %} - {% if m.anexadas.all.exists %} - {% for anexada in m.materia_principal_set.all %} - Matéria Anexada:   - - {{ anexada.materia_anexada }}  - - Data Anexação: {{anexada.data_anexacao}}
- {% endfor %} {% endif %} - {% if m.documentoacessorio_set.all.exists %} - Documentos Acessórios: - - {{ m.documentoacessorio_set.all.count }} + + {% if not tipo_listagem or tipo_listagem == '1' %} + + {% if m.tramitacao_set.last.unidade_tramitacao_destino %} + Localização Atual:  {{m.tramitacao_set.last.unidade_tramitacao_destino}}
+ {% endif %} + {% if m.tramitacao_set.last.status %} + Status:  {{m.tramitacao_set.last.status}}
+ Data Fim Prazo (Tramitação): {{m.tramitacao_set.last.data_fim_prazo|default_if_none:""}}
+ {% endif %} + {% if m.registrovotacao_set.exists %} + Data Votação: + {% for rv in m.registrovotacao_set.all %} + {% if rv.ordem %} +
+ {{ rv.ordem.sessao_plenaria.data_inicio }} + + {% elif rv.expediente %} + + {{ rv.expediente.sessao_plenaria.data_inicio }} + + {% endif %} +
+ {% endfor %} + {% endif %} + {% if m.tramitacao_set.last.data_tramitacao %} + Data da última Tramitação:  {{m.tramitacao_set.last.data_tramitacao}}
+ Ultima Ação:   {{m.tramitacao_set.last.texto}}
+ {% endif %} + {% if m.anexo_de.exists %} + {% for a in m.materia_anexada_set.all %} + Matéria Anexadora:   + + {{ a.materia_principal }}  + Data Anexação: {{a.data_anexacao}}
- {% endif %} - {% if m.texto_original %}Texto Original
{% endif %} - {% if m.texto_articulado.exists %}Texto Articulado
{% endif %} - {% if m.normajuridica_set.exists %} - {% for nr in m.normajuridica_set.all %} - Norma Jurídica Vinculada: - - {{ nr }} + {% endfor %} + {% endif %} + {% if m.anexadas.all.exists %} + {% for anexada in m.materia_principal_set.all %} + Matéria Anexada:   + + {{ anexada.materia_anexada }}  + + Data Anexação: {{anexada.data_anexacao}} +
+ {% endfor %} + {% endif %} + {% if m.documentoacessorio_set.all.exists %} + Documentos Acessórios: + + {{ m.documentoacessorio_set.all.count }}
+ {% endif %} + {% if m.texto_original %}Texto Original
{% endif %} + {% if m.texto_articulado.exists %}Texto Articulado
{% endif %} + {% if m.normajuridica_set.exists %} + {% for nr in m.normajuridica_set.all %} + Norma Jurídica Vinculada: + + {{ nr }} + +
+ {% endfor %} + {% endif %} + {% if m.audienciapublica_set.exists %} + Audiência(s) Pública(s): + {% for ap in m.audienciapublica_set.all %} + + {{ ap.nome }} + + {% if not forloop.last %}, {% endif %} {% endfor %} - {% endif %} - {% if m.audienciapublica_set.exists %} - Audiência(s) Pública(s): - {% for ap in m.audienciapublica_set.all %} - - {{ ap.nome }} - - {% if not forloop.last %}, {% endif %} - {% endfor %} - {% endif %} -

- {% if m.em_tramitacao and mail_service_configured %} - Acompanhar Matéria + {% endif %} +

+ {% if m.em_tramitacao and mail_service_configured %} + Acompanhar Matéria + {% endif %} {% endif %} From 93e394d3f5c677427716574e6a5070932fcc1696 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 04:54:38 -0200 Subject: [PATCH 055/222] =?UTF-8?q?Refatora=20formul=C3=A1rio=20de=20pesqu?= =?UTF-8?q?isa=20de=20normas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/norma/forms.py | 15 +++++++-- .../migrations/0020_auto_20190106_0454.py | 31 +++++++++++++++++++ sapl/norma/models.py | 21 +++++++------ 3 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 sapl/norma/migrations/0020_auto_20190106_0454.py diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 55541b48f..cd5a091a1 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -6,6 +6,7 @@ from crispy_forms.layout import Fieldset, Layout from django import forms from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db import models +from django.db.models import Q from django.forms import ModelForm, widgets, ModelChoiceField from django.utils import timezone from django.utils.translation import ugettext_lazy as _ @@ -44,7 +45,9 @@ class NormaFilterSet(django_filters.FilterSet): label='Ano', choices=choice_anos_com_normas) - ementa = django_filters.CharFilter(lookup_expr='icontains') + ementa = django_filters.CharFilter( + method='filter_ementa', + label=_('Pesquisar expressões na ementa da norma')) indexacao = django_filters.CharFilter(lookup_expr='icontains', label=_('Indexação')) @@ -52,7 +55,7 @@ class NormaFilterSet(django_filters.FilterSet): assuntos = django_filters.ModelChoiceFilter( queryset=AssuntoNorma.objects.all()) - o = NormaPesquisaOrderingFilter() + o = NormaPesquisaOrderingFilter(help_text='') class Meta: filter_overrides = {models.DateField: { @@ -82,6 +85,14 @@ class NormaFilterSet(django_filters.FilterSet): form_actions(label='Pesquisar')) ) + def filter_ementa(self, queryset, name, value): + texto = value.split() + q = Q() + for t in texto: + q &= Q(ementa__icontains=t) + + return queryset.filter(q) + class NormaJuridicaForm(ModelForm): diff --git a/sapl/norma/migrations/0020_auto_20190106_0454.py b/sapl/norma/migrations/0020_auto_20190106_0454.py new file mode 100644 index 000000000..09c5caa6f --- /dev/null +++ b/sapl/norma/migrations/0020_auto_20190106_0454.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-06 06:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('norma', '0019_auto_20190104_1021'), + ] + + operations = [ + migrations.AlterField( + model_name='normajuridica', + name='data_publicacao', + field=models.DateField(blank=True, null=True, verbose_name='Data de Publicação'), + ), + migrations.AlterField( + model_name='normajuridica', + name='tipo', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='norma.TipoNormaJuridica', verbose_name='Tipo da Norma Jurídica'), + ), + migrations.AlterField( + model_name='normajuridica', + name='veiculo_publicacao', + field=models.CharField(blank=True, max_length=30, verbose_name='Veículo de Publicação'), + ), + ] diff --git a/sapl/norma/models.py b/sapl/norma/models.py index 80075f113..21834cc4d 100644 --- a/sapl/norma/models.py +++ b/sapl/norma/models.py @@ -83,7 +83,7 @@ class NormaJuridica(models.Model): tipo = models.ForeignKey( TipoNormaJuridica, on_delete=models.PROTECT, - verbose_name=_('Tipo da Norma Juridica')) + verbose_name=_('Tipo da Norma Jurídica')) materia = models.ForeignKey( MateriaLegislativa, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_('Matéria')) @@ -98,11 +98,11 @@ class NormaJuridica(models.Model): choices=ESFERA_FEDERACAO_CHOICES) data = models.DateField(blank=False, null=True, verbose_name=_('Data')) data_publicacao = models.DateField( - blank=True, null=True, verbose_name=_('Data Publicação')) + blank=True, null=True, verbose_name=_('Data de Publicação')) veiculo_publicacao = models.CharField( max_length=30, blank=True, - verbose_name=_('Veículo Publicação')) + verbose_name=_('Veículo de Publicação')) pagina_inicio_publicacao = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Pg. Início')) pagina_fim_publicacao = models.PositiveIntegerField( @@ -119,7 +119,8 @@ class NormaJuridica(models.Model): assuntos = models.ManyToManyField( AssuntoNorma, blank=True, verbose_name=_('Assuntos')) - data_vigencia = models.DateField(blank=True, null=True, verbose_name=_('Data Fim Vigência')) + data_vigencia = models.DateField( + blank=True, null=True, verbose_name=_('Data Fim Vigência')) timestamp = models.DateTimeField(null=True) texto_articulado = GenericRelation( @@ -197,7 +198,8 @@ class NormaEstatisticas(models.Model): blank=True, null=True, auto_now=True) norma = models.ForeignKey(NormaJuridica, - on_delete=models.CASCADE) + on_delete=models.CASCADE) + def __str__(self): return _('Usuário: %(usuario)s, Norma: %(norma)s') % { 'usuario': self.usuario, 'norma': self.norma} @@ -225,6 +227,7 @@ class AutoriaNorma(models.Model): return _('Autoria: %(autor)s - %(norma)s') % { 'autor': self.autor, 'norma': self.norma} + @reversion.register() class LegislacaoCitada(models.Model): materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE) @@ -271,8 +274,8 @@ class TipoVinculoNormaJuridica(models.Model): descricao_passiva = models.CharField( max_length=50, blank=True, verbose_name=_('Descrição Passiva')) revoga_integralmente = models.BooleanField(verbose_name=_('Revoga Integralmente?'), - choices=YES_NO_CHOICES, - default=False) + choices=YES_NO_CHOICES, + default=False) class Meta: verbose_name = _('Tipo de Vínculo entre Normas Jurídicas') @@ -318,8 +321,8 @@ class AnexoNormaJuridica(models.Model): on_delete=models.PROTECT, verbose_name=_('Norma Juridica')) assunto_anexo = models.TextField( - blank = True, - default = "", + blank=True, + default="", verbose_name=_('Assunto do Anexo'), max_length=250 ) From c8e520509e0225527883605ec0f5e6d980a225d3 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 13:42:04 -0200 Subject: [PATCH 056/222] Refatora form de pesquisa de protocolos --- sapl/protocoloadm/forms.py | 32 +++++++++---------- .../migrations/0013_auto_20190106_1336.py | 26 +++++++++++++++ sapl/protocoloadm/models.py | 10 +++--- 3 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 sapl/protocoloadm/migrations/0013_auto_20190106_1336.py diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 63474be8e..90fb7c7ce 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -29,12 +29,11 @@ from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, TIPOS_PROTOCOLO = [('0', 'Recebido'), ('1', 'Enviado'), - ('2', 'Interno'), ('', '---------')] + ('2', 'Interno')] TIPOS_PROTOCOLO_CREATE = [ ('0', 'Recebido'), ('1', 'Enviado'), ('2', 'Interno')] -NATUREZA_PROCESSO = [('', '---------'), - ('0', 'Administrativo'), +NATUREZA_PROCESSO = [('0', 'Administrativo'), ('1', 'Legislativo')] @@ -68,13 +67,18 @@ class AcompanhamentoDocumentoForm(ModelForm): class ProtocoloFilterSet(django_filters.FilterSet): - ano = django_filters.ChoiceFilter(required=False, - label='Ano', - choices=choice_anos_com_protocolo) + ano = django_filters.ChoiceFilter( + required=False, + label='Ano', + choices=choice_anos_com_protocolo) - assunto_ementa = django_filters.CharFilter(lookup_expr='icontains') + assunto_ementa = django_filters.CharFilter( + label=_('Assunto'), + lookup_expr='icontains') - interessado = django_filters.CharFilter(lookup_expr='icontains') + interessado = django_filters.CharFilter( + label=_('Interessado'), + lookup_expr='icontains') autor = django_filters.CharFilter(widget=forms.HiddenInput()) @@ -91,7 +95,7 @@ class ProtocoloFilterSet(django_filters.FilterSet): widget=forms.Select( attrs={'class': 'selector'})) - o = AnoNumeroOrderingFilter() + o = AnoNumeroOrderingFilter(help_text='') class Meta: filter_overrides = {models.DateTimeField: { @@ -110,9 +114,6 @@ class ProtocoloFilterSet(django_filters.FilterSet): def __init__(self, *args, **kwargs): super(ProtocoloFilterSet, self).__init__(*args, **kwargs) - self.filters['autor'].label = 'Tipo de Matéria' - self.filters['assunto_ementa'].label = 'Assunto' - row1 = to_row( [('numero', 4), ('ano', 4), @@ -136,9 +137,7 @@ class ProtocoloFilterSet(django_filters.FilterSet): 'Limpar Autor', css_class='btn btn-primary btn-sm'), 10)]) row5 = to_row( - [('tipo_processo', 12)]) - row6 = to_row( - [('o', 12)]) + [('tipo_processo', 6), ('o', 6)]) self.form.helper = FormHelper() self.form.helper.form_method = 'GET' @@ -146,9 +145,10 @@ class ProtocoloFilterSet(django_filters.FilterSet): Fieldset(_('Pesquisar Protocolo'), row1, row2, row3, + row5, HTML(autor_label), HTML(autor_modal), - row4, row5, row6, + row4, form_actions(label='Pesquisar')) ) diff --git a/sapl/protocoloadm/migrations/0013_auto_20190106_1336.py b/sapl/protocoloadm/migrations/0013_auto_20190106_1336.py new file mode 100644 index 000000000..3cd58e085 --- /dev/null +++ b/sapl/protocoloadm/migrations/0013_auto_20190106_1336.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2019-01-06 15:36 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0012_auto_20190104_1021'), + ] + + operations = [ + migrations.AlterField( + model_name='protocolo', + name='tipo_documento', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='protocoloadm.TipoDocumentoAdministrativo', verbose_name='Tipo de Documento'), + ), + migrations.AlterField( + model_name='protocolo', + name='tipo_materia', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='materia.TipoMateriaLegislativa', verbose_name='Tipo de Matéria'), + ), + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 1b061fa18..438037205 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -1,8 +1,8 @@ -import reversion from django.db import models from django.utils import timezone 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 TipoMateriaLegislativa, UnidadeTramitacao @@ -78,13 +78,13 @@ class Protocolo(models.Model): blank=True, null=True, on_delete=models.PROTECT, - verbose_name=_('Tipo de documento')) + verbose_name=_('Tipo de Documento')) tipo_materia = models.ForeignKey( TipoMateriaLegislativa, blank=True, null=True, on_delete=models.PROTECT, - verbose_name=_('Tipo Matéria')) + verbose_name=_('Tipo de Matéria')) numero_paginas = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Número de Páginas')) observacao = models.TextField( @@ -299,10 +299,12 @@ class TramitacaoAdministrativo(models.Model): 'documento': self.documento, 'status': self.status } + @reversion.register() class AcompanhamentoDocumento(models.Model): usuario = models.CharField(max_length=50) - documento = models.ForeignKey(DocumentoAdministrativo, on_delete=models.CASCADE) + documento = models.ForeignKey( + DocumentoAdministrativo, on_delete=models.CASCADE) email = models.EmailField( max_length=100, verbose_name=_('E-mail')) data_cadastro = models.DateField(auto_now_add=True) From a19a8c0b1b0fbdc8d4dfed3c94a082a49e84c1a8 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 14:08:36 -0200 Subject: [PATCH 057/222] Refatora form de pesquisa de Documentos Administrativos --- sapl/protocoloadm/forms.py | 51 +++++++++++++++++++++----------------- sapl/utils.py | 5 ++++ 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 90fb7c7ce..2b43e7ab3 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -20,7 +20,8 @@ from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, - choice_anos_com_protocolo) + choice_anos_com_protocolo, + choice_anos_com_documentoadministrativo) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, @@ -37,9 +38,7 @@ NATUREZA_PROCESSO = [('0', 'Administrativo'), ('1', 'Legislativo')] -EM_TRAMITACAO = [('', '---------'), - (0, 'Sim'), - (1, 'Não')] +EM_TRAMITACAO = [(0, 'Sim'), (1, 'Não')] class AcompanhamentoDocumentoForm(ModelForm): @@ -155,19 +154,24 @@ class ProtocoloFilterSet(django_filters.FilterSet): class DocumentoAdministrativoFilterSet(django_filters.FilterSet): - ano = django_filters.ChoiceFilter(required=False, - label='Ano', - choices=RANGE_ANOS) + ano = django_filters.ChoiceFilter( + required=False, + label='Ano', + choices=choice_anos_com_documentoadministrativo) tramitacao = django_filters.ChoiceFilter(required=False, label='Em Tramitação?', - choices=EM_TRAMITACAO) + choices=YES_NO_CHOICES) - assunto = django_filters.CharFilter(lookup_expr='icontains') + assunto = django_filters.CharFilter( + label=_('Assunto'), + lookup_expr='icontains') - interessado = django_filters.CharFilter(lookup_expr='icontains') + interessado = django_filters.CharFilter( + label=_('Interessado'), + lookup_expr='icontains') - o = AnoNumeroOrderingFilter() + o = AnoNumeroOrderingFilter(help_text='') class Meta: filter_overrides = {models.DateField: { @@ -190,37 +194,38 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): local_atual = 'tramitacaoadministrativo__unidade_tramitacao_destino' self.filters['tipo'].label = 'Tipo de Documento' + self.filters['protocolo__numero'].label = 'Núm. Protocolo' self.filters['tramitacaoadministrativo__status'].label = 'Situação' self.filters[local_atual].label = 'Localização Atual' row1 = to_row( - [('tipo', 6), - ('numero', 6)]) + [('tipo', 8), + ('o', 4), ]) row2 = to_row( - [('ano', 4), + [('numero', 2), + ('ano', 2), ('protocolo__numero', 2), ('numero_externo', 2), ('data', 4)]) row3 = to_row( - [('interessado', 4), - ('assunto', 4), - ('tramitacao', 4)]) + [('interessado', 6), + ('assunto', 6)]) row4 = to_row( - [('tramitacaoadministrativo__unidade_tramitacao_destino', 6), - ('tramitacaoadministrativo__status', 6)]) - - row5 = to_row( - [('o', 12)]) + [ + ('tramitacao', 2), + ('tramitacaoadministrativo__status', 5), + ('tramitacaoadministrativo__unidade_tramitacao_destino', 5), + ]) self.form.helper = FormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Pesquisar Documento'), row1, row2, - row3, row4, row5, + row3, row4, form_actions(label='Pesquisar')) ) diff --git a/sapl/utils.py b/sapl/utils.py index c812fdcb9..b1970c46b 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -369,6 +369,11 @@ def choice_anos_com_protocolo(): return choice_anos(Protocolo) +def choice_anos_com_documentoadministrativo(): + from sapl.protocoloadm.models import DocumentoAdministrativo + return choice_anos(DocumentoAdministrativo) + + def choice_anos_com_sessaoplenaria(): try: from sapl.sessao.models import SessaoPlenaria From 94fc4db6260389b97ea8e36bc33d58ae2608a7a4 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 14:19:32 -0200 Subject: [PATCH 058/222] corrige form de cadastro de documento administrativo --- sapl/protocoloadm/forms.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 2b43e7ab3..9e8920f7f 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -21,7 +21,7 @@ from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, choice_anos_com_protocolo, - choice_anos_com_documentoadministrativo) + choice_anos_com_documentoadministrativo, ANO_CHOICES) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, @@ -707,12 +707,13 @@ class DocumentoAdministrativoForm(ModelForm): data = forms.DateField(initial=timezone.now) - ano_protocolo = forms.ChoiceField(required=False, - label=Protocolo._meta. - get_field('ano').verbose_name, - choices=RANGE_ANOS, - widget=forms.Select( - attrs={'class': 'selector'})) + ano_protocolo = forms.ChoiceField( + required=False, + label=Protocolo._meta. + get_field('ano').verbose_name, + choices=[('', '---------')] + choice_anos_com_protocolo(), + widget=forms.Select( + attrs={'class': 'selector'})) numero_protocolo = forms.IntegerField(required=False, label=Protocolo._meta. @@ -829,7 +830,7 @@ class DocumentoAdministrativoForm(ModelForm): def __init__(self, *args, **kwargs): row1 = to_row( - [('tipo', 4), ('numero', 4), ('ano', 4)]) + [('tipo', 6), ('numero', 3), ('ano', 3)]) row2 = to_row( [('data', 4), ('numero_protocolo', 4), ('ano_protocolo', 4)]) @@ -838,7 +839,7 @@ class DocumentoAdministrativoForm(ModelForm): [('assunto', 12)]) row4 = to_row( - [('interessado', 8), ('tramitacao', 2), (InlineRadios('restrito'), 2)]) + [('interessado', 7), ('tramitacao', 2), (InlineRadios('restrito'), 3)]) row5 = to_row( [('texto_integral', 12)]) From ae370faf189a7318cc821f9d45b45148ae1c3df3 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 17:02:45 -0200 Subject: [PATCH 059/222] altera teste de documento administrativo inexistente --- sapl/protocoloadm/tests/test_protocoloadm.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index 2f61d359f..d61d7b2b3 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -1,10 +1,10 @@ from datetime import date, timedelta -import pytest from django.core.urlresolvers import reverse from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy +import pytest from sapl.materia.models import UnidadeTramitacao from sapl.protocoloadm.forms import (AnularProcoloAdmForm, @@ -368,6 +368,9 @@ def test_documento_administrativo_invalido(): def test_documento_administrativo_protocolo_inexistente(): tipo = mommy.make(TipoDocumentoAdministrativo) + protocolo = mommy.make(Protocolo, + ano=2017, + numero=10) form = DocumentoAdministrativoForm(data={'ano': '2017', 'tipo': str(tipo.pk), From 6c3ca7e57b4ab027f4f76147802e7be14fa0f3d8 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 7 Jan 2019 00:03:10 -0200 Subject: [PATCH 060/222] corrige erro apontado pelo teste de doc adms inexistentes --- sapl/protocoloadm/forms.py | 6 +++--- sapl/protocoloadm/tests/test_protocoloadm.py | 7 +++++-- sapl/utils.py | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 9e8920f7f..9a9bda40b 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -20,8 +20,8 @@ from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, - choice_anos_com_protocolo, - choice_anos_com_documentoadministrativo, ANO_CHOICES) + choice_anos_com_protocolo, choice_force_optional, + choice_anos_com_documentoadministrativo) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, @@ -711,7 +711,7 @@ class DocumentoAdministrativoForm(ModelForm): required=False, label=Protocolo._meta. get_field('ano').verbose_name, - choices=[('', '---------')] + choice_anos_com_protocolo(), + choices=choice_force_optional(choice_anos_com_protocolo), widget=forms.Select( attrs={'class': 'selector'})) diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index d61d7b2b3..2a4c9f53c 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -1,6 +1,7 @@ from datetime import date, timedelta from django.core.urlresolvers import reverse +from django.utils import timezone from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from model_mommy import mommy @@ -191,7 +192,7 @@ def test_create_tramitacao(admin_client): 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk, 'documento': documento_adm.pk, 'status': status.pk, - 'data_tramitacao': date.today() + timedelta( + 'data_tramitacao': timezone.now().date() + timedelta( days=1)}, follow=True) @@ -370,7 +371,9 @@ def test_documento_administrativo_protocolo_inexistente(): tipo = mommy.make(TipoDocumentoAdministrativo) protocolo = mommy.make(Protocolo, ano=2017, - numero=10) + numero=10, + anulado=False, + tipo_documento=tipo) form = DocumentoAdministrativoForm(data={'ano': '2017', 'tipo': str(tipo.pk), diff --git a/sapl/utils.py b/sapl/utils.py index b1970c46b..ee8271b4f 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -387,6 +387,26 @@ def choice_anos_com_sessaoplenaria(): return [] +def choice_force_optional(callable): + """ Django-filter faz algo que tenha o mesmo sentido em ChoiceFilter, + no entanto, as funções choice_anos_... podem ser usadas em formulários + comuns de adição e/ou edição, com a particularidade de terem + required=False. + Neste caso para ser possível contar com a otimização de apenas mostrar anos + que estejam na base de dados e ainda colocar o item opcional '---------', + é necessário encapsular então, as funções choice_anos_... com a + esta função choice_force_optional... isso ocorre e foi aplicado + inicialmente no cadastro de documentos administrativos onde tem-se + opcionalmente a possibilidade de colocar o ano do protocolo. + Em ChoiceFilter choice_force_optional não deve ser usado pois duplicaria + o item opcional '---------' já que ChoiceFilter já o adiciona, como dito + anteriormente. + """ + def _func(): + return [('', '---------')] + callable() + return _func + + TIPOS_TEXTO_PERMITIDOS = ( 'application/vnd.oasis.opendocument.text', 'application/x-vnd.oasis.opendocument.text', From 0605581e2ede90a2161b2c48f554b73297416857 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 7 Jan 2019 09:45:39 -0200 Subject: [PATCH 061/222] =?UTF-8?q?remove=20duplicidade=20de=20c=C3=B3digo?= =?UTF-8?q?=20de=20filter=5Foverrides?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/forms.py | 49 ++++++------------------------------- sapl/materia/forms.py | 34 ++++--------------------- sapl/norma/forms.py | 8 +----- sapl/protocoloadm/forms.py | 18 +++----------- sapl/protocoloadm/models.py | 5 ++-- sapl/utils.py | 16 ++++++++++++ 6 files changed, 36 insertions(+), 94 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 5aa3315fb..5b246a47f 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -32,7 +32,8 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, ChoiceWithoutValidationField, ImageThumbnailFileInput, RangeWidgetOverride, autor_label, autor_modal, models_with_gr_for_model, qs_override_django_filter, - choice_anos_com_normas, choice_anos_com_materias) + choice_anos_com_normas, choice_anos_com_materias, + FilterOverridesMetaMixin) from .models import AppConfig, CasaLegislativa @@ -674,13 +675,7 @@ class AutorFormForAdmin(AutorForm): class RelatorioAtasFilterSet(django_filters.FilterSet): - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = SessaoPlenaria fields = ['data_inicio'] @@ -714,12 +709,6 @@ class RelatorioNormasMesFilterSet(django_filters.FilterSet): choices=choice_anos_com_normas) class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Ano')), - 'widget': RangeWidgetOverride} - }} model = NormaJuridica fields = ['ano'] @@ -784,13 +773,7 @@ class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet): class RelatorioPresencaSessaoFilterSet(django_filters.FilterSet): - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = SessaoPlenaria fields = ['data_inicio'] @@ -822,13 +805,7 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): parent = super(RelatorioHistoricoTramitacaoFilterSet, self).qs return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'tramitacao__unidade_tramitacao_local', 'tramitacao__status', 'tramitacao__data_tramitacao'] @@ -861,13 +838,7 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet): parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero') - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'tramitacao__unidade_tramitacao_local', 'tramitacao__status', 'tramitacao__data_fim_prazo'] @@ -1034,13 +1005,7 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet): return parent.distinct().filter(autoria__primeiro_autor=True)\ .order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero') - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'data_apresentacao'] diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 06d5bada8..a043d024d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -45,7 +45,7 @@ from sapl.utils import (YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO, MateriaPesquisaOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, gerar_hash_arquivo, models_with_gr_for_model, qs_override_django_filter, - choice_anos_com_materias) + choice_anos_com_materias, FilterOverridesMetaMixin) from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, DocumentoAcessorio, Numeracao, Proposicao, Relatoria, @@ -806,13 +806,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): choices=CHOICE_TIPO_LISTAGEM, label=_('Tipo da Listagem do Resultado da Pesquisa')) - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial / Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['numero', 'numero_protocolo', @@ -1104,13 +1098,7 @@ class AutoriaMultiCreateForm(Form): class AcessorioEmLoteFilterSet(django_filters.FilterSet): - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'data_apresentacao'] @@ -1134,13 +1122,7 @@ class AcessorioEmLoteFilterSet(django_filters.FilterSet): class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet): - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'data_apresentacao'] @@ -1165,13 +1147,7 @@ class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet): class TramitacaoEmLoteFilterSet(django_filters.FilterSet): - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'data_apresentacao', 'tramitacao__status', 'tramitacao__unidade_tramitacao_destino'] diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index cd5a091a1..512308e4f 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -57,13 +57,7 @@ class NormaFilterSet(django_filters.FilterSet): o = NormaPesquisaOrderingFilter(help_text='') - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = NormaJuridica fields = ['tipo', 'numero', 'ano', 'data', 'data_vigencia', 'data_publicacao', 'ementa', 'assuntos'] diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 9a9bda40b..2a324543b 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -96,13 +96,7 @@ class ProtocoloFilterSet(django_filters.FilterSet): o = AnoNumeroOrderingFilter(help_text='') - class Meta: - filter_overrides = {models.DateTimeField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': 'Data (%s)' % (_('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = Protocolo fields = ['numero', 'tipo_documento', @@ -113,6 +107,8 @@ class ProtocoloFilterSet(django_filters.FilterSet): def __init__(self, *args, **kwargs): super(ProtocoloFilterSet, self).__init__(*args, **kwargs) + self.filters['timestamp'].label = 'Data (Inicial - Final)' + row1 = to_row( [('numero', 4), ('ano', 4), @@ -173,13 +169,7 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): o = AnoNumeroOrderingFilter(help_text='') - class Meta: - filter_overrides = {models.DateField: { - 'filter_class': django_filters.DateFromToRangeFilter, - 'extra': lambda f: { - 'label': 'Data (%s)' % (_('Inicial - Final')), - 'widget': RangeWidgetOverride} - }} + class Meta(FilterOverridesMetaMixin): model = DocumentoAdministrativo fields = ['tipo', 'numero', diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 438037205..6d3d90671 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -56,10 +56,11 @@ class Protocolo(models.Model): null=False, choices=RANGE_ANOS, verbose_name=_('Ano do Protocolo')) - # TODO: Remover esses dois campos após migração, - # TODO: pois timestamp supre a necessidade + + # FIXME: https://github.com/interlegis/sapl/issues/2337 data = models.DateField(null=True, blank=True) hora = models.TimeField(null=True, blank=True) + # Não foi utilizado auto_now_add=True em timestamp porque # ele usa datetime.now que não é timezone aware. timestamp = models.DateTimeField(default=timezone.now) diff --git a/sapl/utils.py b/sapl/utils.py index ee8271b4f..def839eb1 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -16,6 +16,7 @@ from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRel, GenericRelation) from django.core.exceptions import ValidationError from django.core.mail import get_connection +from django.db import models from django.db.models import Q from django.utils import six, timezone from django.utils.translation import ugettext_lazy as _ @@ -407,6 +408,21 @@ def choice_force_optional(callable): return _func +FILTER_OVERRIDES_DATEFIELD = { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride + } +} + + +class FilterOverridesMetaMixin: + filter_overrides = { + models.DateField: FILTER_OVERRIDES_DATEFIELD + } + + TIPOS_TEXTO_PERMITIDOS = ( 'application/vnd.oasis.opendocument.text', 'application/x-vnd.oasis.opendocument.text', From 0b9feaf5ce0ce76c7d06a92ca1ef46a2d4bdb833 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 7 Jan 2019 17:13:41 -0200 Subject: [PATCH 062/222] add imports --- sapl/norma/forms.py | 2 +- sapl/protocoloadm/forms.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index 512308e4f..c49f94889 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -18,7 +18,7 @@ from sapl.materia.forms import choice_anos_com_materias from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.utils import NormaPesquisaOrderingFilter, RangeWidgetOverride,\ - choice_anos_com_normas + choice_anos_com_normas, FilterOverridesMetaMixin from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada, TipoNormaJuridica, AutoriaNorma) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 2a324543b..d0c812958 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -21,7 +21,8 @@ from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, choice_anos_com_protocolo, choice_force_optional, - choice_anos_com_documentoadministrativo) + choice_anos_com_documentoadministrativo, + FilterOverridesMetaMixin) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, From 9869d4d4c4bcaef0afd793f3cb8dc74517914c89 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 7 Jan 2019 20:35:27 -0200 Subject: [PATCH 063/222] =?UTF-8?q?retira=20field=20search=20inv=C3=A1lido?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/parlamentares/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 8c07914c4..b1ee14629 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -281,7 +281,6 @@ class Parlamentar(models.Model): ('nome_completo', '__icontains'), ('nome_parlamentar', '__icontains'), ('filiacao__partido__sigla', '__icontains'), - ('filiacao__partido', '__exact'), )) class Meta: From e9d64207f2fd1b1437267106618a5e5ced42ed93 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 9 Jan 2019 17:30:54 -0200 Subject: [PATCH 064/222] Fix #2447 --- sapl/materia/views.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 07911f09b..0f856ede3 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -26,7 +26,7 @@ import weasyprint import sapl from sapl.base.email_utils import do_envia_email_confirmacao -from sapl.base.models import Autor, CasaLegislativa +from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig from sapl.base.signals import tramitacao_signal from sapl.comissoes.models import Comissao, Participacao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, @@ -783,16 +783,23 @@ class ProposicaoCrud(Crud): msg_error = _('Proposição não possui nenhum tipo de ' 'Texto associado.') else: - p.data_devolucao = None - p.data_envio = timezone.now() - p.save() - if p.texto_articulado.exists(): ta = p.texto_articulado.first() ta.privacidade = STATUS_TA_IMMUTABLE_RESTRICT ta.editing_locked = True ta.save() + receber_recibo = BaseAppConfig.attr( + 'receber_recibo_proposicao') + + if not receber_recibo: + ta = p.texto_articulado.first() + p.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(p.pk) + + p.data_devolucao = None + p.data_envio = timezone.now() + p.save() + messages.success(request, _( 'Proposição enviada com sucesso.')) try: From 05f1bb923912b051d7710952a0b0792bdc1187da Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Thu, 10 Jan 2019 18:42:30 -0200 Subject: [PATCH 065/222] Release: 3.1.141 --- docker-compose.yml | 2 +- sapl/templates/base.html | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b379cf46c..c796253d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.140 + image: interlegis/sapl:3.1.141 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 59f9919f1..a738aa276 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -184,7 +184,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.140 + Release: 3.1.141

diff --git a/setup.py b/setup.py index 6b7c5a248..61de04956 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.140', + version='3.1.141', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From bd2bc3a4f7d71f6f7b387f13694defcebaca93ea Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 04:39:39 -0200 Subject: [PATCH 066/222] bump django para 1.11 --- requirements/requirements.txt | 17 +++++++++-------- setup.py | 11 ++++++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 3c4d2e135..69cb803f5 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,18 +1,19 @@ +django>=1.11,<2.0 +django-haystack==2.8.1 +django-bootstrap3==11.0.0 +django-filter==2.0.0 +djangorestframework==3.9.0 + dj-database-url==0.4.1 -django-haystack==2.6.0 -django>=1.10,<1.11 -django-bootstrap3==7.0.1 django-bower==5.2.0 django-braces==1.9.0 django-compressor==2.0 django-crispy-forms==1.6.1 django-extensions==1.9.8 django-extra-views==0.11.0 -django-filter==1.0.0 django-floppyforms==1.6.2 django-model-utils==3.1.1 django-sass-processor==0.5.8 -djangorestframework==3.4.0 easy-thumbnails==2.5 django-image-cropping==1.2 libsass==0.11.1 @@ -32,6 +33,6 @@ whoosh==2.7.4 django-speedinfo==1.3.5 django-reversion-compare==0.8.4 -git+git://github.com/interlegis/trml2pdf.git -git+git://github.com/jasperlittle/django-rest-framework-docs -git+git://github.com/rubgombar1/django-admin-bootstrapped.git \ No newline at end of file +#git+git://github.com/interlegis/trml2pdf.git +#git+git://github.com/jasperlittle/django-rest-framework-docs +#git+git://github.com/rubgombar1/django-admin-bootstrapped.git \ No newline at end of file diff --git a/setup.py b/setup.py index 61de04956..a64217d42 100644 --- a/setup.py +++ b/setup.py @@ -9,21 +9,22 @@ with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme: os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) install_requires = [ + 'django>=1.11,<2.0', + 'django-haystack==2.8.1', + 'django-bootstrap3==11.0.0', + 'django-filter==2.0.0', + 'djangorestframework==3.9.0', + 'dj-database-url==0.4.1', - 'django-haystack==2.6.0', - 'django>=1.10,<1.11', - 'django-bootstrap3==7.0.1', 'django-bower==5.2.0', 'django-braces==1.9.0', 'django-compressor==2.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==3.1.1', 'django-sass-processor==0.5.8', - 'djangorestframework==3.4.0', 'drfdocs', 'easy-thumbnails==2.5', 'django-image-cropping==1.1.0', From 55963883265c9165aa62a8bf62e030395eb7d80b Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 04:40:44 -0200 Subject: [PATCH 067/222] =?UTF-8?q?altera=C3=A7=C3=B5es=20m=C3=ADnimas=20p?= =?UTF-8?q?ara=20executar=20manage=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/api/forms.py | 2 +- sapl/api/views.py | 5 +++-- sapl/settings.py | 7 ++++--- sapl/utils.py | 21 ++++++++++----------- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/sapl/api/forms.py b/sapl/api/forms.py index fecfbf598..0c8a1889f 100644 --- a/sapl/api/forms.py +++ b/sapl/api/forms.py @@ -6,8 +6,8 @@ from django.forms.widgets import MultiWidget, TextInput from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django_filters.filters import CharFilter, ModelChoiceFilter, DateFilter +from django_filters.rest_framework.filterset import FilterSet from rest_framework import serializers -from rest_framework.filters import FilterSet from sapl.base.models import Autor, TipoAutor from sapl.parlamentares.models import Legislatura diff --git a/sapl/api/views.py b/sapl/api/views.py index b8cafc1dd..336bb23d7 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -1,9 +1,10 @@ import logging + from django.contrib.contenttypes.models import ContentType from django.db.models import Q from django.http import Http404 from django.utils.translation import ugettext_lazy as _ -from rest_framework.filters import DjangoFilterBackend +from django_filters.rest_framework.backends import DjangoFilterBackend from rest_framework.generics import ListAPIView from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.permissions import (AllowAny, IsAuthenticated, @@ -175,7 +176,7 @@ class AutoresProvaveisListView(ListAPIView): serializer_class = ChoiceSerializer def get_queryset(self): - + params = {'content_type__isnull': False} username = self.request.user.username tipo = '' diff --git a/sapl/settings.py b/sapl/settings.py index 80bf18273..63f18e325 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -90,6 +90,7 @@ INSTALLED_APPS = ( 'haystack', 'sass_processor', 'rest_framework', + 'django_filters', 'reversion', 'reversion_compare', 'whoosh', @@ -110,7 +111,7 @@ SOLR_URL = config('SOLR_URL', cast=str, default='http://localhost:8983') SOLR_COLLECTION = config('SOLR_COLLECTION', cast=str, default='sapl') if USE_SOLR: - HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' #enable auto-index + HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' # enable auto-index SEARCH_BACKEND = 'haystack.backends.solr_backend.SolrEngine' SEARCH_URL = ('URL', '{}/solr/{}'.format(SOLR_URL, SOLR_COLLECTION)) @@ -118,7 +119,7 @@ if USE_SOLR: HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': SEARCH_BACKEND, - SEARCH_URL[0]: SEARCH_URL[1], + SEARCH_URL[0]: SEARCH_URL[1], 'BATCH_SIZE': 1000, 'TIMEOUT': 60, }, @@ -166,7 +167,7 @@ REST_FRAMEWORK = { "DEFAULT_PAGINATION_CLASS": "sapl.api.pagination.StandardPagination", "DEFAULT_FILTER_BACKENDS": ( "rest_framework.filters.SearchFilter", - "rest_framework.filters.DjangoFilterBackend", + 'django_filters.rest_framework.DjangoFilterBackend', ), } diff --git a/sapl/utils.py b/sapl/utils.py index def839eb1..c884a8c48 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -21,7 +21,6 @@ from django.db.models import Q from django.utils import six, timezone from django.utils.translation import ugettext_lazy as _ import django_filters -from django_filters.filterset import STRICTNESS from easy_thumbnails import source_generators from floppyforms import ClearableFileInput import magic @@ -685,12 +684,12 @@ def qs_override_django_filter(self): valid = self.is_bound and self.form.is_valid() if self.is_bound and not valid: - if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR: + """if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR: raise forms.ValidationError(self.form.errors) - elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS: - self._qs = self.queryset.none() - return self._qs - # else STRICTNESS.IGNORE... ignoring + elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS:""" + self._qs = self.queryset.none() + return self._qs + # else STRICTNESS.IGNORE... ignoring # start with all the results and filter from there qs = self.queryset.all() @@ -703,12 +702,12 @@ def qs_override_django_filter(self): try: value = self.form.fields[name].clean(raw_value) except forms.ValidationError: - if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR: + """if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR: raise - elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS: - self._qs = self.queryset.none() - return self._qs - # else STRICTNESS.IGNORE... ignoring + elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS:""" + self._qs = self.queryset.none() + return self._qs + # else STRICTNESS.IGNORE... ignoring if value is not None: # valid & clean data qs = qs._next_is_sticky() From b4666807ab6c9f16101a2dd5cc832d580ef06c01 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 5 Jan 2019 04:52:22 -0200 Subject: [PATCH 068/222] =?UTF-8?q?adequa=C3=A7=C3=A3o=20de=20c=C3=B3digo?= =?UTF-8?q?=20na=20chamada=20do=20render=20de=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/email_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/base/email_utils.py b/sapl/base/email_utils.py index 024045edd..b41c68402 100644 --- a/sapl/base/email_utils.py +++ b/sapl/base/email_utils.py @@ -18,7 +18,7 @@ def load_email_templates(templates, context={}): emails = [] for t in templates: tpl = loader.get_template(t) - email = tpl.render(Context(context)) + email = tpl.render(context) if t.endswith(".html"): email = email.replace('\n', '').replace('\r', '') emails.append(email) From 243f984a13a60ef441daff8fef9dc8603be773a1 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 16:21:20 -0200 Subject: [PATCH 069/222] remove django-compressor --- requirements/requirements.txt | 11 ++++++----- sapl/base/templatetags/common_tags.py | 15 ++++++++++----- sapl/crud/base.py | 15 +++++++++------ setup.py | 9 +++++---- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 69cb803f5..944b300d7 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,13 +1,12 @@ django>=1.11,<2.0 -django-haystack==2.8.1 django-bootstrap3==11.0.0 +django-haystack==2.8.1 django-filter==2.0.0 djangorestframework==3.9.0 - -dj-database-url==0.4.1 +dj-database-url==0.5.0 django-bower==5.2.0 django-braces==1.9.0 -django-compressor==2.0 + django-crispy-forms==1.6.1 django-extensions==1.9.8 django-extra-views==0.11.0 @@ -35,4 +34,6 @@ django-reversion-compare==0.8.4 #git+git://github.com/interlegis/trml2pdf.git #git+git://github.com/jasperlittle/django-rest-framework-docs -#git+git://github.com/rubgombar1/django-admin-bootstrapped.git \ No newline at end of file +#git+git://github.com/rubgombar1/django-admin-bootstrapped.git + +#django-compressor==2.2 \ No newline at end of file diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 89f781558..884a6968f 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -1,8 +1,4 @@ -import logging - -from compressor.utils import get_class from django import template -from django.conf import settings from django.template.defaultfilters import stringfilter from sapl.base.models import AppConfig @@ -15,6 +11,15 @@ from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO register = template.Library() +def get_class(class_string): + if not hasattr(class_string, '__bases__'): + class_string = str(class_string) + dot = class_string.rindex('.') + mod_name, class_name = class_string[:dot], class_string[dot + 1:] + if class_name: + return getattr(__import__(mod_name, {}, {}, [str('')]), class_name) + + @register.simple_tag def define(arg): return arg @@ -228,7 +233,7 @@ def file_extension(value): def cronometro_to_seconds(value): if not AppConfig.attr('cronometro_' + value): return 0 - + return AppConfig.attr('cronometro_' + value).seconds diff --git a/sapl/crud/base.py b/sapl/crud/base.py index e720b36cd..faa0e1287 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -1,6 +1,6 @@ import logging + from braces.views import FormMessagesMixin -from compressor.utils.decorators import cached_property from crispy_forms.bootstrap import FieldWithButtons, StrictButton from crispy_forms.helper import FormHelper from crispy_forms.layout import Field, Layout @@ -16,6 +16,7 @@ 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.functional import cached_property from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ from django.views.generic import (CreateView, DeleteView, DetailView, ListView, @@ -29,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 + ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ 'list', 'create', 'detail', 'update', 'delete' @@ -558,7 +560,8 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView): fm = model._meta.get_field(fo) except Exception as e: username = self.request.user.username - self.logger.error("user=" + username + ". " + str(e)) + self.logger.error( + "user=" + username + ". " + str(e)) pass if fm and hasattr(fm, 'related_model')\ @@ -824,7 +827,7 @@ class CrudUpdateView(PermissionRequiredContainerCrudMixin, logger = logging.getLogger(__name__) def form_valid(self, form): - + self.object = form.instance try: self.object.modifier = self.request.user @@ -882,12 +885,12 @@ class CrudDeleteView(PermissionRequiredContainerCrudMixin, error_msg2 += '{} - {}, '.format( i._meta.verbose_name, i ) - error_msg2 = error_msg2[:len(error_msg2)-2] + '.' + error_msg2 = error_msg2[:len(error_msg2) - 2] + '.' error_msg += '' - + username = request.user.username self.logger.error("user=" + username + ". Registro não pode ser removido, pois " - "é referenciado por outros registros: " + error_msg2) + "é referenciado por outros registros: " + error_msg2) messages.add_message(request, messages.ERROR, error_msg) diff --git a/setup.py b/setup.py index a64217d42..e44ded347 100644 --- a/setup.py +++ b/setup.py @@ -10,15 +10,14 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) install_requires = [ 'django>=1.11,<2.0', - 'django-haystack==2.8.1', 'django-bootstrap3==11.0.0', + 'django-haystack==2.8.1', 'django-filter==2.0.0', 'djangorestframework==3.9.0', - - 'dj-database-url==0.4.1', + 'dj-database-url==0.5.0', 'django-bower==5.2.0', 'django-braces==1.9.0', - 'django-compressor==2.0', + 'django-crispy-forms==1.6.1', 'django-extensions==1.9.8', 'django-extra-views==0.11.0', @@ -47,6 +46,8 @@ install_requires = [ # 'git+git://github.com/interlegis/trml2pdf.git', # 'git+git://github.com/jasperlittle/django-rest-framework-docs' # 'git+git://github.com/rubgombar1/django-admin-bootstrapped.git'' + + #'django-compressor==2.2', ] setup( name='interlegis-sapl', From 22b87f36ebc8659a6ecaf8831ab0f425206b0993 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 16:49:40 -0200 Subject: [PATCH 070/222] =?UTF-8?q?bump=20django-crispy-forms=20e=20ajuste?= =?UTF-8?q?s=20de=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/requirements.txt | 2 +- sapl/utils.py | 16 ++++++++++++---- setup.py | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 944b300d7..7b6dc25c1 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -6,8 +6,8 @@ djangorestframework==3.9.0 dj-database-url==0.5.0 django-bower==5.2.0 django-braces==1.9.0 +django-crispy-forms==1.7.2 -django-crispy-forms==1.6.1 django-extensions==1.9.8 django-extra-views==0.11.0 django-floppyforms==1.6.2 diff --git a/sapl/utils.py b/sapl/utils.py index c884a8c48..706d5cb65 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -208,19 +208,27 @@ class RangeWidgetOverride(forms.MultiWidget): def __init__(self, attrs=None): widgets = (forms.DateInput(format='%d/%m/%Y', - attrs={'class': 'dateinput', + attrs={'class': 'dateinput form-control', 'placeholder': 'Inicial'}), forms.DateInput(format='%d/%m/%Y', - attrs={'class': 'dateinput', + attrs={'class': 'dateinput form-control', 'placeholder': 'Final'})) super(RangeWidgetOverride, self).__init__(widgets, attrs) def decompress(self, value): if value: return [value.start, value.stop] - return [None, None] + return [] + + def render(self, name, value, attrs=None, renderer=None): + rendered_widgets = [] + for i, x in enumerate(self.widgets): + rendered_widgets.append( + x.render( + '%s_%d' % (name, i), value[i] if value else '' + ) + ) - def format_output(self, rendered_widgets): html = '
%s
%s
'\ % tuple(rendered_widgets) return '
%s
' % html diff --git a/setup.py b/setup.py index e44ded347..018ff1002 100644 --- a/setup.py +++ b/setup.py @@ -17,8 +17,8 @@ install_requires = [ 'dj-database-url==0.5.0', 'django-bower==5.2.0', 'django-braces==1.9.0', + 'django-crispy-forms==1.7.2', - 'django-crispy-forms==1.6.1', 'django-extensions==1.9.8', 'django-extra-views==0.11.0', 'django-floppyforms==1.6.2', @@ -46,7 +46,7 @@ install_requires = [ # 'git+git://github.com/interlegis/trml2pdf.git', # 'git+git://github.com/jasperlittle/django-rest-framework-docs' # 'git+git://github.com/rubgombar1/django-admin-bootstrapped.git'' - + #'django-compressor==2.2', ] setup( From ca684e006734a94e10af7da367cba0c0db5747f8 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 6 Jan 2019 17:08:34 -0200 Subject: [PATCH 071/222] descomenta libs do requirements --- requirements/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 7b6dc25c1..4b869decc 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -32,8 +32,8 @@ whoosh==2.7.4 django-speedinfo==1.3.5 django-reversion-compare==0.8.4 -#git+git://github.com/interlegis/trml2pdf.git -#git+git://github.com/jasperlittle/django-rest-framework-docs -#git+git://github.com/rubgombar1/django-admin-bootstrapped.git +git+git://github.com/interlegis/trml2pdf.git +git+git://github.com/jasperlittle/django-rest-framework-docs +git+git://github.com/rubgombar1/django-admin-bootstrapped.git #django-compressor==2.2 \ No newline at end of file From 82fb5613c39f991a985f0291af0d6d95c86754d3 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 7 Jan 2019 00:43:54 -0200 Subject: [PATCH 072/222] bump django-floppyforms --- requirements/requirements.txt | 2 +- sapl/sessao/forms.py | 8 +++----- sapl/settings.py | 19 ++++++++++++------- sapl/static/styles/app.scss | 3 +++ .../parlamentares/parlamentares_list.html | 6 ++++-- setup.py | 4 ++-- 6 files changed, 25 insertions(+), 17 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 4b869decc..524549446 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -7,10 +7,10 @@ dj-database-url==0.5.0 django-bower==5.2.0 django-braces==1.9.0 django-crispy-forms==1.7.2 +django-floppyforms==1.7.0 django-extensions==1.9.8 django-extra-views==0.11.0 -django-floppyforms==1.6.2 django-model-utils==3.1.1 django-sass-processor==0.5.8 easy-thumbnails==2.5 diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 35d49e277..68f6d3222 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -3,7 +3,6 @@ from datetime import datetime from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Button, Fieldset, Layout from django import forms -from django.contrib import messages from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db import transaction @@ -12,22 +11,21 @@ from django.forms import ModelForm from django.forms.widgets import CheckboxSelectMultiple from django.utils.translation import ugettext_lazy as _ import django_filters -from floppyforms import widgets from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import form_actions, to_row, SaplFormLayout from sapl.materia.forms import MateriaLegislativaFilterSet from sapl.materia.models import (MateriaLegislativa, StatusTramitacao, TipoMateriaLegislativa) -from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato +from sapl.parlamentares.models import Parlamentar, Mandato from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, MateriaPesquisaOrderingFilter, autor_label, autor_modal, timezone, choice_anos_com_sessaoplenaria) from .models import (Bancada, Bloco, ExpedienteMateria, JustificativaAusencia, Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, - SessaoPlenariaPresenca, TipoJustificativa, TipoResultadoVotacao, - OcorrenciaSessao, RegistroVotacao, RetiradaPauta, TipoRetiradaPauta) + SessaoPlenariaPresenca, TipoResultadoVotacao, + OcorrenciaSessao, RetiradaPauta, TipoRetiradaPauta) MES_CHOICES = RANGE_MESES diff --git a/sapl/settings.py b/sapl/settings.py index 63f18e325..fbc19f53f 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -79,20 +79,25 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', - # more - 'django_extensions', 'djangobower', - 'bootstrap3', # basically for django_admin_bootstrapped + 'bootstrap3', 'crispy_forms', - 'easy_thumbnails', - 'image_cropping', 'floppyforms', - 'haystack', - 'sass_processor', + 'rest_framework', 'django_filters', + + + + 'django_extensions', + 'easy_thumbnails', + 'image_cropping', + 'sass_processor', + 'reversion', 'reversion_compare', + + 'haystack', 'whoosh', 'speedinfo', diff --git a/sapl/static/styles/app.scss b/sapl/static/styles/app.scss index a0540b8e1..f05189142 100644 --- a/sapl/static/styles/app.scss +++ b/sapl/static/styles/app.scss @@ -451,6 +451,9 @@ nav { overflow-x: auto; } } +.lista-parlamentares .table td { + vertical-align: middle; +} @media (min-width: 1092px) and (max-width: 1199px) { .container { diff --git a/sapl/templates/parlamentares/parlamentares_list.html b/sapl/templates/parlamentares/parlamentares_list.html index bc3955b06..43627a9ad 100644 --- a/sapl/templates/parlamentares/parlamentares_list.html +++ b/sapl/templates/parlamentares/parlamentares_list.html @@ -21,7 +21,7 @@ {% if not rows %}

{{ NO_ENTRIES_MSG }}

{% else %} -
+
{% blocktrans with verbose_name_plural=view.verbose_name_plural %}Total de {{ verbose_name_plural }}: {{count}}{% endblocktrans %}
@@ -43,7 +43,9 @@ {% for value, href, obj in value_list %} {% if forloop.first %} {% endif %} - + {% if protocolo.timestamp %} + + {% else %} + + {% endif %} {% if protocolo.tipo_processo == 1 %} diff --git a/sapl/templates/protocoloadm/protocolar_documento.html b/sapl/templates/protocoloadm/protocolar_documento.html index 5cb1fa789..49cf4933f 100644 --- a/sapl/templates/protocoloadm/protocolar_documento.html +++ b/sapl/templates/protocoloadm/protocolar_documento.html @@ -14,3 +14,17 @@ {% block detail_content %} {% crispy form %} {% endblock detail_content %} + +{% block extra_js %} + +{% endblock %} diff --git a/sapl/templates/protocoloadm/protocolar_materia.html b/sapl/templates/protocoloadm/protocolar_materia.html index db3785bd6..2dcb8b4f0 100644 --- a/sapl/templates/protocoloadm/protocolar_materia.html +++ b/sapl/templates/protocoloadm/protocolar_materia.html @@ -26,35 +26,43 @@ } $(document).ready(function() { - function busca_ementa() { - var vincular_materia = $("#id_vincular_materia_1").prop("checked"); - var ano_materia = $("#id_ano_materia").val(); - var numero_materia = $("#id_numero_materia").val(); - var tipo_materia = $("#id_tipo_materia").val(); - var json_data = { - ano : ano_materia, - numero : numero_materia, - tipo : tipo_materia - } - if (vincular_materia === true && ano_materia !== undefined && - numero_materia !== undefined && numero_materia !== "") { - $.getJSON("/protocoloadm/recuperar-materia", json_data, function(data){ - if (data) { - if (data['error'] === undefined){ - $('#id_assunto_ementa').val(data['ementa']); - if (data['autor'] !== undefined) { - $('#id_autor').val(data['autor']); - $('#id_tipo_autor').val(data['tipo_autor']); + $("input[name=data_hora_manual]").change(function(event) { + if (this.value === 'True' && this.checked) + $("#protocolo_data_hora_manual").removeClass('hidden'); + else if (this.value === 'False' && this.checked) + $("#protocolo_data_hora_manual").addClass('hidden'); + }); + $("input[name=data_hora_manual]").trigger('change') + + function busca_ementa() { + var vincular_materia = $("#id_vincular_materia_1").prop("checked"); + var ano_materia = $("#id_ano_materia").val(); + var numero_materia = $("#id_numero_materia").val(); + var tipo_materia = $("#id_tipo_materia").val(); + var json_data = { + ano : ano_materia, + numero : numero_materia, + tipo : tipo_materia + } + if (vincular_materia === true && ano_materia !== undefined && + numero_materia !== undefined && numero_materia !== "") { + $.getJSON("/protocoloadm/recuperar-materia", json_data, function(data){ + if (data) { + if (data['error'] === undefined){ + $('#id_assunto_ementa').val(data['ementa']); + if (data['autor'] !== undefined) { + $('#id_autor').val(data['autor']); + $('#id_tipo_autor').val(data['tipo_autor']); - } - } - } - }) - } + } + } + } + }) + } }; - $("#id_ano_materia").blur(busca_ementa); - $("#id_numero_materia").blur(busca_ementa); - $("#id_tipo_materia").change(busca_ementa); + $("#id_ano_materia").blur(busca_ementa); + $("#id_numero_materia").blur(busca_ementa); + $("#id_tipo_materia").change(busca_ementa); $("#id_tipo_autor").change(function() { var tipo_selecionado = $("#id_tipo_autor").val(); diff --git a/sapl/templates/protocoloadm/protocolo_mostrar.html b/sapl/templates/protocoloadm/protocolo_mostrar.html index 2cac987f3..d22464397 100644 --- a/sapl/templates/protocoloadm/protocolo_mostrar.html +++ b/sapl/templates/protocoloadm/protocolo_mostrar.html @@ -4,6 +4,14 @@ {% load crispy_forms_tags %} {% load static %} +{% block actions %} + + {{ block.super }} + +{% endblock %} + {% block detail_content %} Protocolo: {{ protocolo.numero|stringformat:'06d' }}/{{ protocolo.ano }} - Etiqueta Individual
@@ -12,7 +20,7 @@ {% if protocolo.timestamp %} Data Protocolo: {{ protocolo.timestamp|localtime|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ protocolo.timestamp|localtime|date:"G:i:s" }}
{% else %} - Data Protocolo: {{ protocolo.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ protocolo.hora|date:"G:i:s" }}
+ Data Protocolo: {{ protocolo.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ protocolo.hora|date:"G:i:s" }} - {% if not protocolo.timestamp %} Informado Manualmente por: {{protocolo.user_data_hora_manual}}{% endif %}
{% endif %} {% if protocolo.tipo_processo == 0 %} diff --git a/sapl/utils.py b/sapl/utils.py index 706d5cb65..eb26cadb1 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -18,6 +18,7 @@ from django.core.exceptions import ValidationError from django.core.mail import get_connection from django.db import models from django.db.models import Q +from django.forms.widgets import SplitDateTimeWidget from django.utils import six, timezone from django.utils.translation import ugettext_lazy as _ import django_filters @@ -234,6 +235,23 @@ class RangeWidgetOverride(forms.MultiWidget): return '
%s
' % html +class CustomSplitDateTimeWidget(SplitDateTimeWidget): + def render(self, name, value, attrs=None, renderer=None): + rendered_widgets = [] + for i, x in enumerate(self.widgets): + x.attrs['class'] += ' form-control' + rendered_widgets.append( + x.render( + '%s_%d' % (name, i), self.decompress( + value)[i] if value else '' + ) + ) + + html = '
%s
%s
'\ + % tuple(rendered_widgets) + return '
%s
' % html + + def register_all_models_in_admin(module_name, exclude_list=[]): appname = module_name.split('.') appname = appname[1] if appname[0] == 'sapl' else appname[0] From 5bbfbc4b74819351d8474a9d4f5fd42234b7f0eb Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Thu, 10 Jan 2019 20:51:51 -0200 Subject: [PATCH 087/222] =?UTF-8?q?add=20informa=C3=A7=C3=A3o=20na=20lista?= =?UTF-8?q?=20de=20protocolos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/protocoloadm/protocolo_filter.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/protocoloadm/protocolo_filter.html b/sapl/templates/protocoloadm/protocolo_filter.html index 316003075..d3d1968d8 100644 --- a/sapl/templates/protocoloadm/protocolo_filter.html +++ b/sapl/templates/protocoloadm/protocolo_filter.html @@ -47,7 +47,7 @@ {% if p.timestamp%} Data Protocolo: {{ p.timestamp|localtime|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.timestamp|localtime|date:"G:i:s" }}
{% else %} - Data Protocolo: {{ p.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.hora|date:"G:i:s" }}
+ Data Protocolo: {{ p.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.hora|date:"G:i:s" }} - {% if not p.timestamp %} Informado Manualmente por: {{p.user_data_hora_manual}}{% endif %}
{% endif %} {% if p.tipo_processo == 0 %} Interessado: {{ p.interessado|default_if_none:"Não informado" }}
From 091f566688363e3c8693c8d315e1b4ed898dfe38 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Fri, 11 Jan 2019 12:07:40 -0200 Subject: [PATCH 088/222] HOT-FIX: insere EMAIL_SEND_USER em docs e envs. --- config/env-sample | 1 + config/env_dockerfile | 1 + docker-compose.yml | 1 + docs/instalacao31.rst | 1 + sapl/.env_test | 1 + sapl/env-backup | 1 + 6 files changed, 6 insertions(+) diff --git a/config/env-sample b/config/env-sample index bde081a92..aeb8c38c4 100644 --- a/config/env-sample +++ b/config/env-sample @@ -5,4 +5,5 @@ EMAIL_USE_TLS = True EMAIL_PORT = 587 EMAIL_HOST = '' EMAIL_HOST_USER = '' +EMAIL_SEND_USER = '' EMAIL_HOST_PASSWORD = '' diff --git a/config/env_dockerfile b/config/env_dockerfile index c83fc88f1..134beb274 100644 --- a/config/env_dockerfile +++ b/config/env_dockerfile @@ -5,4 +5,5 @@ EMAIL_USE_TLS = True EMAIL_PORT = 587 EMAIL_HOST = '' EMAIL_HOST_USER = '' +EMAIL_SEND_USER = '' EMAIL_HOST_PASSWORD = '' diff --git a/docker-compose.yml b/docker-compose.yml index c796253d4..51af52a6b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,6 +21,7 @@ sapl: EMAIL_USE_TLS: 'False' EMAIL_HOST: smtp.dominio.net EMAIL_HOST_USER: usuariosmtp + EMAIL_SEND_USER: usuariosmtp EMAIL_HOST_PASSWORD: senhasmtp TZ: America/Sao_Paulo volumes: diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index e904f8d6c..6e9146ee4 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -147,6 +147,7 @@ Criação da `SECRET_KEY Date: Wed, 16 Jan 2019 10:57:00 -0200 Subject: [PATCH 089/222] HOT-FIX: corrige form e view no cadastro de Frentes --- sapl/parlamentares/views.py | 11 ++++++++++- sapl/templates/parlamentares/frente_form.html | 19 +++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/sapl/parlamentares/views.py b/sapl/parlamentares/views.py index c47d36566..7b09c4067 100644 --- a/sapl/parlamentares/views.py +++ b/sapl/parlamentares/views.py @@ -301,9 +301,18 @@ class FrenteCrud(Crud): def form_valid(self, form): return super(Crud.CreateView, self).form_valid(form) + class DetailView(Crud.DetailView): + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['subnav_template_name'] = '' + return context + class UpdateView(Crud.UpdateView): form_class = FrenteForm - + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['subnav_template_name'] = '' + return context class MandatoCrud(MasterDetailCrud): diff --git a/sapl/templates/parlamentares/frente_form.html b/sapl/templates/parlamentares/frente_form.html index bbab780ae..1d71f6b76 100644 --- a/sapl/templates/parlamentares/frente_form.html +++ b/sapl/templates/parlamentares/frente_form.html @@ -57,16 +57,15 @@ function selecionar_parlamentares_frente() { // Seleciona automaticamente todos os parlamentares // que já estão presentes naquela frente - var update_view = {{ update_view }} - if (update_view == 1) { - var frente_id = {{ object.id }} - $.get("/sistema/frente/parlamentares-frente-selected", - {frente_id: frente_id}, - function (data) { - id_list = data['id_list']; - $("div.controls select").val(id_list); - }); - } + {% if object.id %} + var frente_id = {{ object.id }} + $.get("/sistema/frente/parlamentares-frente-selected", + {frente_id: frente_id}, + function (data) { + id_list = data['id_list']; + $("div.controls select").val(id_list); + }); + {% endif %} } function atualiza_parlamentares() { From a07e9ca39e156a3b0dd31dd0076feaf61f06fbdc Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 16 Jan 2019 11:11:34 -0200 Subject: [PATCH 090/222] HOT-FIX: corrige html em frente_form.html --- sapl/static/js/app.js | 2 +- sapl/templates/parlamentares/frente_form.html | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sapl/static/js/app.js b/sapl/static/js/app.js index d3616a8b5..c30f357bd 100644 --- a/sapl/static/js/app.js +++ b/sapl/static/js/app.js @@ -190,7 +190,7 @@ function OptionalCustomFrontEnd() { if (_label.length === 0) { _label = $('label[for='+this.id+']'); if (_label.length === 0) { - _label = $('').insertBefore(this) + _label = $('
- {% if not mes in meses_sem_acesso %} @@ -53,10 +48,6 @@ {% endfor %}
- {% else %} -

{% trans 'Nenhuma norma deste mês teve acessos.'%}

-

- {% endif %}
{% endfor %} {% endif %} From f84ac62c4a5b7fc1ca538125b7b2b9c4c0cb9bae Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Mon, 21 Jan 2019 17:36:26 -0200 Subject: [PATCH 103/222] adiciona ultimo ano com norma como default em relatorios de normas por mes --- sapl/base/forms.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 798e24e11..c63163801 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -704,11 +704,17 @@ class RelatorioAtasFilterSet(django_filters.FilterSet): ) +def ultimo_ano_com_norma(): + anos_normas = choice_anos_com_normas() + return anos_normas[0] + + class RelatorioNormasMesFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, label='Ano da Norma', - choices=choice_anos_com_normas) + choices=choice_anos_com_normas, + initial=ultimo_ano_com_norma) class Meta: model = NormaJuridica @@ -765,11 +771,6 @@ class EstatisticasAcessoNormasForm(Form): return self.cleaned_data -def ultimo_ano_com_norma(): - anos_normas = choice_anos_com_normas() - return anos_normas[0] - - class RelatorioNormasVigenciaFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter(required=True, From 53507cc01c52a102349434ff0c50cb8a303deef4 Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Mon, 21 Jan 2019 17:46:05 -0200 Subject: [PATCH 104/222] fix commit #f84ac62 --- sapl/base/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index c63163801..d603ffc45 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -706,8 +706,11 @@ class RelatorioAtasFilterSet(django_filters.FilterSet): def ultimo_ano_com_norma(): anos_normas = choice_anos_com_normas() - return anos_normas[0] + if anos_normas: + return anos_normas[0] + return '' + class RelatorioNormasMesFilterSet(django_filters.FilterSet): From 35780b0faceffaabfa080c453189928224e752a7 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 21 Jan 2019 21:11:35 -0200 Subject: [PATCH 105/222] move javascript para dentro do bloco correto --- sapl/templates/base/login.html | 13 +++++-------- sapl/templates/compilacao/text_list.html | 2 +- .../compilacao/text_list__embedded.html | 11 ++++++++--- .../compilacao/text_list__print_version.html | 2 +- sapl/templates/index.html | 18 +++++++++++------- sapl/templates/norma/normajuridica_filter.html | 11 +++++++---- .../sessao/votacao/nominal_detail.html | 2 +- .../templates/sessao/votacao/nominal_edit.html | 2 +- .../sessao/votacao/nominal_transparencia.html | 2 +- .../votacao/simbolica_transparencia.html | 2 +- 10 files changed, 37 insertions(+), 28 deletions(-) diff --git a/sapl/templates/base/login.html b/sapl/templates/base/login.html index c2c7aa2c6..5db419fce 100644 --- a/sapl/templates/base/login.html +++ b/sapl/templates/base/login.html @@ -57,13 +57,10 @@ {% endblock base_content %} - {% block javascript %} - - +{% block extra_js %} - - {% endblock %} +{% endblock %} diff --git a/sapl/templates/compilacao/text_list.html b/sapl/templates/compilacao/text_list.html index 7d3526cc1..c0ab6209e 100644 --- a/sapl/templates/compilacao/text_list.html +++ b/sapl/templates/compilacao/text_list.html @@ -113,7 +113,7 @@
{% endblock base_content %} -{% block foot_js %} +{% block extra_js %} {{block.super}} diff --git a/sapl/templates/compilacao/text_list__embedded.html b/sapl/templates/compilacao/text_list__embedded.html index a448c9dd4..33b19695c 100644 --- a/sapl/templates/compilacao/text_list__embedded.html +++ b/sapl/templates/compilacao/text_list__embedded.html @@ -78,9 +78,14 @@ {% include 'compilacao/text_list_bloco.html'%}
- - + + +{% block extra_js %} + + {% if perms.compilacao.add_nota %} - {% endif %} \ No newline at end of file + {% endif %} + +{% endblock %} \ No newline at end of file diff --git a/sapl/templates/compilacao/text_list__print_version.html b/sapl/templates/compilacao/text_list__print_version.html index 8aad1409c..aaf49babb 100644 --- a/sapl/templates/compilacao/text_list__print_version.html +++ b/sapl/templates/compilacao/text_list__print_version.html @@ -15,7 +15,7 @@ {% block footer_container %}{% endblock %} -{% block foot_js %}{{block.super}} +{% block extra_js %}{{block.super}} {% endblock %} diff --git a/sapl/templates/index.html b/sapl/templates/index.html index 69c53e075..9dd611471 100644 --- a/sapl/templates/index.html +++ b/sapl/templates/index.html @@ -192,11 +192,15 @@
- + +{% endblock %} + +{% block extra_js %} + {% endblock %} diff --git a/sapl/templates/norma/normajuridica_filter.html b/sapl/templates/norma/normajuridica_filter.html index 0c7547661..a2a9c5f82 100644 --- a/sapl/templates/norma/normajuridica_filter.html +++ b/sapl/templates/norma/normajuridica_filter.html @@ -91,6 +91,12 @@ {% endif %} {% endif %} +{% endblock detail_content %} + +{% block table_content %} +{% endblock table_content %} + +{% block extra_js %} -{% endblock detail_content %} - -{% block table_content %} -{% endblock table_content %} +{% endblock table_content %} \ No newline at end of file diff --git a/sapl/templates/sessao/votacao/nominal_detail.html b/sapl/templates/sessao/votacao/nominal_detail.html index 53d41084b..17ccb1f69 100644 --- a/sapl/templates/sessao/votacao/nominal_detail.html +++ b/sapl/templates/sessao/votacao/nominal_detail.html @@ -52,7 +52,7 @@ {% endblock detail_content %} -{% block foot_js %} +{% block extra_js %} diff --git a/sapl/templates/sessao/votacao/nominal_edit.html b/sapl/templates/sessao/votacao/nominal_edit.html index f751e21d9..c9d543c15 100644 --- a/sapl/templates/sessao/votacao/nominal_edit.html +++ b/sapl/templates/sessao/votacao/nominal_edit.html @@ -83,7 +83,7 @@ {% endblock detail_content %} -{% block foot_js %} +{% block extra_js %} diff --git a/sapl/templates/sessao/votacao/nominal_transparencia.html b/sapl/templates/sessao/votacao/nominal_transparencia.html index e373e7b03..920710a3e 100644 --- a/sapl/templates/sessao/votacao/nominal_transparencia.html +++ b/sapl/templates/sessao/votacao/nominal_transparencia.html @@ -58,7 +58,7 @@ {% endblock detail_content %} -{% block foot_js %} +{% block extra_js %} diff --git a/sapl/templates/sessao/votacao/simbolica_transparencia.html b/sapl/templates/sessao/votacao/simbolica_transparencia.html index 159dc1f94..57829dc3d 100644 --- a/sapl/templates/sessao/votacao/simbolica_transparencia.html +++ b/sapl/templates/sessao/votacao/simbolica_transparencia.html @@ -49,7 +49,7 @@ {% endblock detail_content %} -{% block foot_js %} +{% block extra_js %} From 1badaeb31276237811fcb73a6420d69b0a3f0add Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 21 Jan 2019 21:18:47 -0200 Subject: [PATCH 106/222] corrige endblock --- sapl/templates/norma/normajuridica_filter.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/templates/norma/normajuridica_filter.html b/sapl/templates/norma/normajuridica_filter.html index a2a9c5f82..674f43a9c 100644 --- a/sapl/templates/norma/normajuridica_filter.html +++ b/sapl/templates/norma/normajuridica_filter.html @@ -108,4 +108,4 @@ }); }); -{% endblock table_content %} \ No newline at end of file +{% endblock extra_js %} \ No newline at end of file From 87dce29d1072482f845cbfc117b6008781433c6e Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 21 Jan 2019 22:24:44 -0200 Subject: [PATCH 107/222] =?UTF-8?q?adequa=20form=20de=20notas=20de=20compi?= =?UTF-8?q?la=C3=A7=C3=A3o=20ao=20form=20do=20django=201.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index f7889604a..1b90374bc 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -251,6 +251,8 @@ class NotaForm(ModelForm): ('publicidade', 6), ('publicacao', 3), ('efetividade', 3), + ('dispositivo', 0), + ('pk', 0), ]) buttons = FormActions( From 09e40439ca9d8ee58513fef9e819c326c0a19b5d Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Mon, 21 Jan 2019 22:29:29 -0200 Subject: [PATCH 108/222] =?UTF-8?q?adequa=20form=20de=20vides=20de=20compi?= =?UTF-8?q?la=C3=A7=C3=A3o=20ao=20form=20do=20django=201.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/forms.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index 1b90374bc..3c4275bee 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -359,13 +359,15 @@ class VideForm(ModelForm): self.helper = FormHelper() self.helper.layout = Layout( Div( - Div(HTML(_('Vides')), css_class='panel-heading'), + Div(HTML(_('Vides')), css_class='car-header'), Div( to_column((fields_form[0], 6)), to_column((fields_form[1], 6)), - css_class="panel-body" + to_column(('dispositivo_base', 0)), + to_column(('pk', 0)), + css_class="card-body" ), - css_class="panel panel-primary" + css_class="card bg-light" ) ) From e01ba09e4d579382e7afbdb804599333d3623856 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Tue, 22 Jan 2019 00:09:59 -0200 Subject: [PATCH 109/222] =?UTF-8?q?aplica=20convers=C3=A3o=20autom=C3=A1ti?= =?UTF-8?q?ca=20de=20html=20mal=20formado=20nos=20dispositivos=20de=20TAs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/models.py | 10 ++++++++++ sapl/compilacao/views.py | 6 ++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index bb504934b..f36e406f9 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -1,4 +1,5 @@ +from bs4 import BeautifulSoup from django.contrib import messages from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType @@ -1105,6 +1106,15 @@ class Dispositivo(BaseModel, TimestampedMixin): self.contagem_continua = self.tipo_dispositivo.contagem_continua + try: + if self.texto: + self.texto = str(BeautifulSoup(self.texto, "html.parser")) + if self.texto_atualizador: + self.texto_atualizador = str(BeautifulSoup( + self.texto_atualizador, "html.parser")) + except: + pass + return super().save( force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields, clean=clean) diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 7d28f619a..897e18cd6 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -4,6 +4,7 @@ import logging import sys from braces.views import FormMessagesMixin +from bs4 import BeautifulSoup from django import forms from django.conf import settings from django.contrib import messages @@ -2940,13 +2941,10 @@ class DispositivoDinamicEditView( if texto != texto_atualizador else '' visibilidade = request.POST['visibilidade'] - # if d.texto != '': - # d.texto = texto - # d.save() - # return self.get(request, *args, **kwargs) d_texto = d.texto d.texto = texto.strip() d.texto_atualizador = texto_atualizador.strip() + d.visibilidade = not visibilidade or visibilidade == 'True' d.save() From aa36931b1f4d448238ab451a188acb0502f66a77 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Tue, 22 Jan 2019 11:10:05 -0200 Subject: [PATCH 110/222] HOT-FIX: adiciona .dockerignore ao projeto --- .dockerignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..8f4c8f147 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +media +collected_static +.git +whoosh From 0948eaf8d47723f687cabc8949ba6046350296a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Cantu=C3=A1ria?= Date: Thu, 24 Jan 2019 14:34:45 -0200 Subject: [PATCH 111/222] HOT-FIX: adiciona paths para .vscode em .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cb6cce48e..dfdeb2b5c 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,7 @@ target/ .ipynb_checkpoints/ *.ipynb .vscode/* +*/.vscode/* # specific to this project whoosh_index From 7fe678622fe24fd2f7c5ccdc16c892e187058eae Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Thu, 24 Jan 2019 17:13:30 -0200 Subject: [PATCH 112/222] Fix #2452 --- sapl/materia/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index c89d82336..0e841504b 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -802,7 +802,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): o = MateriaPesquisaOrderingFilter(help_text='') tipo_listagem = forms.ChoiceField( - required=True, + required=False, choices=CHOICE_TIPO_LISTAGEM, label=_('Tipo da Listagem do Resultado da Pesquisa')) From 12acabd13fe2993d3cb2c5879b14bb496582fd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Cantu=C3=A1ria?= Date: Thu, 24 Jan 2019 17:15:09 -0200 Subject: [PATCH 113/222] =?UTF-8?q?HOT-FIX:=20corrige=20o=20fechamento=20d?= =?UTF-8?q?o=20coment=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 8d64c275c..c549f2bd4 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -26,11 +26,11 @@ ## Imagens do Ocorrido - ## Seu Ambiente * Versão usada (_Release_): * Nome e versão do navegador: * Nome e versão do Sistema Operacional (desktop ou mobile): -* Link para o seu projeto (Caso de fork deste projeto): \ No newline at end of file +* Link para o seu projeto (Caso de fork deste projeto): From ed50c00193f980742d5f877ff13832535298b634 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Mon, 28 Jan 2019 14:09:58 -0200 Subject: [PATCH 114/222] fix #2453 (#2457) --- sapl/materia/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 0e841504b..9a1e4eda7 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -202,7 +202,8 @@ class MateriaLegislativaForm(ModelForm): widget=forms.HiddenInput()) self.fields['autor'] = forms.CharField(required=False, widget=forms.HiddenInput()) - self.fields['numero_protocolo'].widget.attrs['readonly'] = True + if kwargs['instance'].numero_protocolo: + self.fields['numero_protocolo'].widget.attrs['readonly'] = True def clean(self): super(MateriaLegislativaForm, self).clean() From 2434f3266cb570f2aee1c68ba1f6fd1ba176c9ae Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Tue, 29 Jan 2019 15:00:54 -0200 Subject: [PATCH 115/222] HOTFIX - Retira erro para Legislatura com data_fim vazia --- sapl/parlamentares/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index b1ee14629..d88f2fd87 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -28,10 +28,14 @@ class Legislatura(models.Model): def atual(self): current_year = timezone.now().year + if not self.data_fim: + self.data_fim = timezone.now().date() return self.data_inicio.year <= current_year <= self.data_fim.year @vigencia_atual def __str__(self): + if not self.data_fim: + self.data_fim = timezone.now().date() return _('%(numero)sª (%(start)s - %(end)s)') % { 'numero': self.numero, 'start': self.data_inicio.year, From 0cc296f6a2dbc65288db026ac5cd343fd7d152b3 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Tue, 29 Jan 2019 20:11:11 -0200 Subject: [PATCH 116/222] =?UTF-8?q?Fix=202461=20-=20Logotipo=20em=20relat?= =?UTF-8?q?=C3=B3rios=20(#2463)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix erro ao gerar pdf sem logotipo * retira ipdb e ajusta codigo --- .../templates/pdf_documento_administrativo_gerar.py | 6 ++++-- sapl/relatorios/templates/pdf_espelho_gerar.py | 6 ++++-- sapl/relatorios/templates/pdf_materia_gerar.py | 4 +++- sapl/relatorios/templates/pdf_ordem_dia_gerar.py | 7 ++++--- sapl/relatorios/templates/pdf_pauta_sessao_gerar.py | 6 ++++-- sapl/relatorios/templates/pdf_protocolo_gerar.py | 4 +++- sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py | 7 +++++-- sapl/relatorios/views.py | 3 +-- 8 files changed, 28 insertions(+), 15 deletions(-) diff --git a/sapl/relatorios/templates/pdf_documento_administrativo_gerar.py b/sapl/relatorios/templates/pdf_documento_administrativo_gerar.py index b102322ab..2dc8d363e 100755 --- a/sapl/relatorios/templates/pdf_documento_administrativo_gerar.py +++ b/sapl/relatorios/templates/pdf_documento_administrativo_gerar.py @@ -8,6 +8,7 @@ versão: 1.0 """ import time +import os from trml2pdf import parseString @@ -15,8 +16,9 @@ from trml2pdf import parseString def cabecalho(dic_cabecalho, imagem): """Gera o codigo rml do cabecalho""" tmp_data = '' - tmp_data += '\t\t\t\t\n' + if os.path.isfile(imagem): + tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t2cm 25.4cm 19cm 25.4cm\n' tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t' + \ diff --git a/sapl/relatorios/templates/pdf_espelho_gerar.py b/sapl/relatorios/templates/pdf_espelho_gerar.py index ba3cd373c..769d56790 100644 --- a/sapl/relatorios/templates/pdf_espelho_gerar.py +++ b/sapl/relatorios/templates/pdf_espelho_gerar.py @@ -7,6 +7,7 @@ versão: 1.0 """ import time +import os from trml2pdf import parseString @@ -14,8 +15,9 @@ from trml2pdf import parseString def cabecalho(dic_cabecalho, imagem): """Gera o codigo rml do cabecalho""" tmp_data = '' - tmp_data += '\t\t\t\t\n' + if os.path.isfile(imagem): + tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t2cm 25cm 19cm 25cm\n' tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t' + \ diff --git a/sapl/relatorios/templates/pdf_materia_gerar.py b/sapl/relatorios/templates/pdf_materia_gerar.py index 125d147e6..cadc6501c 100755 --- a/sapl/relatorios/templates/pdf_materia_gerar.py +++ b/sapl/relatorios/templates/pdf_materia_gerar.py @@ -7,6 +7,7 @@ versão: 1.0 """ import time +import os from trml2pdf import parseString @@ -14,7 +15,8 @@ from trml2pdf import parseString def cabecalho(dic_cabecalho, imagem): """Gera o codigo rml do cabecalho""" tmp_data = '' - tmp_data += '\t\t\t\t\n' + if os.path.isfile(imagem): + tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t2cm 25cm 19cm 25cm\n' tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t' + \ diff --git a/sapl/relatorios/templates/pdf_ordem_dia_gerar.py b/sapl/relatorios/templates/pdf_ordem_dia_gerar.py index 559a2d979..41cf8f2eb 100755 --- a/sapl/relatorios/templates/pdf_ordem_dia_gerar.py +++ b/sapl/relatorios/templates/pdf_ordem_dia_gerar.py @@ -6,8 +6,8 @@ Empresa: Interlegis versão: 1.0 """ -import os import time +import os from trml2pdf import parseString @@ -16,8 +16,9 @@ def cabecalho(dic_cabecalho, dat_ordem, imagem): """Gera o codigo rml do cabecalho""" tmp = '' - tmp += '\t\t\t\t\n' + if os.path.isfile(imagem): + tmp += '\t\t\t\t\n' tmp += '\t\t\t\t2cm 25cm 19cm 25cm\n' tmp += '\t\t\t\t\n' #tmp+='\t\t\t\t' + str(dic_cabecalho['nom_casa']) + '\n' diff --git a/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py b/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py index 24cd5ed4a..e570e38ea 100755 --- a/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py +++ b/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py @@ -4,6 +4,7 @@ versão: 1.0 """ import time +import os from trml2pdf import parseString @@ -12,8 +13,9 @@ def cabecalho(inf_basicas_dic, imagem): """ """ tmp = '' - tmp += '\t\t\t\t\n' + if os.path.isfile(imagem): + tmp += '\t\t\t\t\n' tmp += '\t\t\t\t2cm 25.4cm 19cm 25.4cm\n' tmp += '\t\t\t\t\n' tmp += '\t\t\t\t' + \ diff --git a/sapl/relatorios/templates/pdf_protocolo_gerar.py b/sapl/relatorios/templates/pdf_protocolo_gerar.py index a3fc82dd1..752f19c9a 100755 --- a/sapl/relatorios/templates/pdf_protocolo_gerar.py +++ b/sapl/relatorios/templates/pdf_protocolo_gerar.py @@ -7,6 +7,7 @@ versão: 1.0 """ import time +import os from trml2pdf import parseString @@ -14,7 +15,8 @@ from trml2pdf import parseString def cabecalho(dic_cabecalho, imagem): """Gera o codigo rml do cabecalho""" tmp_data = '' - tmp_data += '\t\t\t\t\n' + if os.path.isfile(imagem): + tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t2cm 25.4cm 19cm 25.4cm\n' tmp_data += '\t\t\t\t\n' tmp_data += '\t\t\t\t' + \ diff --git a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py index 3a3512764..c1be7c3f9 100644 --- a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py +++ b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py @@ -5,6 +5,7 @@ versão: 1.0 """ import time +import os from django.template.defaultfilters import safe from django.utils.html import strip_tags @@ -18,8 +19,10 @@ def cabecalho(inf_basicas_dic, imagem): """ """ tmp = '' - tmp += '\t\t\t\t\n' + + if os.path.isfile(imagem): + tmp += '\t\t\t\t\n' tmp += '\t\t\t\t2cm 25.4cm 19cm 25.4cm\n' tmp += '\t\t\t\t\n' tmp += '\t\t\t\t' + \ diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index f4bc8cda2..aad44fc1d 100755 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -55,8 +55,7 @@ def get_cabecalho(casa): def get_imagem(casa): if casa.logotipo: return casa.logotipo.path - else: - return STATIC_ROOT + '/img/brasao_transp.gif' + return STATIC_ROOT + '/img/brasao_transp.gif' def get_rodape(casa): From 57d8d337055f60f90d9f8cd466dc1f1349a78f8e Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Fri, 1 Feb 2019 14:24:06 -0200 Subject: [PATCH 117/222] =?UTF-8?q?HOTFIX=20-=20Erro=20na=20cria=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20documento=20administrativo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/protocoloadm/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 8f476d443..9710a08ee 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -831,10 +831,10 @@ class DocumentoAdministrativoForm(ModelForm): if not self.instance.pk or mudanca_doc: doc_exists = DocumentoAdministrativo.objects.filter(numero=numero_documento, tipo=tipo_documento, - ano=ano_protocolo).exists() + ano=ano_documento).exists() if doc_exists: self.logger.error("DocumentoAdministrativo (numero={}, tipo={} e ano={}) já existe." - .format(numero_documento, tipo_documento, ano_protocolo)) + .format(numero_documento, tipo_documento, ano_documento)) raise ValidationError(_('Documento já existente')) # campos opcionais, mas que se informados devem ser válidos From 8c1655b44cde7df1962488eacd5ca47c22af4af3 Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Fri, 1 Feb 2019 14:31:11 -0200 Subject: [PATCH 118/222] HOTFIX - Mensagem de erro mal formatada --- sapl/protocoloadm/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 9710a08ee..640d20613 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -855,8 +855,8 @@ class DocumentoAdministrativoForm(ModelForm): self.logger.error("Existe mais de um Protocolo com este ano ({}) e número ({}).".format( ano_protocolo, numero_protocolo)) msg = _( - 'Existe mais de um Protocolo com este ano e número.' % ( - numero_protocolo, ano_protocolo)) + 'Existe mais de um Protocolo com este ano ({}) e número({}).' % ( + ano_protocolo, numero_protocolo)) raise ValidationError(msg) inst = self.instance.protocolo From 70a26293d33eee6741f4a21c81d97cbc74ff3b8e Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Fri, 1 Feb 2019 14:33:41 -0200 Subject: [PATCH 119/222] fix commit #8c1655b --- sapl/protocoloadm/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 640d20613..77ec1b7bf 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -855,7 +855,7 @@ class DocumentoAdministrativoForm(ModelForm): self.logger.error("Existe mais de um Protocolo com este ano ({}) e número ({}).".format( ano_protocolo, numero_protocolo)) msg = _( - 'Existe mais de um Protocolo com este ano ({}) e número({}).' % ( + 'Existe mais de um Protocolo com este ano (%s) e número (%s).' % ( ano_protocolo, numero_protocolo)) raise ValidationError(msg) From 46b151d3963498ab6868d2ad878b4b2f83f6470c Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Fri, 1 Feb 2019 15:44:53 -0200 Subject: [PATCH 120/222] desativa checkbox e radiobox do druken MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drunken será desativa totalmente apos o PR do branch 1540-migra-frontend --- sapl/static/js/app.js | 2 +- sapl/static/js/compilacao.js | 4 ++-- sapl/static/js/compilacao_edit.js | 2 +- sapl/templates/base.html | 3 --- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sapl/static/js/app.js b/sapl/static/js/app.js index c30f357bd..9a7e41604 100644 --- a/sapl/static/js/app.js +++ b/sapl/static/js/app.js @@ -231,7 +231,7 @@ $(document).ready(function(){ autorModal(); initTinymce("texto-rico"); - OptionalCustomFrontEnd(); + //OptionalCustomFrontEnd(); }); diff --git a/sapl/static/js/compilacao.js b/sapl/static/js/compilacao.js index a5dd9be1b..1769fce9f 100644 --- a/sapl/static/js/compilacao.js +++ b/sapl/static/js/compilacao.js @@ -118,7 +118,7 @@ function DispostivoSearch(opts) { insertWaitAjax('.result-busca-dispositivo') $.get(url, formData).done(function( data ) { $('.result-busca-dispositivo').html(data); - //OptionalCustomFrontEnd().init(); + ////OptionalCustomFrontEnd().init(); if (data_type_selection == 'checkbox') { var tas = $('.result-busca-dispositivo').find('input[name="ta_select_all"]'); tas.off(); @@ -168,7 +168,7 @@ function DispostivoSearch(opts) { $.get(opts['url_form'], function(data) { container_ds.html(data); var modal_ds = $('#modal-ds'); - OptionalCustomFrontEnd().init(); + //OptionalCustomFrontEnd().init(); modal_ds.find("select[name='tipo_ta']").change(function(event) { var url = ''; diff --git a/sapl/static/js/compilacao_edit.js b/sapl/static/js/compilacao_edit.js index 58e05280b..540b0c48d 100644 --- a/sapl/static/js/compilacao_edit.js +++ b/sapl/static/js/compilacao_edit.js @@ -229,7 +229,7 @@ function DispositivoEdit() { if (editortype == 'tinymce' ) { initTinymce(); } - OptionalCustomFrontEnd().init(); + //OptionalCustomFrontEnd().init(); } dpt.trigger(trigger); }).always(function() { diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 807f97786..84deb4b60 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -241,9 +241,6 @@ - - - From 59bc7d75b07812be04f7956c285e60f64aad0cb0 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Mon, 4 Feb 2019 14:11:20 -0200 Subject: [PATCH 121/222] HOT-FIX: set default uploaded file permissions to 644 --- sapl/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sapl/settings.py b/sapl/settings.py index 782cbb0f4..d616a446f 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -278,6 +278,8 @@ STATICFILES_FINDERS = ( MEDIA_ROOT = PROJECT_DIR.child("media") MEDIA_URL = '/media/' +FILE_UPLOAD_PERMISSIONS = 0o644 + DAB_FIELD_RENDERER = \ 'django_admin_bootstrapped.renderers.BootstrapFieldRenderer' CRISPY_TEMPLATE_PACK = 'bootstrap3' From 095b1165c2a05a8d5b888bedef808e2620cafe22 Mon Sep 17 00:00:00 2001 From: Edward Date: Mon, 4 Feb 2019 18:20:43 -0200 Subject: [PATCH 122/222] =?UTF-8?q?Evita=20quebra=20de=20relat=C3=B3rio=20?= =?UTF-8?q?em=20ementas=20enormes=20(#2468)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/relatorios/templates/pdf_pauta_sessao_gerar.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py b/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py index e570e38ea..208b2bf3f 100755 --- a/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py +++ b/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py @@ -129,6 +129,8 @@ def expediente_materia(lst_expediente_materia): expediente_materia['id_materia'] + '\n' + '' + expediente_materia['num_autores'] + ': ' + \ expediente_materia['nom_autor'] + '\n' txt_ementa = expediente_materia['txt_ementa'].replace('&', '&') + if len(txt_ementa) > 1600: + txt_ementa = txt_ementa[:1600] + "..." tmp += '' + txt_ementa + '' + '' + expediente_materia['ordem_observacao'] + '\n' tmp += '' + \ str(expediente_materia['des_situacao']) + '\n' @@ -156,6 +158,8 @@ def votacao(lst_votacao): str(votacao['des_turno']) + '\n' + ''+votacao['num_autores']+': ' + \ str(votacao['nom_autor']) + '\n' txt_ementa = votacao['txt_ementa'].replace('&', '&') + if len(txt_ementa) > 1600: + txt_ementa = txt_ementa[:1600] + "..." tmp += '' + txt_ementa + '' + '' + votacao['ordem_observacao'] + '\n' tmp += '' + \ str(votacao['des_situacao']) + '\n' From 9a1f3f770f61bee07081777c4cd0e5a0a0f02666 Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 6 Feb 2019 13:56:20 -0200 Subject: [PATCH 123/222] HOT-FIX: corrige erro introduzido em c2ebae0 --- sapl/norma/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sapl/norma/forms.py b/sapl/norma/forms.py index c49f94889..bf676c242 100644 --- a/sapl/norma/forms.py +++ b/sapl/norma/forms.py @@ -356,7 +356,8 @@ class NormaRelacionadaForm(ModelForm): def save(self, commit=False): relacionada = super(NormaRelacionadaForm, self).save(commit) relacionada.norma_relacionada = self.cleaned_data['norma_relacionada'] - relacionada.norma_relacionada.data_vigencia = relacionada.norma_principal.data + if relacionada.tipo_vinculo.revoga_integralmente: + relacionada.norma_relacionada.data_vigencia = relacionada.norma_principal.data relacionada.norma_relacionada.save() relacionada.save() return relacionada From c1d3f88c858689e3a725a676aab4cf817931b33b Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 6 Feb 2019 14:02:10 -0200 Subject: [PATCH 124/222] =?UTF-8?q?corrige=20formul=C3=A1rio=20de=20add=20?= =?UTF-8?q?doc=20acess=20em=20lote?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/templates/materia/em_lote/acessorio.html | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sapl/templates/materia/em_lote/acessorio.html b/sapl/templates/materia/em_lote/acessorio.html index cdf7a85c1..738010083 100644 --- a/sapl/templates/materia/em_lote/acessorio.html +++ b/sapl/templates/materia/em_lote/acessorio.html @@ -20,45 +20,58 @@ Documento Acessório
+
+
+
+
+
+
+
+
+
+
+
+
+
-


+
Matérias para inclusão do Documento Acessório From d6eb7968932f9dee55b57285b633fb7d46ac6ee3 Mon Sep 17 00:00:00 2001 From: Ricardo Lima Canela Date: Wed, 6 Feb 2019 14:12:04 -0300 Subject: [PATCH 125/222] Insere excecoes no log (#2473) * adicionando ao log qualquer excecao que ocorra no django * apagando comentarios desnecessarios --- sapl/settings.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/sapl/settings.py b/sapl/settings.py index d616a446f..237b137d7 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -340,6 +340,11 @@ LOGGING = { 'level': 'INFO', 'propagate': True, }, + 'django': { + 'handlers': ['applogfile'], + 'level': 'ERROR', + 'propagate': True, + }, } } @@ -358,15 +363,3 @@ def remove_warnings(): remove_warnings() - - -def uncaught_exceptions(type, value, error_traceback): - import traceback - logger = logging.getLogger(__name__) - error_msg = ''.join(traceback.format_tb(error_traceback)) - logger.error(error_msg) - print(error_msg) - - -# captura exceções que não foram tratadas -sys.excepthook = uncaught_exceptions From 88aec7b54278c6176b2424a60ba33908bdf21f32 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Wed, 6 Feb 2019 15:12:40 -0200 Subject: [PATCH 126/222] =?UTF-8?q?Evita=20quebra=20de=20relat=C3=B3rio=20?= =?UTF-8?q?em=20ementas=20enormes=20(#2469)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Evita quebra de relatório em ementas enormes * fix form e pdf resumo * retirada de linha em branco * fix form e pdf resumo * retirada de linha em branco --- sapl/materia/forms.py | 2 ++ sapl/relatorios/templates/pdf_pauta_sessao_gerar.py | 8 ++++---- sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 9a1e4eda7..c8ba3e4cf 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -196,6 +196,8 @@ class MateriaLegislativaForm(ModelForm): def __init__(self, *args, **kwargs): super(MateriaLegislativaForm, self).__init__(*args, **kwargs) + + self.fields['ementa'].widget.attrs['maxlength'] = 1000 if self.instance and self.instance.pk: self.fields['tipo_autor'] = forms.CharField(required=False, diff --git a/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py b/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py index 208b2bf3f..81e0aa70d 100755 --- a/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py +++ b/sapl/relatorios/templates/pdf_pauta_sessao_gerar.py @@ -129,8 +129,8 @@ def expediente_materia(lst_expediente_materia): expediente_materia['id_materia'] + '\n' + '' + expediente_materia['num_autores'] + ': ' + \ expediente_materia['nom_autor'] + '\n' txt_ementa = expediente_materia['txt_ementa'].replace('&', '&') - if len(txt_ementa) > 1600: - txt_ementa = txt_ementa[:1600] + "..." + if len(txt_ementa) > 1000: + txt_ementa = txt_ementa[:1000] + "..." tmp += '' + txt_ementa + '' + '' + expediente_materia['ordem_observacao'] + '\n' tmp += '' + \ str(expediente_materia['des_situacao']) + '\n' @@ -158,8 +158,8 @@ def votacao(lst_votacao): str(votacao['des_turno']) + '\n' + ''+votacao['num_autores']+': ' + \ str(votacao['nom_autor']) + '\n' txt_ementa = votacao['txt_ementa'].replace('&', '&') - if len(txt_ementa) > 1600: - txt_ementa = txt_ementa[:1600] + "..." + if len(txt_ementa) > 1000: + txt_ementa = txt_ementa[:1000] + "..." tmp += '' + txt_ementa + '' + '' + votacao['ordem_observacao'] + '\n' tmp += '' + \ str(votacao['des_situacao']) + '\n' diff --git a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py index c1be7c3f9..02cea969d 100644 --- a/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py +++ b/sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py @@ -208,6 +208,8 @@ def expediente_materia(lst_expediente_materia): tmp += '' + str(expediente_materia['num_ordem']) + ' - ' + expediente_materia['id_materia'] + '\n' + 'Turno: ' + expediente_materia[ 'des_turno'] + '\n' + ''+ expediente_materia['num_autores'] + ': ' + str(expediente_materia['nom_autor']) + '\n' txt_ementa = expediente_materia['txt_ementa'].replace('&', '&') + if len(txt_ementa) > 1000: + txt_ementa = txt_ementa[:1000] + "..." tmp += '' + txt_ementa + '' + '' + expediente_materia['ordem_observacao'] + '\n' tmp += '' + \ str(expediente_materia['nom_resultado']) + \ @@ -271,6 +273,8 @@ def votacao(lst_votacao): tmp += '' + str(votacao['num_ordem']) + ' - ' + votacao['id_materia'] + '\n' + 'Turno: ' + votacao[ 'des_turno'] + '\n' + ''+ votacao['num_autores'] +': ' + str(votacao['nom_autor']) + '\n' txt_ementa = votacao['txt_ementa'].replace('&', '&') + if len(txt_ementa) > 1000: + txt_ementa = txt_ementa[:1000] + "..." tmp += '' + txt_ementa + '' + '' + votacao['ordem_observacao'] + '\n' tmp += '' + \ str(votacao['nom_resultado']) + \ From da83ff91c67d990db4876f42294c4580750b2c77 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 6 Feb 2019 15:22:54 -0200 Subject: [PATCH 127/222] ajusta checkbox de autoria multicreate --- sapl/templates/materia/autoria_multicreate_form.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sapl/templates/materia/autoria_multicreate_form.html b/sapl/templates/materia/autoria_multicreate_form.html index 59c3ece91..105d42d51 100644 --- a/sapl/templates/materia/autoria_multicreate_form.html +++ b/sapl/templates/materia/autoria_multicreate_form.html @@ -26,21 +26,23 @@ if (autores_pre_cadastrados.indexOf(obj.value) !== -1) return ; - $('') + let input = $('') .attr('type', 'checkbox') .attr('name','autor') .attr('id', 'id_autor_'+idx) .attr('value', obj.value) .appendTo( - $('
+ {% include 'paginacao.html'%} {% endblock base_content %} From 350475a1dbd27071a0f4c4b7407d85ab0fab432a Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 6 Feb 2019 16:58:26 -0200 Subject: [PATCH 129/222] =?UTF-8?q?corrige=20l=C3=B3gica=20de=20tratamento?= =?UTF-8?q?=20de=20despachos=20iniciais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/forms.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index c8ba3e4cf..cdb21021d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -196,7 +196,7 @@ class MateriaLegislativaForm(ModelForm): def __init__(self, *args, **kwargs): super(MateriaLegislativaForm, self).__init__(*args, **kwargs) - + self.fields['ementa'].widget.attrs['maxlength'] = 1000 if self.instance and self.instance.pk: @@ -989,8 +989,9 @@ class DespachoInicialForm(ModelForm): if DespachoInicial.objects.filter( materia=self.instance.materia, comissao=self.cleaned_data['comissao'], - ).exists(): - msg = _('Esse Despacho já foi cadastrado.') + ).exclude(pk=self.instance.pk).exists(): + msg = _('Já existe um Despacho cadastrado para %s' % + self.cleaned_data['comissao']) raise ValidationError(msg) return self.cleaned_data From efe2a39d5c6cac2eecd87564ffa892a8492937cb Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Wed, 6 Feb 2019 17:10:26 -0200 Subject: [PATCH 130/222] Fix #2474 --- sapl/base/forms.py | 15 ++++++++++----- sapl/materia/forms.py | 9 +++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sapl/base/forms.py b/sapl/base/forms.py index d603ffc45..f24868ff6 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -18,14 +18,15 @@ from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ import django_filters +from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica from sapl.base.models import Autor, TipoAutor from sapl.comissoes.models import Reuniao, Comissao +from sapl.comissoes.models import Reuniao, Comissao from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, to_row) -from sapl.audiencia.models import AudienciaPublica,TipoAudienciaPublica -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, NormaEstatisticas) from sapl.parlamentares.models import SessaoLegislativa from sapl.sessao.models import SessaoPlenaria @@ -706,7 +707,7 @@ class RelatorioAtasFilterSet(django_filters.FilterSet): def ultimo_ano_com_norma(): anos_normas = choice_anos_com_normas() - + if anos_normas: return anos_normas[0] return '' @@ -754,7 +755,7 @@ class EstatisticasAcessoNormasForm(Form): class Meta: fields = ['ano'] - + def __init__(self, *args, **kwargs): super(EstatisticasAcessoNormasForm, self).__init__( *args, **kwargs) @@ -857,7 +858,11 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): self.filters['tipo'].label = 'Tipo de Matéria' + self.filters['tramitacao__unidade_tramitacao_local' + ].label = _('Unidade Local (Último Local)') + self.filters['tramitacao__status'].label = _('Status') row1 = to_row([('tramitacao__data_tramitacao', 12)]) + row2 = to_row( [('tipo', 4), ('tramitacao__unidade_tramitacao_local', 4), diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index cdb21021d..85659ff78 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1160,10 +1160,11 @@ class TramitacaoEmLoteFilterSet(django_filters.FilterSet): super(TramitacaoEmLoteFilterSet, self).__init__( *args, **kwargs) - self.filters['tipo'].label = 'Tipo de Matéria' - self.filters['data_apresentacao'].label = 'Data (Inicial - Final)' + self.filters['tipo'].label = _('Tipo de Matéria') + self.filters['data_apresentacao'].label = _('Data (Inicial - Final)') self.filters['tramitacao__unidade_tramitacao_destino' - ].label = 'Unidade Destino (Último Destino)' + ].label = _('Unidade Destino (Último Destino)') + self.filters['tramitacao__status'].label = _('Status') self.form.fields['tipo'].required = True self.form.fields['data_apresentacao'].required = False self.form.fields['tramitacao__status'].required = True @@ -1180,7 +1181,7 @@ class TramitacaoEmLoteFilterSet(django_filters.FilterSet): self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Tramitação em Lote'), - row1, row2, form_actions(label='Pesquisar'))) + row1, row2, form_actions(label=_('Pesquisar')))) class TipoProposicaoForm(ModelForm): From 6d01901ef240e7e5194ca84a2c7e3ab689d01d9c Mon Sep 17 00:00:00 2001 From: Edward Ribeiro Date: Wed, 6 Feb 2019 17:51:54 -0200 Subject: [PATCH 131/222] Release: 3.1.143 --- docker-compose.yml | 2 +- sapl/templates/base.html | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5b0ee2315..ab841b87b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.142 + image: interlegis/sapl:3.1.143 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 84deb4b60..b13a9e3b4 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -184,7 +184,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.142 + Release: 3.1.143

diff --git a/setup.py b/setup.py index 31cf08684..fb680f72c 100644 --- a/setup.py +++ b/setup.py @@ -51,7 +51,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.142', + version='3.1.143', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', From 719d4c928a9bd8cfd3746f447f0bc5451de03ad7 Mon Sep 17 00:00:00 2001 From: Cesar Carvalho Date: Fri, 8 Feb 2019 15:58:23 -0200 Subject: [PATCH 132/222] HOTFIX - Erro de data do timestamp de protocoloadm --- sapl/materia/models.py | 2 ++ sapl/materia/views.py | 8 +++++++- sapl/protocoloadm/views.py | 5 ++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/sapl/materia/models.py b/sapl/materia/models.py index 221078811..1adb21ea5 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -269,6 +269,8 @@ class MateriaLegislativa(models.Model): if protocolo: if protocolo.timestamp: return protocolo.timestamp.date() + elif protocolo.timestamp_data_hora_manual: + return protocolo.timestamp_data_hora_manual.date() elif protocolo.data: return protocolo.data diff --git a/sapl/materia/views.py b/sapl/materia/views.py index c3036d52e..47cb857af 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -211,7 +211,13 @@ class CriarProtocoloMateriaView(CreateView): context['form'].fields['tipo'].initial = protocolo.tipo_materia context['form'].fields['numero'].initial = numero context['form'].fields['ano'].initial = protocolo.ano - context['form'].fields['data_apresentacao'].initial = protocolo.timestamp.date() + if protocolo: + if protocolo.timestamp: + context['form'].fields['data_apresentacao'].initial = protocolo.timestamp.date() + elif protocolo.timestamp_data_hora_manual: + context['form'].fields['data_apresentacao'].initial = protocolo.timestamp_data_hora_manual.date() + elif protocolo.data: + context['form'].fields['data_apresentacao'].initial = protocolo.data context['form'].fields['numero_protocolo'].initial = protocolo.numero context['form'].fields['ementa'].initial = protocolo.assunto_ementa diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index f91ee5227..a750d1881 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -730,8 +730,8 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): if protocolo.numero < (numero['numero__max'] + 1): self.logger.error("user=" + username + ". Número de protocolo ({}) é menor que {}" .format(protocolo.numero, numero['numero__max'])) - msg = _('Número de protocolo deve ser maior que {}').format( - numero['numero__max']) + msg = _('Número de protocolo deve ser maior que {}'.format( + numero['numero__max'])) messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) protocolo.ano = timezone.now().year @@ -757,7 +757,6 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): protocolo.hora = None protocolo.user_data_hora_manual = '' protocolo.ip_data_hora_manual = '' - protocolo.save() data = form.cleaned_data if data['vincular_materia'] == 'True': From 9e62f0626346700345eec0310dda9f926adb0260 Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 8 Feb 2019 18:40:39 -0200 Subject: [PATCH 133/222] Fixes #2482 (#2483) --- sapl/templates/search/search.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sapl/templates/search/search.html b/sapl/templates/search/search.html index a5103d47d..12b7e07fb 100644 --- a/sapl/templates/search/search.html +++ b/sapl/templates/search/search.html @@ -42,7 +42,11 @@ {% if query %} - + {% for result in page.object_list %} From 4cdc78788f8985d37da34ede4bcebb2fa5954615 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 9 Feb 2019 22:01:08 -0200 Subject: [PATCH 134/222] =?UTF-8?q?ajustas=20heran=C3=A7as=20de=20sele?= =?UTF-8?q?=C3=A7=C3=A3o=20baseada=20em=20content=5Ftypes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - muda BancadaCrud(Crud) para BancadaCrud(CrudAux) e BlocoCrud(Crud) para BlocoCrud(CrudAux) e adequa forma de buscar TipoAutor em metodos save de formulários que criam Autores automaticamente. --- sapl/comissoes/forms.py | 118 +++++++++++++++++++----------------- sapl/materia/forms.py | 2 +- sapl/parlamentares/forms.py | 61 ++++++++++--------- sapl/sessao/forms.py | 4 +- sapl/sessao/views.py | 17 ++---- 5 files changed, 102 insertions(+), 100 deletions(-) diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 14d42f53e..cef967102 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -13,10 +13,13 @@ from sapl.comissoes.models import (Comissao, Composicao, DocumentoAcessorio, Participacao, Reuniao, Periodo) from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar + class ComposicaoForm(forms.ModelForm): - comissao = forms.CharField(required=False, label='Comissao', widget=forms.HiddenInput()) + comissao = forms.CharField( + required=False, label='Comissao', widget=forms.HiddenInput()) logger = logging.getLogger(__name__) + class Meta: model = Composicao exclude = [] @@ -43,8 +46,8 @@ class ComposicaoForm(forms.ModelForm): if intersecao_periodo: self.logger.error('O período informado ({} a {})' - 'choca com períodos já ' - 'cadastrados para esta comissão'.format(periodo.data_inicio, periodo.data_fim)) + 'choca com períodos já ' + 'cadastrados para esta comissão'.format(periodo.data_inicio, periodo.data_fim)) raise ValidationError('O período informado ' 'choca com períodos já ' 'cadastrados para esta comissão') @@ -55,6 +58,7 @@ class ComposicaoForm(forms.ModelForm): class PeriodoForm(forms.ModelForm): logger = logging.getLogger(__name__) + class Meta: model = Periodo exclude = [] @@ -70,31 +74,29 @@ class PeriodoForm(forms.ModelForm): if data_fim and data_fim < data_inicio: self.logger.error('A Data Final ({}) é menor que ' - 'a Data Inicial({}).'.format(data_fim, data_inicio)) + 'a Data Inicial({}).'.format(data_fim, data_inicio)) raise ValidationError('A Data Final não pode ser menor que ' - 'a Data Inicial') + 'a Data Inicial') # 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, - ) + data_fim__gte=data_fim, + ) if not legislatura: self.logger.error('O período informado ({} a {})' - 'não está contido em uma única ' - 'legislatura existente'.format(data_inicio, data_fim)) + 'não está contido em uma única ' + 'legislatura existente'.format(data_inicio, data_fim)) raise ValidationError('O período informado ' 'deve estar contido em uma única ' 'legislatura existente') - return cleaned_data - class ParticipacaoCreateForm(forms.ModelForm): logger = logging.getLogger(__name__) @@ -122,9 +124,9 @@ class ParticipacaoCreateForm(forms.ModelForm): parlamentares = Mandato.objects.filter(qs, parlamentar__ativo=True ).prefetch_related('parlamentar').\ - values_list('parlamentar', - flat=True - ).distinct() + values_list('parlamentar', + flat=True + ).distinct() qs = Parlamentar.objects.filter(id__in=parlamentares).distinct().\ exclude(id__in=id_part) @@ -137,7 +139,6 @@ class ParticipacaoCreateForm(forms.ModelForm): qs = Parlamentar.objects.filter(id__in=ids) self.fields['parlamentar'].queryset = qs - def clean(self): cleaned_data = super(ParticipacaoCreateForm, self).clean() @@ -148,22 +149,23 @@ class ParticipacaoCreateForm(forms.ModelForm): data_desligamento = cleaned_data['data_desligamento'] if data_desligamento and \ - data_designacao > data_desligamento: + data_designacao > data_desligamento: self.logger.error('Data de designação ({}) superior ' - 'à data de desligamento ({})'.format(data_designacao, data_desligamento)) + 'à data de desligamento ({})'.format(data_designacao, data_desligamento)) raise ValidationError(_('Data de designação não pode ser superior ' - 'à data de desligamento')) + 'à data de desligamento')) composicao = Composicao.objects.get(id=self.initial['parent_pk']) - cargos_unicos = [c.cargo.nome for c in composicao.participacao_set.filter(cargo__unico=True)] + cargos_unicos = [ + c.cargo.nome for c in composicao.participacao_set.filter(cargo__unico=True)] if cleaned_data['cargo'].nome in cargos_unicos: msg = _('Este cargo é único para esta Comissão.') - self.logger.error('Este cargo ({}) é único para esta Comissão.'.format(cleaned_data['cargo'].nome)) + self.logger.error('Este cargo ({}) é único para esta Comissão.'.format( + cleaned_data['cargo'].nome)) raise ValidationError(msg) return cleaned_data - def create_participacao(self): composicao = Composicao.objects.get(id=self.initial['parent_pk']) data_inicio_comissao = composicao.periodo.data_inicio @@ -237,9 +239,9 @@ class ParticipacaoEditForm(forms.ModelForm): if data_desligamento and \ data_designacao > data_desligamento: self.logger.error('Data de designação ({}) superior ' - 'à data de desligamento ({})'.format(data_designacao, data_desligamento)) + 'à data de desligamento ({})'.format(data_designacao, data_desligamento)) raise ValidationError(_('Data de designação não pode ser superior ' - 'à data de desligamento')) + 'à data de desligamento')) composicao_id = self.instance.composicao_id @@ -250,7 +252,7 @@ class ParticipacaoEditForm(forms.ModelForm): if cleaned_data['cargo'].nome in cargos_unicos: msg = _('Este cargo é único para esta Comissão.') self.logger.error('Este cargo ({}) é único para esta Comissão (id={}).' - .format(cleaned_data['cargo'].nome, composicao_id)) + .format(cleaned_data['cargo'].nome, composicao_id)) raise ValidationError(msg) return cleaned_data @@ -259,6 +261,7 @@ class ParticipacaoEditForm(forms.ModelForm): class ComissaoForm(forms.ModelForm): logger = logging.getLogger(__name__) + class Meta: model = Comissao fields = '__all__' @@ -274,8 +277,6 @@ class ComissaoForm(forms.ModelForm): self.fields['data_prorrogada_temp'].widget.attrs['disabled'] = 'disabled' self.fields['data_fim_comissao'].widget.attrs['disabled'] = 'disabled' - - def clean(self): super(ComissaoForm, self).clean() @@ -283,51 +284,54 @@ class ComissaoForm(forms.ModelForm): return self.cleaned_data if len(self.cleaned_data['nome']) > 100: - msg = _('Nome da Comissão informado ({}) tem mais de 50 caracteres.'.format(self.cleaned_data['nome'])) - self.logger.error('Nome da Comissão deve ter no máximo 50 caracteres.') + msg = _('Nome da Comissão informado ({}) tem mais de 50 caracteres.'.format( + self.cleaned_data['nome'])) + self.logger.error( + 'Nome da Comissão deve ter no máximo 50 caracteres.') raise ValidationError(msg) if (self.cleaned_data['data_extincao'] and self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): - msg = _('Data de extinção não pode ser menor que a de criação') - self.logger.error('Data de extinção ({}) não pode ser menor que a de criação ({}).' - .format(self.cleaned_data['data_extincao'],self.cleaned_data['data_criacao'])) - raise ValidationError(msg) + msg = _('Data de extinção não pode ser menor que a de criação') + self.logger.error('Data de extinção ({}) não pode ser menor que a de criação ({}).' + .format(self.cleaned_data['data_extincao'], self.cleaned_data['data_criacao'])) + raise ValidationError(msg) if (self.cleaned_data['data_final_prevista_temp'] and self.cleaned_data['data_final_prevista_temp'] < self.cleaned_data['data_criacao']): - msg = _('Data Prevista para Término não pode ser menor que a de criação') - self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de criação ({}).' - .format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_criacao'])) - raise ValidationError(msg) + msg = _('Data Prevista para Término não pode ser menor que a de criação') + self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de criação ({}).' + .format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_criacao'])) + raise ValidationError(msg) if (self.cleaned_data['data_prorrogada_temp'] and self.cleaned_data['data_prorrogada_temp'] < self.cleaned_data['data_criacao']): - msg = _('Data Novo Prazo não pode ser menor que a de criação') - self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de criação ({}).' - .format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_criacao'])) - raise ValidationError(msg) + msg = _('Data Novo Prazo não pode ser menor que a de criação') + self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de criação ({}).' + .format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_criacao'])) + raise ValidationError(msg) if (self.cleaned_data['data_instalacao_temp'] and self.cleaned_data['data_instalacao_temp'] < self.cleaned_data['data_criacao']): - msg = _('Data de Instalação não pode ser menor que a de criação') - self.logger.error('Data de Instalação ({}) não pode ser menor que a de criação ({}).' - .format(self.cleaned_data['data_instalacao_temp'], self.cleaned_data['data_criacao'])) - raise ValidationError(msg) + msg = _('Data de Instalação não pode ser menor que a de criação') + self.logger.error('Data de Instalação ({}) não pode ser menor que a de criação ({}).' + .format(self.cleaned_data['data_instalacao_temp'], self.cleaned_data['data_criacao'])) + raise ValidationError(msg) if (self.cleaned_data['data_final_prevista_temp'] and self.cleaned_data['data_instalacao_temp'] and self.cleaned_data['data_final_prevista_temp'] < self.cleaned_data['data_instalacao_temp']): - msg = _('Data Prevista para Término não pode ser menor que a de Instalação.') - self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de Instalação ({}).' - .format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_instalacao_temp'])) - raise ValidationError(msg) + msg = _( + 'Data Prevista para Término não pode ser menor que a de Instalação.') + self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de Instalação ({}).' + .format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_instalacao_temp'])) + raise ValidationError(msg) if (self.cleaned_data['data_prorrogada_temp'] and self.cleaned_data['data_instalacao_temp'] and self.cleaned_data['data_prorrogada_temp'] < self.cleaned_data['data_instalacao_temp']): - msg = _('Data Novo Prazo não pode ser menor que a de Instalação.') - self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de Instalação ({}).' - .format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_instalacao_temp'])) - raise ValidationError(msg) + msg = _('Data Novo Prazo não pode ser menor que a de Instalação.') + self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de Instalação ({}).' + .format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_instalacao_temp'])) + raise ValidationError(msg) return self.cleaned_data @transaction.atomic @@ -337,7 +341,7 @@ class ComissaoForm(forms.ModelForm): comissao = super(ComissaoForm, self).save(commit) content_type = ContentType.objects.get_for_model(Comissao) object_id = comissao.pk - tipo = TipoAutor.objects.get(descricao__icontains='Comiss') + tipo = TipoAutor.objects.get(content_type=content_type) nome = comissao.sigla + ' - ' + comissao.nome Autor.objects.create( content_type=content_type, @@ -363,7 +367,6 @@ class ReuniaoForm(ModelForm): def clean(self): super(ReuniaoForm, self).clean() - if not self.is_valid(): return self.cleaned_data @@ -371,12 +374,14 @@ class ReuniaoForm(ModelForm): if self.cleaned_data['hora_fim']: if (self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']): - msg = _('A hora de término da reunião não pode ser menor que a de início') + msg = _( + 'A hora de término da reunião não pode ser menor que a de início') self.logger.error("A hora de término da reunião ({}) não pode ser menor que a de início ({})." - .format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio'])) + .format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio'])) raise ValidationError(msg) return self.cleaned_data + class DocumentoAcessorioCreateForm(forms.ModelForm): parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput()) @@ -395,7 +400,6 @@ class DocumentoAcessorioCreateForm(forms.ModelForm): documentos = reuniao.documentoacessorio_set.all() return self.create_documentoacessorio() - def create_documentoacessorio(self): reuniao = Reuniao.objects.get(id=self.initial['parent_pk']) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 85659ff78..7e6b5afe0 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -96,7 +96,7 @@ class OrgaoForm(ModelForm): orgao = super(OrgaoForm, self).save(commit) content_type = ContentType.objects.get_for_model(Orgao) object_id = orgao.pk - tipo = TipoAutor.objects.get(descricao='Órgão') + tipo = TipoAutor.objects.get(content_type=content_type) nome = orgao.nome + ' - ' + orgao.sigla Autor.objects.create( content_type=content_type, diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index a15a4e305..a0ef549a4 100755 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -1,6 +1,5 @@ -import logging - from datetime import timedelta +import logging from crispy_forms.helper import FormHelper from crispy_forms.layout import Fieldset, Layout @@ -46,8 +45,8 @@ def validar_datas_legislatura(eleicao, inicio, fim, pk=None): # Verifica se data de eleição < inicio < fim if inicio >= fim or eleicao >= inicio: logger.error('A data início ({}) deve ser menor que a ' + - 'data fim ({}) e a data eleição ({}) deve ser ' + - 'menor que a data início ({})'.format(inicio, fim, eleicao, inicio)) + 'data fim ({}) e a data eleição ({}) deve ser ' + + 'menor que a data início ({})'.format(inicio, fim, eleicao, inicio)) msg_error = _('A data início deve ser menor que a ' + 'data fim e a data eleição deve ser ' + 'menor que a data início') @@ -66,7 +65,8 @@ def validar_datas_legislatura(eleicao, inicio, fim, pk=None): # Verifica se há alguma outra data de eleição cadastrada if Legislatura.objects.filter( data_eleicao=eleicao).exclude(pk=pk).exists(): - logger.error("Esta data de eleição ({}) já foi cadastrada.".format(eleicao)) + logger.error( + "Esta data de eleição ({}) já foi cadastrada.".format(eleicao)) msg_error = _('Esta data de eleição já foi cadastrada') return (False, msg_error) @@ -75,6 +75,7 @@ def validar_datas_legislatura(eleicao, inicio, fim, pk=None): class MandatoForm(ModelForm): logger = logging.getLogger(__name__) + class Meta: model = Mandato fields = ['legislatura', 'coligacao', 'votos_recebidos', @@ -108,30 +109,30 @@ class MandatoForm(ModelForm): if (data_fim_mandato < legislatura.data_inicio or data_fim_mandato > legislatura.data_fim): self.logger.error("Data fim mandato ({}) fora do intervalo" - " de legislatura informada ({} a {})." - .format(data_fim_mandato, legislatura.data_inicio, legislatura.data_fim)) + " de legislatura informada ({} a {})." + .format(data_fim_mandato, legislatura.data_inicio, legislatura.data_fim)) raise ValidationError(_("Data fim mandato fora do intervalo de" " legislatura informada")) data_expedicao_diploma = data['data_expedicao_diploma'] if (data_expedicao_diploma and data_expedicao_diploma > data_inicio_mandato): - self.logger.error("A data da expedição do diploma ({}) deve ser anterior " - "a data de início do mandato ({}).".format(data_expedicao_diploma, data_inicio_mandato)) - raise ValidationError(_("A data da expedição do diploma deve ser anterior " - "a data de início do mandato")) + self.logger.error("A data da expedição do diploma ({}) deve ser anterior " + "a data de início do mandato ({}).".format(data_expedicao_diploma, data_inicio_mandato)) + raise ValidationError(_("A data da expedição do diploma deve ser anterior " + "a data de início do mandato")) coligacao = data['coligacao'] if coligacao and not coligacao.legislatura == legislatura: - self.logger.error("A coligação selecionada ({}) não está cadastrada " - "na mesma legislatura ({}) que o presente mandato ({}), " - "favor verificar a coligação ou fazer o cadastro " - "de uma nova coligação na legislatura correspondente" - .format(coligacao, coligacao.legislatura, legislatura)) - raise ValidationError(_("A coligação selecionada não está cadastrada " - "na mesma legislatura que o presente mandato, " - "favor verificar a coligação ou fazer o cadastro " - "de uma nova coligação na legislatura correspondente")) + self.logger.error("A coligação selecionada ({}) não está cadastrada " + "na mesma legislatura ({}) que o presente mandato ({}), " + "favor verificar a coligação ou fazer o cadastro " + "de uma nova coligação na legislatura correspondente" + .format(coligacao, coligacao.legislatura, legislatura)) + raise ValidationError(_("A coligação selecionada não está cadastrada " + "na mesma legislatura que o presente mandato, " + "favor verificar a coligação ou fazer o cadastro " + "de uma nova coligação na legislatura correspondente")) existe_mandato = Mandato.objects.filter( parlamentar=data['parlamentar'], @@ -158,7 +159,6 @@ class LegislaturaForm(ModelForm): if not self.is_valid(): return self.cleaned_data - numero = data['numero'] data_inicio = data['data_inicio'] data_fim = data['data_fim'] @@ -166,7 +166,6 @@ class LegislaturaForm(ModelForm): pk = self.instance.pk - ultima_legislatura = Legislatura.objects.filter(data_inicio__lt=data_inicio ).order_by('-data_inicio').first() proxima_legislatura = Legislatura.objects.filter(data_fim__gt=data_fim @@ -175,13 +174,14 @@ class LegislaturaForm(ModelForm): if ultima_legislatura and ultima_legislatura.numero >= numero: self.logger.error("Número ({}) deve ser maior que o da legislatura anterior ({})." .format(numero, ultima_legislatura.numero)) - raise ValidationError(_("Número deve ser maior que o da legislatura anterior")) + raise ValidationError( + _("Número deve ser maior que o da legislatura anterior")) elif proxima_legislatura and proxima_legislatura.numero <= numero: self.logger.error("O Número ({}) deve ser menor que {}, pois existe uma " "legislatura afrente cronologicamente desta que está sendo criada!" .format(numero, proxima_legislatura.numero)) msg_erro = "O Número deve ser menor que {}, pois existe uma " \ - "legislatura afrente cronologicamente desta que está sendo criada!" + "legislatura afrente cronologicamente desta que está sendo criada!" msg_erro = msg_erro.format(proxima_legislatura.numero) raise ValidationError(_(msg_erro)) @@ -241,7 +241,7 @@ class ParlamentarCreateForm(ParlamentarForm): data_expedicao_diploma=self.cleaned_data['data_expedicao_diploma']) content_type = ContentType.objects.get_for_model(Parlamentar) object_id = parlamentar.pk - tipo = TipoAutor.objects.get(descricao='Parlamentar') + tipo = TipoAutor.objects.get(content_type=content_type) Autor.objects.create( content_type=content_type, object_id=object_id, @@ -385,6 +385,7 @@ class ComposicaoColigacaoForm(ModelForm): class FrenteForm(ModelForm): logger = logging.getLogger(__name__) + def __init__(self, *args, **kwargs): super(FrenteForm, self).__init__(*args, **kwargs) self.fields['parlamentares'].queryset = Parlamentar.objects.filter( @@ -404,15 +405,16 @@ class FrenteForm(ModelForm): if cd['data_extincao'] and cd['data_criacao'] >= cd['data_extincao']: self.logger.error("Data Dissolução ({}) não pode ser anterior a Data Criação ({})." - .format(cd['data_extincao'],cd['data_criacao'])) - raise ValidationError(_("Data Dissolução não pode ser anterior a Data Criação")) + .format(cd['data_extincao'], cd['data_criacao'])) + raise ValidationError( + _("Data Dissolução não pode ser anterior a Data Criação")) return cd @transaction.atomic def save(self, commit=True): frente = super(FrenteForm, self).save(commit) - + if not self.instance.pk: frente = super(FrenteForm, self).save(commit) content_type = ContentType.objects.get_for_model(Frente) @@ -466,7 +468,8 @@ class VotanteForm(ModelForm): username = cd['username'] user = get_user_model().objects.filter(username=username) if not user.exists(): - self.logger.error("Não foi possível vincular usuário. Usuário {} não existe.".format(username)) + self.logger.error( + "Não foi possível vincular usuário. Usuário {} não existe.".format(username)) raise ValidationError(_( "{} [{}] {}".format( 'Não foi possível vincular usuário. Usuário', diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 68f6d3222..2b8ec4742 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -317,7 +317,7 @@ class BancadaForm(ModelForm): bancada = super(BancadaForm, self).save(commit) content_type = ContentType.objects.get_for_model(Bancada) object_id = bancada.pk - tipo = TipoAutor.objects.get(descricao__icontains='Bancada') + tipo = TipoAutor.objects.get(content_type=content_type) Autor.objects.create( content_type=content_type, object_id=object_id, @@ -352,7 +352,7 @@ class BlocoForm(ModelForm): bloco = super(BlocoForm, self).save(commit) content_type = ContentType.objects.get_for_model(Bloco) object_id = bloco.pk - tipo = TipoAutor.objects.get(descricao__icontains='Bloco') + tipo = TipoAutor.objects.get(content_type=content_type) Autor.objects.create( content_type=content_type, object_id=object_id, diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index b4665429b..096130162 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -614,26 +614,20 @@ class OradorCrud(OradorCrud): return initial -class BancadaCrud(Crud): +class BancadaCrud(CrudAux): model = Bancada - class ListView(Crud.ListView): - template_name = 'crud/list_tabaux.html' - - class CreateView(Crud.CreateView): + class CreateView(CrudAux.CreateView): form_class = BancadaForm def get_success_url(self): return reverse('sapl.sessao:bancada_list') -class BlocoCrud(Crud): +class BlocoCrud(CrudAux): model = Bloco - class ListView(Crud.ListView): - template_name = 'crud/list_tabaux.html' - - class CreateView(Crud.CreateView): + class CreateView(CrudAux.CreateView): form_class = BlocoForm def get_success_url(self): @@ -1902,7 +1896,8 @@ class VotacaoView(SessaoPermissionMixin): qtde_presentes -= 1 if (qtde_votos > qtde_presentes or qtde_votos < qtde_presentes): - msg = _('O total de votos não corresponde com a quantidade de presentes!') + msg = _( + 'O total de votos não corresponde com a quantidade de presentes!') messages.add_message(request, messages.ERROR, msg) return self.render_to_response(context) elif (qtde_presentes == qtde_votos): From 9b422f14c79e2dd1e5ed305b47a8de44c459cdb2 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sun, 10 Feb 2019 15:37:54 -0200 Subject: [PATCH 135/222] =?UTF-8?q?Refatora=20Manuten=C3=A7=C3=A3o=20de=20?= =?UTF-8?q?Tipos=20de=20Textos=20Articulados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/compilacao/urls.py | 16 +-- sapl/compilacao/views.py | 109 +++++------------- sapl/templates/compilacao/layouts.yaml | 8 ++ .../tipotextoarticulado_detail.html | 73 ------------ .../compilacao/tipotextoarticulado_list.html | 50 -------- sapl/templates/menu_tabelas_auxiliares.yaml | 2 +- 6 files changed, 41 insertions(+), 217 deletions(-) delete mode 100644 sapl/templates/compilacao/tipotextoarticulado_detail.html delete mode 100644 sapl/templates/compilacao/tipotextoarticulado_list.html diff --git a/sapl/compilacao/urls.py b/sapl/compilacao/urls.py index 781a6d80e..9364985aa 100644 --- a/sapl/compilacao/urls.py +++ b/sapl/compilacao/urls.py @@ -3,7 +3,8 @@ from django.conf.urls import include, url from sapl.compilacao import views from sapl.compilacao.views import (TipoDispositivoCrud, TipoNotaCrud, TipoPublicacaoCrud, TipoVideCrud, - VeiculoPublicacaoCrud) + VeiculoPublicacaoCrud, + TipoTextoArticuladoCrud) from .apps import AppConfig @@ -113,14 +114,7 @@ urlpatterns = [ include(TipoPublicacaoCrud.get_urls())), url(r'^sistema/ta/config/veiculo-publicacao/', include(VeiculoPublicacaoCrud.get_urls())), - url(r'^sistema/ta/config/tipo-textoarticulado$', - views.TipoTaListView.as_view(), name='tipo_ta_list'), - url(r'^sistema/ta/config/tipo-textoarticulado/create$', - views.TipoTaCreateView.as_view(), name='tipo_ta_create'), - url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)$', - views.TipoTaDetailView.as_view(), name='tipo_ta_detail'), - url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)/edit$', - views.TipoTaUpdateView.as_view(), name='tipo_ta_edit'), - url(r'^sistema/ta/config/tipo-textoarticulado/(?P[0-9]+)/delete$', - views.TipoTaDeleteView.as_view(), name='tipo_ta_delete'), + url(r'^sistema/ta/config/tipo/', + include(TipoTextoArticuladoCrud.get_urls())), + ] diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 897e18cd6..f09ed8a4f 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -50,7 +50,8 @@ from sapl.compilacao.models import (STATUS_TA_EDITION, STATUS_TA_PRIVATE, from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, DISPOSITIVO_SELECT_RELATED_EDIT, get_integrations_view_names) -from sapl.crud.base import Crud, CrudAux, CrudListView, make_pagination +from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, CrudAux, CrudListView,\ + make_pagination from sapl.settings import BASE_DIR @@ -431,88 +432,32 @@ class CompMixin(PermissionRequiredMixin): return rr -class TipoTaListView(CompMixin, ListView): +class TipoTextoArticuladoCrud(CrudAux): model = TipoTextoArticulado - paginate_by = 10 - verbose_name = model._meta.verbose_name - permission_required = 'compilacao.list_tipotextoarticulado' - - @property - def title(self): - return self.model._meta.verbose_name_plural - - @property - def create_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_create') - - -class TipoTaCreateView(CompMixin, FormMessagesMixin, CreateView): - model = TipoTextoArticulado - form_class = TipoTaForm - template_name = "crud/form.html" - form_valid_message = _('Registro criado com sucesso!') - form_invalid_message = _('O registro não foi criado.') - permission_required = 'compilacao.add_tipotextoarticulado' - - def get(self, request, *args, **kwargs): - self.object = None - form = self.get_form() - form.fields['content_type'] = forms.ChoiceField( - choices=choice_models_in_extenal_views(), - label=_('Modelo Integrado'), required=False) - - return self.render_to_response(self.get_context_data(form=form)) - - def get_success_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_detail', - kwargs={'pk': self.object.id}) - - @property - def cancel_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_list') - - -class TipoTaDetailView(CompMixin, DetailView): - model = TipoTextoArticulado - permission_required = 'compilacao.detail_tipotextoarticulado' - - -class TipoTaUpdateView(CompMixin, UpdateView): - model = TipoTextoArticulado - form_class = TipoTaForm - template_name = "crud/form.html" - permission_required = 'compilacao.change_tipotextoarticulado' - - def get(self, request, *args, **kwargs): - self.object = self.get_object() - form = self.get_form() - form.fields['content_type'] = forms.ChoiceField( - choices=choice_models_in_extenal_views(), - label=_('Modelo Integrado'), required=False) - return self.render_to_response(self.get_context_data(form=form)) - - def get_success_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_detail', - kwargs={'pk': self.kwargs['pk']}) - - @property - def cancel_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_detail', - kwargs={'pk': self.kwargs['pk']}) - - -class TipoTaDeleteView(CompMixin, DeleteView): - model = TipoTextoArticulado - template_name = "crud/confirm_delete.html" - permission_required = 'compilacao.delete_tipotextoarticulado' - - @property - def detail_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_detail', - kwargs={'pk': self.kwargs['pk']}) - - def get_success_url(self): - return reverse_lazy('sapl.compilacao:tipo_ta_list') + public = [RP_LIST, RP_DETAIL, ] + + class CreateView(CrudAux.CreateView): + form_class = TipoTaForm + + def get(self, request, *args, **kwargs): + self.object = None + form = self.get_form() + form.fields['content_type'] = forms.ChoiceField( + choices=choice_models_in_extenal_views(), + label=_('Modelo Integrado'), required=False) + + return self.render_to_response(self.get_context_data(form=form)) + + class UpdateView(CrudAux.UpdateView): + form_class = TipoTaForm + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + form = self.get_form() + form.fields['content_type'] = forms.ChoiceField( + choices=choice_models_in_extenal_views(), + label=_('Modelo Integrado'), required=False) + return self.render_to_response(self.get_context_data(form=form)) class TaListView(CompMixin, ListView): diff --git a/sapl/templates/compilacao/layouts.yaml b/sapl/templates/compilacao/layouts.yaml index 60895b185..20446ba19 100644 --- a/sapl/templates/compilacao/layouts.yaml +++ b/sapl/templates/compilacao/layouts.yaml @@ -37,3 +37,11 @@ TipoDispositivo: - rotulo_separador_variacao23:5 formato_variacao3 - rotulo_separador_variacao34:5 formato_variacao4 - rotulo_separador_variacao45:5 formato_variacao5 + + +TipoTextoArticulado: + {% trans 'Identificação Básica' %}: + - sigla:3 descricao:5 content_type:4 + {% trans 'Funcionalidaes' %}: + - participacao_social publicacao_func + - perfis diff --git a/sapl/templates/compilacao/tipotextoarticulado_detail.html b/sapl/templates/compilacao/tipotextoarticulado_detail.html deleted file mode 100644 index 5deffd227..000000000 --- a/sapl/templates/compilacao/tipotextoarticulado_detail.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends "base.html" %} {% load i18n %} {% load compilacao_filters %} -{% load common_tags %} - -{% block base_content %} - - {% block sections_nav %} - {% endblock %} - -
- {% block actions %} -
- {% if perms.compilacao.change_tipotextoarticulado %}{% trans 'Editar' %}{% endif %} - {% if perms.compilacao.delete_tipotextoarticulado %}{% trans 'Excluir' %}{% endif %} -
- {% endblock actions %} -
- - {% block detail_content %} {# TODO replace fieldset for something semantically correct, but with similar visual grouping style #} -
- {%trans 'Identificação Básica'%} -
-
-
- -

{{ object.sigla}}

-
-
- -
-
- -

{{ object.descricao}}

-
-
- -
-
- -

{{ object.content_type|default:""}}

-
-
-
-
- {%trans 'Funcionalidades'%} -
-
-
- -

{{ object.get_participacao_social_display}}

-
-
-
-
- -

{{ object.get_publicacao_func_display}}

-
-
-
-
-
-
- -
    - {% for perfil in object.perfis.all %} -
  • {{perfil}}
  • - {% endfor %} -
-
-
-
-
- {% endblock detail_content %} -{% endblock base_content %} diff --git a/sapl/templates/compilacao/tipotextoarticulado_list.html b/sapl/templates/compilacao/tipotextoarticulado_list.html deleted file mode 100644 index 3445306f5..000000000 --- a/sapl/templates/compilacao/tipotextoarticulado_list.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "base.html" %} -{% load i18n compilacao_filters common_tags menus%} - -{% block base_content %} - - - {% block actions %} - {% if perms.compilacao.add_tipotextoarticulado %} - - {% endif %} - {% endblock actions %} - -
-
- {% if not object_list %} -

{{ NO_ENTRIES_MSG }}

- {% else %} -

Resultados

Resultados - Foram encontrados {{ page.paginator.count }} registros
+ {% if page.paginator.count %} + Registros {{ page.start_index }} a {{ page.end_index }} de {{ page.paginator.count }} + {% endif %} +

- - - - - - - - - {% for tipo_ta in object_list %} - - - - - - {% endfor %} - -
{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'sigla' %}{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'descricao' %}{% fieldclass_verbose_name 'sapl.compilacao.models.TipoTextoArticulado' 'content_type' %}
{{ tipo_ta.sigla }}{{ tipo_ta.descricao }}{{ tipo_ta.content_type }}
- {%endif%} - {% include 'paginacao.html'%} -
- {% if perms.base.view_tabelas_auxiliares %} - - {% endif %} - -{% endblock %} diff --git a/sapl/templates/menu_tabelas_auxiliares.yaml b/sapl/templates/menu_tabelas_auxiliares.yaml index 6c8734805..2e8eb6045 100644 --- a/sapl/templates/menu_tabelas_auxiliares.yaml +++ b/sapl/templates/menu_tabelas_auxiliares.yaml @@ -126,7 +126,7 @@ css_class: head_title children: - title: {% trans 'Tipos de Textos Articulados' %} - url: sapl.compilacao:tipo_ta_list + url: sapl.compilacao:tipotextoarticulado_list css_class: btn btn-link - title: {% trans 'Tipos de Publicação' %} url: sapl.compilacao:tipopublicacao_list From 2ba8a37873b2bbaa61baa074ff6f78b60a058d05 Mon Sep 17 00:00:00 2001 From: Leandro Roberto da Silva Date: Sun, 10 Feb 2019 16:41:56 -0200 Subject: [PATCH 136/222] Fix #1540 migra frontend (#2485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * retira django-bootstrap3 do projeto sapl * retira bower sass-processor e libsass do projeto sapl * altera origem do django-admin-bootstrapped * commenta todas as entradas css e js em base.html * vue create sapl-frontend * add e configura django-webpack-loader * add vue.config.js e configura comunicação com webpack-loader * adequa staticfiles_dirs e ignora webpack-stats * cria bloco de expansão para vue_content * remove rotas do app hellow e impl multiplas entradas * add nova entrada para gereciamento de temas * cria plugin para carregar THEME_CUSTOM em .env * add bootstrap ao projeto e a configuração fixa de temas * add imports básicos para bootstrap * move assets para sapl-frontend * move assets para projetosexterno de tema e configura sapl project para leitura de temas através do .env * remove theme do sapl frontend project * retira link simbólico de entre projeto frontend e projeto de tema * retira scss do projeto django * altera btn-default/bootstrap3 para btn-outline-dark/bootstrap4 * altera btns de outline-dark para outlink-primary * migra pull-right para float-right * migra pull-left para float-left * migra btn-excluir para btn-outline-danger * add global entry and configure jquery * add jquery na entrada global e migra getCookie * remove row-fluid * muda active para link a * ajustes do botão salvar * ajuste botão add participação em comissão * ajuste do layout das mensagens de alerta e botao add detail detail * ajusta script de votação individual * ajuste eslint * altera origem da imagem para etiqueta.png * corrige eslint * migra tela de busca de autores para sapl-frontend * corrige fragmento de html para paginação * ajuste de js e html em protocolo * ajuste de layout no menu protocolo * ajuste no formulário de proposições para sapl_frontend * migra jquery-mask-plugin * remove código antigo do jquery-mask-plugin * migra jquery e algumas funções dependentes * migra tinymce * ajustes eslint * ajuste de sub menus * add campo de hora em mask * move jquery.runner.js para sapl-frontend * primeira versão com jquery runner funcionando * ajusta painel ao sapl-frontend * ajuste de tela de login * cria entr compilação p sapl-frontend e migra jsdiff * migra js das notas * add import bootstrap em module global * altera nome de função para iniciar editor de texto rico * move scss de compilação do tema para o frontend * adequa crud de notas de compilação ao form do django 1.11 * retira render padrão scripts css e js de image_cropping * integra jquery runner e image cropping com jquery e lodash global * ajustes de eslint em compilação * ajuste de layout para notas e de código eslint * ajuste de layout para Vides da app compilação * altera configurações para pasta público de tema ser importada no build * ajustes de eslint * ajusta TAs embedded de normas para sapl-frontend * migra botões de compilação para bootstrap4 * migra componente alert para bootstrap 4 * altera chamada a jQuery e resolve conflito com bootstrap * altera travis.yaml * corrige entrada doo sapl-oficial-theme para instalação trivial * testa modo de definir versão do node no travis * teste de configuração do travis * ajuste de teste e das telas de erro 404 e 500 * Configura sapl-frontend e webpackloader Configura sapl-frontend e webpack-loader com código de produção já esportado para a sapl/static. Desta forma, tanto no travis como no docker não existe a necessidade de instalação de node, npm e/ou yarn * configura docker e localização do webpack-stats.json * inicia migração da edição de dispositivos * ajuste de chunks * resume forma de lidar com com chunks css e js * cria template tag para tratar chunk-vendors * corrige menu de configuração dos TAs * migra barra inferior da vigencia * migra linha do tempo de vigências * ajuste nos menus do topo da edição dinamica da compilação * frontend produção * ajuste de blocos * migra layout da edição dinamica de dispositivos originais * ajuste da seleção de tipos de vigências * migra frontend de edição dinâmica de dispositivos * ajst dropdown de seleção de editor de dispositivos * migra subnav da edição avançada de dispositivos * separa frontend em outro projeto * Altera how-to de instalação do ambiente dev Altera how-to de instalação do ambiente de desenvolvimento com novas instruções para colaboração com o sapl-frontend * migra barra de navegação de parents de dispositivos * Alterações no how-to para colab com sapl-frontend Alterações no how-to para colab com sapl-frontend * ajuste de docs * sapl-frontend reinseriu language pt-br datepicker * ajuste no form autoria multicreate para sapl-frontend * add webpack blocks no index de painel * refatora layout do painel para bootstrap4 * migra cadastro de autor * migra frontend da manutenção de tipos de proposição * migra tela de incorporação * remove templates de compilação * ajusta layout do form de pesquisa textual * ajustes de layout no painel * primeira versão checada do frontend --- .gitignore | 1 + .travis.yml | 2 - Dockerfile | 13 +- docs/instalacao31.rst | 106 +- requirements/requirements.txt | 13 +- sapl/base/forms.py | 8 +- sapl/base/templatetags/common_tags.py | 12 + sapl/base/tests/test_login.py | 8 +- sapl/compilacao/forms.py | 65 +- sapl/crispy_layout_mixin.py | 13 +- sapl/crud/base.py | 2 +- sapl/crud/tests/stub_app/templates/base.html | 4 +- sapl/materia/forms.py | 113 +- .../migrations/0039_auto_20190209_2346.py | 21 + sapl/materia/models.py | 16 +- sapl/materia/views.py | 2 +- sapl/parlamentares/views.py | 4 + sapl/protocoloadm/forms.py | 6 +- sapl/settings.py | 54 +- sapl/static/css/chunk-vendors.f109b7f2.css | 101 + sapl/static/css/compilacao.1e862898.css | 1 + sapl/static/css/global.d2e0a784.css | 1 + sapl/static/css/painel.61177241.css | 1 + sapl/static/fonts/fa-brands-400.3186ebd2.eot | Bin 0 -> 125320 bytes .../static/fonts/fa-brands-400.662c24d0.woff2 | Bin 0 -> 72148 bytes sapl/static/fonts/fa-brands-400.a995bae1.ttf | Bin 0 -> 125016 bytes sapl/static/fonts/fa-brands-400.c7d7a2a1.woff | Bin 0 -> 84568 bytes .../fonts/fa-regular-400.6a9d786e.woff2 | Bin 0 -> 13608 bytes .../static/fonts/fa-regular-400.72f15fa7.woff | Bin 0 -> 16812 bytes sapl/static/fonts/fa-regular-400.80efa56b.eot | Bin 0 -> 34388 bytes sapl/static/fonts/fa-regular-400.fcb220ee.ttf | Bin 0 -> 34092 bytes sapl/static/fonts/fa-solid-900.20c189aa.ttf | Bin 0 -> 186228 bytes sapl/static/fonts/fa-solid-900.3638e62e.woff2 | Bin 0 -> 74320 bytes sapl/static/fonts/fa-solid-900.9a52a4e9.eot | Bin 0 -> 186512 bytes sapl/static/fonts/fa-solid-900.9c73abbd.woff | Bin 0 -> 96248 bytes sapl/static/img/fa-brands-400.e4fed0a5.svg | 3300 ++++++++++++ sapl/static/img/fa-regular-400.304f31f4.svg | 803 +++ sapl/static/img/fa-solid-900.c8ea4c79.svg | 4520 +++++++++++++++++ .../img/ui-icons_2694e8_256x240.274157b3.png | Bin 0 -> 4676 bytes .../img/ui-icons_2e83ff_256x240.602e5d4d.png | Bin 0 -> 4676 bytes .../img/ui-icons_3d80b3_256x240.24fcd129.png | Bin 0 -> 4676 bytes .../img/ui-icons_72a7cf_256x240.55a4c5ce.png | Bin 0 -> 4676 bytes .../img/ui-icons_ffffff_256x240.bb2a88be.png | Bin 0 -> 6487 bytes sapl/static/js/app.js | 252 - sapl/static/js/chunk-vendors.406f40ec.js | 2572 ++++++++++ sapl/static/js/compilacao.9bf86742.js | 240 + sapl/static/js/compilacao.js | 276 - sapl/static/js/compilacao_edit.js | 610 --- sapl/static/js/compilacao_notas.js | 143 - sapl/static/js/compilacao_view.js | 178 - sapl/static/js/global.594a728f.js | 274 + sapl/static/js/jquery.runner.js | 296 -- sapl/static/js/painel.518bdc14.js | 192 + sapl/static/styles/_header.scss | 5 - sapl/static/styles/_home_index.scss | 188 - sapl/static/styles/app.scss | 468 -- sapl/static/styles/compilacao.scss | 1542 ------ sapl/templates/404.html | 46 +- sapl/templates/500.html | 44 +- sapl/templates/auth/user_list.html | 2 +- sapl/templates/base.html | 144 +- .../base/EstatisticasAcessoNormas_filter.html | 4 +- sapl/templates/base/RelatorioAtas_filter.html | 4 +- .../base/RelatorioAudiencia_filter.html | 4 +- ...elatorioDataFimPrazoTramitacao_filter.html | 4 +- .../RelatorioHistoricoTramitacao_filter.html | 4 +- ...latorioMateriasPorAnoAutorTipo_filter.html | 4 +- .../RelatorioMateriasPorAutor_filter.html | 4 +- ...RelatorioMateriasPorTramitacao_filter.html | 4 +- .../base/RelatorioNormaMes_filter.html | 4 +- .../base/RelatorioNormasVigencia_filter.html | 4 +- .../base/RelatorioPresencaSessao_filter.html | 4 +- .../base/RelatorioReuniao_filter.html | 4 +- sapl/templates/base/autor_form.html | 6 +- sapl/templates/base/casalegislativa_list.html | 4 +- sapl/templates/base/login.html | 12 +- .../bootstrap4/layout/formactions.html | 13 + sapl/templates/comissoes/composicao_list.html | 8 +- .../compilacao/ajax_actions_dinamic_edit.html | 133 +- .../ajax_actions_registro_inclusao.html | 2 +- .../templates/compilacao/base_compilacao.html | 12 + .../compilacao/dispositivo_form.html | 62 +- .../dispositivo_form_alteracao.html | 4 +- .../dispositivo_form_definidor_vigencia.html | 2 +- .../dispositivo_form_edicao_basica.html | 2 +- .../compilacao/dispositivo_form_parents.html | 24 +- .../compilacao/dispositivo_form_search.html | 6 +- .../dispositivo_form_search_fragment.html | 2 +- .../compilacao/dispositivo_form_vigencia.html | 2 +- .../layout/bootstrap_btn_checkbox.html | 2 +- sapl/templates/compilacao/messages.html | 4 +- .../compilacao/publicacao_detail.html | 6 +- .../templates/compilacao/publicacao_list.html | 4 +- sapl/templates/compilacao/subnav.html | 25 + sapl/templates/compilacao/text_edit.html | 24 +- .../templates/compilacao/text_edit_bloco.html | 4 +- sapl/templates/compilacao/text_list.html | 96 +- .../compilacao/text_list__embedded.html | 113 +- .../compilacao/text_list__print_version.html | 8 - .../compilacao/text_notificacoes.html | 8 +- .../compilacao/textoarticulado_detail.html | 34 +- .../compilacao/textoarticulado_list.html | 4 +- .../textoarticulado_menu_config.html | 16 +- sapl/templates/crud/confirm_delete.html | 2 +- sapl/templates/crud/detail.html | 20 +- sapl/templates/crud/detail_detail.html | 20 +- sapl/templates/crud/list.html | 8 +- .../floppyforms/image_thumbnail.html | 2 +- sapl/templates/index.html | 361 +- .../materia/adicionar_varias_autorias.html | 4 +- sapl/templates/materia/autoria_list.html | 2 +- .../materia/autoria_multicreate_form.html | 6 +- .../materia/confirmar_proposicao.html | 6 +- .../materia/materialegislativa_detail.html | 2 +- .../materia/materialegislativa_filter.html | 8 +- .../materia/materialegislativa_list.html | 2 +- .../materia/proposicao_confirm_return.html | 4 +- sapl/templates/materia/proposicao_detail.html | 20 +- sapl/templates/materia/proposicao_form.html | 2 +- sapl/templates/materia/relatoria_form.html | 2 +- .../materia/tipoproposicao_form.html | 5 +- sapl/templates/menu_tabelas_auxiliares.yaml | 2 +- sapl/templates/menus/nav.html | 10 +- sapl/templates/menus/subnav.html | 12 +- .../templates/norma/normajuridica_detail.html | 30 +- .../templates/norma/normajuridica_filter.html | 8 +- sapl/templates/paginacao.html | 66 +- sapl/templates/painel/index.html | 180 +- sapl/templates/painel/mensagem.html | 162 +- sapl/templates/painel/parlamentares.html | 60 +- sapl/templates/painel/votacao.html | 199 +- sapl/templates/painel/voto_nominal.html | 24 +- .../parlamentares/composicaomesa_form.html | 10 +- sapl/templates/parlamentares/frente_form.html | 10 +- .../parlamentar_perfil_publico.html | 2 +- .../templates/parlamentares/votante_list.html | 4 +- .../protocoloadm/MateriaTemplate.html | 2 +- .../protocoloadm/anular_protocoloadm.html | 13 +- .../protocoloadm/detail_doc_detail.html | 8 +- .../documentoadministrativo_filter.html | 8 +- .../pesquisa_documento_detail.html | 4 +- .../protocoloadm/proposicoes_detail.html | 10 +- .../protocoloadm/protocolar_documento.html | 19 +- .../protocoloadm/protocolar_materia.html | 14 +- .../protocoloadm/protocolo_filter.html | 17 +- .../protocoloadm/protocolo_list.html | 6 +- .../protocoloadm/protocolo_mostrar.html | 12 +- .../protocoloadm/protocoloadm_detail.html | 33 +- .../tramitacaoadministrativo_detail.html | 8 +- sapl/templates/search/search.html | 208 +- .../adicionar_varias_materias_expediente.html | 8 +- .../adicionar_varias_materias_ordem.html | 8 +- sapl/templates/sessao/expediente.html | 6 +- .../sessao/expedientemateria_form.html | 4 +- .../sessao/expedientemateria_list.html | 4 +- sapl/templates/sessao/mesa.html | 8 +- sapl/templates/sessao/ocorrencia_sessao.html | 2 +- sapl/templates/sessao/ordemdia_list.html | 4 +- sapl/templates/sessao/painel.html | 3 +- .../sessao/sessaoplenaria_filter.html | 12 +- .../templates/sessao/sessaoplenaria_list.html | 2 +- sapl/templates/sessao/votacao/nominal.html | 2 +- .../sessao/votacao/votacao_nominal_bloco.html | 2 +- .../votacao/votacao_simbolica_bloco.html | 2 +- sapl/utils.py | 2 +- setup.py | 13 +- start.sh | 5 - webpack-stats.json | 1 + 168 files changed, 13551 insertions(+), 5506 deletions(-) create mode 100644 sapl/materia/migrations/0039_auto_20190209_2346.py create mode 100644 sapl/static/css/chunk-vendors.f109b7f2.css create mode 100644 sapl/static/css/compilacao.1e862898.css create mode 100644 sapl/static/css/global.d2e0a784.css create mode 100644 sapl/static/css/painel.61177241.css create mode 100644 sapl/static/fonts/fa-brands-400.3186ebd2.eot create mode 100644 sapl/static/fonts/fa-brands-400.662c24d0.woff2 create mode 100644 sapl/static/fonts/fa-brands-400.a995bae1.ttf create mode 100644 sapl/static/fonts/fa-brands-400.c7d7a2a1.woff create mode 100644 sapl/static/fonts/fa-regular-400.6a9d786e.woff2 create mode 100644 sapl/static/fonts/fa-regular-400.72f15fa7.woff create mode 100644 sapl/static/fonts/fa-regular-400.80efa56b.eot create mode 100644 sapl/static/fonts/fa-regular-400.fcb220ee.ttf create mode 100644 sapl/static/fonts/fa-solid-900.20c189aa.ttf create mode 100644 sapl/static/fonts/fa-solid-900.3638e62e.woff2 create mode 100644 sapl/static/fonts/fa-solid-900.9a52a4e9.eot create mode 100644 sapl/static/fonts/fa-solid-900.9c73abbd.woff create mode 100644 sapl/static/img/fa-brands-400.e4fed0a5.svg create mode 100644 sapl/static/img/fa-regular-400.304f31f4.svg create mode 100644 sapl/static/img/fa-solid-900.c8ea4c79.svg create mode 100644 sapl/static/img/ui-icons_2694e8_256x240.274157b3.png create mode 100644 sapl/static/img/ui-icons_2e83ff_256x240.602e5d4d.png create mode 100644 sapl/static/img/ui-icons_3d80b3_256x240.24fcd129.png create mode 100644 sapl/static/img/ui-icons_72a7cf_256x240.55a4c5ce.png create mode 100644 sapl/static/img/ui-icons_ffffff_256x240.bb2a88be.png delete mode 100644 sapl/static/js/app.js create mode 100644 sapl/static/js/chunk-vendors.406f40ec.js create mode 100644 sapl/static/js/compilacao.9bf86742.js delete mode 100644 sapl/static/js/compilacao.js delete mode 100644 sapl/static/js/compilacao_edit.js delete mode 100644 sapl/static/js/compilacao_notas.js delete mode 100644 sapl/static/js/compilacao_view.js create mode 100644 sapl/static/js/global.594a728f.js delete mode 100644 sapl/static/js/jquery.runner.js create mode 100644 sapl/static/js/painel.518bdc14.js delete mode 100644 sapl/static/styles/_header.scss delete mode 100644 sapl/static/styles/_home_index.scss delete mode 100644 sapl/static/styles/app.scss delete mode 100644 sapl/static/styles/compilacao.scss create mode 100644 sapl/templates/bootstrap4/layout/formactions.html create mode 100644 sapl/templates/compilacao/base_compilacao.html create mode 100644 sapl/templates/compilacao/subnav.html create mode 100644 webpack-stats.json diff --git a/.gitignore b/.gitignore index dfdeb2b5c..c656b3b8f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ __pycache__/ # Nodejs node_modules/ +yarn.lock # Distribution / packaging .Python diff --git a/.travis.yml b/.travis.yml index f54ee6d20..80532c789 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ install: - pip install -r requirements/test-requirements.txt before_script: - - npm install -g bower - cp sapl/.env_test sapl/.env - psql -c "CREATE USER sapl WITH PASSWORD 'sapl'" -U postgres; - psql -c "CREATE DATABASE sapl OWNER sapl;" -U postgres @@ -18,7 +17,6 @@ before_script: script: - ./manage.py migrate - - ./manage.py bower install - py.test --create-db # - ./scripts/django/test_and_check_qa.sh diff --git a/Dockerfile b/Dockerfile index f4953de84..8c2dc0fb5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM alpine:3.8 ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \ python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \ - nodejs npm py3-lxml py3-magic postgresql-client poppler-utils antiword \ + nodejs py3-lxml py3-magic postgresql-client poppler-utils antiword \ curl jq openssh-client vim openssh-client bash RUN apk update --update-cache && apk upgrade @@ -17,9 +17,7 @@ RUN apk add --no-cache python3 nginx tzdata && \ rm -f /etc/nginx/conf.d/* RUN mkdir -p /var/interlegis/sapl && \ - apk add --update --no-cache $BUILD_PACKAGES && \ - npm install -g bower && \ - npm cache verify + apk add --update --no-cache $BUILD_PACKAGES WORKDIR /var/interlegis/sapl/ @@ -37,13 +35,6 @@ COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env # Configura timezone para BRT # RUN cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime && echo "America/Sao_Paulo" > /etc/timezone -# manage.py bower install bug: https://github.com/nvbn/django-bower/issues/51 - -# compilescss - Precompile all occurrences of your SASS/SCSS files for the whole project into css files - -RUN python3 manage.py bower_install --allow-root && \ - python3 manage.py compilescss - RUN python3 manage.py collectstatic --noinput --clear # Remove .env(fake) e sapl.db da imagem diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index 6e9146ee4..a9752990f 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -28,15 +28,7 @@ Instalar as seguintes dependências do sistema:: pkg-config postgresql postgresql-contrib pgadmin3 python-psycopg2 \ software-properties-common build-essential libxml2-dev libjpeg-dev \ libmysqlclient-dev libssl-dev libffi-dev libxslt1-dev python3-setuptools \ - python3-pip curl poppler-utils antiword default-jre python3-venv - - sudo -i - curl -sL https://deb.nodesource.com/setup_8.x | bash - - exit - sudo apt-get install nodejs - - sudo npm install npm -g - sudo npm install -g bower + python3-pip poppler-utils antiword default-jre python3-venv Instalar o virtualenv usando python 3 para o projeto. ----------------------------------------------------- @@ -153,6 +145,8 @@ Criação da `SECRET_KEY =1.11,<2.0 -django-bootstrap3==11.0.0 django-haystack==2.8.1 django-filter==2.0.0 djangorestframework==3.9.0 dj-database-url==0.5.0 -django-bower==5.2.0 django-braces==1.9.0 django-crispy-forms==1.7.2 django-floppyforms==1.7.0 django-extra-views==0.12.0 django-model-utils==3.1.2 -django-sass-processor==0.7.2 django-reversion==3.0.2 django-reversion-compare==0.8.6 django-speedinfo==1.4.0 django-extensions==2.1.4 django-image-cropping==1.2 +django-webpack-loader==0.6.0 easy-thumbnails==2.5 -libsass==0.17.0 python-decouple==3.1 psycopg2-binary==2.7.6.1 pyyaml==4.2b1 @@ -34,6 +31,10 @@ whoosh==2.7.4 git+git://github.com/interlegis/trml2pdf.git git+git://github.com/jasperlittle/django-rest-framework-docs -git+git://github.com/rubgombar1/django-admin-bootstrapped.git +git+git://github.com/interlegis/django-admin-bootstrapped@custom-for-sapl31 -django-compressor==2.2 \ No newline at end of file +#django-compressor==2.2 +#django-bootstrap3==11.0.0 +#django-bower==5.2.0 +#django-sass-processor==0.7.2 +#libsass==0.17.0 diff --git a/sapl/base/forms.py b/sapl/base/forms.py index f24868ff6..d97ed1804 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -394,7 +394,7 @@ class AutorForm(ModelForm): placeholder=_('Pesquisar por possíveis autores para ' 'o Tipo de Autor selecionado.')), StrictButton( - _('Filtrar'), css_class='btn-default btn-filtrar-autor', + _('Filtrar'), css_class='btn-outline-primary btn-filtrar-autor', type='button')), css_class='hidden', data_action='create', @@ -402,9 +402,9 @@ class AutorForm(ModelForm): data_field='autor_related') autor_select = Row(to_column(('tipo', 3)), - Div(to_column(('nome', 5)), - to_column(('cargo', 4)), - css_class="div_nome_cargo"), + Div(to_column(('nome', 7)), + to_column(('cargo', 5)), + css_class="div_nome_cargo row col"), to_column((autor_related, 9)), to_column((Div( Field('autor_related'), diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 884a6968f..3c72b1654 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -1,5 +1,7 @@ from django import template from django.template.defaultfilters import stringfilter +from django.utils.safestring import mark_safe +from webpack_loader import utils from sapl.base.models import AppConfig from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa, Proposicao @@ -274,3 +276,13 @@ def filiacao_data_filter(parlamentar, data_inicio): @register.filter def filiacao_intervalo_filter(parlamentar, date_range): return filiacao_data(parlamentar, date_range[0], date_range[1]) + + +@register.simple_tag +def render_chunk_vendors(extension=None): + try: + tags = utils.get_as_tags( + 'chunk-vendors', extension=extension, config='DEFAULT', attrs='') + return mark_safe('\n'.join(tags)) + except: + return '' diff --git a/sapl/base/tests/test_login.py b/sapl/base/tests/test_login.py index 91665ea8d..7fe7672e5 100755 --- a/sapl/base/tests/test_login.py +++ b/sapl/base/tests/test_login.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -import pytest from django.contrib.auth import get_user_model +import pytest + pytestmark = pytest.mark.django_db @@ -12,14 +13,15 @@ def user(): def test_login_aparece_na_barra_para_usuario_nao_logado(client): response = client.get('/') - assert '' in str( + assert '' in str( response.content) def test_username_do_usuario_logado_aparece_na_barra(client, user): assert client.login(username='jfirmino', password='123') response = client.get('/') - assert 'Login' not in str(response.content) + assert 'Login' not in str( + response.content) assert 'jfirmino' in str(response.content) assert 'Sair' in str(response.content) diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index 3c4275bee..0e4f933d7 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -23,7 +23,8 @@ from sapl.compilacao.models import (NOTAS_PUBLICIDADE_CHOICES, TipoTextoArticulado, TipoVide, VeiculoPublicacao, Vide) from sapl.compilacao.utils import DISPOSITIVO_SELECT_RELATED -from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row +from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row,\ + form_actions from sapl.utils import YES_NO_CHOICES error_messages = { @@ -256,19 +257,22 @@ class NotaForm(ModelForm): ]) buttons = FormActions( - HTML('' - '%s' % _('Cancelar')), + *[ + HTML('%s' % _('Cancelar')) + ], Button( 'submit-form', 'Salvar', - css_class='btn btn-primary pull-right') + css_class='btn btn-primary float-right'), + css_class='form-group row justify-content-between mr-1 ml-1' ) self.helper = FormHelper() self.helper.layout = Layout( Div( - Div(HTML(_('Notas')), css_class='panel-heading'), + Div(HTML(_('Notas')), css_class='card-header bg-light'), Div( row1, to_row([(Field( @@ -279,9 +283,9 @@ class NotaForm(ModelForm): placeholder=_('URL Externa (opcional)')), 12)]), row3, to_row([(buttons, 12)]), - css_class="panel-body" + css_class="card-body" ), - css_class="panel panel-primary" + css_class="card" ) ) @@ -328,12 +332,15 @@ class VideForm(ModelForm): def __init__(self, *args, **kwargs): buttons = FormActions( - HTML('' - '%s' % _('Cancelar')), + *[ + HTML('%s' % _('Cancelar')) + ], Button( 'submit-form', 'Salvar', - css_class='btn-primary pull-right') + css_class='btn btn-primary float-right'), + css_class='form-group row justify-content-between mr-1 ml-1' ) dispositivo_ref = Field( @@ -359,15 +366,15 @@ class VideForm(ModelForm): self.helper = FormHelper() self.helper.layout = Layout( Div( - Div(HTML(_('Vides')), css_class='car-header'), + Div(HTML(_('Vides')), css_class='card-header bg-light'), Div( to_column((fields_form[0], 6)), to_column((fields_form[1], 6)), to_column(('dispositivo_base', 0)), to_column(('pk', 0)), - css_class="card-body" + css_class="card-body row" ), - css_class="card bg-light" + css_class="card" ) ) @@ -671,7 +678,7 @@ class DispositivoEdicaoBasicaForm(ModelForm): cancel_label = _('Fechar') more = [ - HTML('%s' % + HTML('%s' % cancel_label), ] @@ -680,7 +687,7 @@ class DispositivoEdicaoBasicaForm(ModelForm): if not (inst.tipo_dispositivo.dispositivo_de_alteracao and inst.tipo_dispositivo.dispositivo_de_articulacao): btns_excluir = [ - HTML('%s' % + HTML('%s' % _('Cancelar')), ] - more.append(Submit('salvar', _('Salvar'), css_class='pull-right')) + more.append(Submit('salvar', _('Salvar'), css_class='float-right')) buttons = FormActions(*more, css_class='form-group') - _fields = [Div(*layout, css_class="row-fluid")] + \ + _fields = [Div(*layout, css_class="row")] + \ [to_row([(buttons, 12)])] self.helper = FormHelper() @@ -1414,14 +1421,14 @@ class DispositivoRegistroRevogacaoForm(Form): layout.append(Field('dispositivo_search_form')) more = [ - HTML('%s' % + HTML('%s' % _('Cancelar')), ] - more.append(Submit('salvar', _('Salvar'), css_class='pull-right')) + more.append(Submit('salvar', _('Salvar'), css_class='float-right')) buttons = FormActions(*more, css_class='form-group') - _fields = [Div(*layout, css_class="row-fluid")] + \ + _fields = [Div(*layout, css_class="row")] + \ [to_row([(buttons, 12)])] self.helper = FormHelper() @@ -1464,14 +1471,14 @@ class DispositivoRegistroInclusaoForm(Form): layout.append(Div(css_class="allowed_inserts col-md-12")) more = [ - HTML('%s' % + HTML('%s' % _('Cancelar')), ] - # more.append(Submit('salvar', _('Salvar'), css_class='pull-right')) + # more.append(Submit('salvar', _('Salvar'), css_class='float-right')) buttons = FormActions(*more, css_class='form-group') - _fields = [Div(*layout, css_class="row-fluid")] + \ + _fields = [Div(*layout, css_class="row")] + \ [to_row([(buttons, 12)])] self.helper = FormHelper() diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index 9b2f0867b..245be6b82 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -1,6 +1,5 @@ from math import ceil -import rtyaml from crispy_forms.bootstrap import FormActions from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit @@ -8,6 +7,7 @@ from django import template from django.core.urlresolvers import reverse, reverse_lazy from django.utils import formats from django.utils.translation import ugettext as _ +import rtyaml def heads_and_tails(list_of_lists): @@ -21,7 +21,7 @@ def to_column(name_span): def to_row(names_spans): - return Div(*map(to_column, names_spans), css_class='row-fluid') + return Div(*map(to_column, names_spans), css_class='row') def to_fieldsets(fields): @@ -35,7 +35,8 @@ def to_fieldsets(fields): def form_actions(more=[Div(css_class='clearfix')], - label=_('Salvar'), name='salvar', css_class='pull-right', disabled=True): + label=_('Salvar'), name='salvar', + css_class='float-right', disabled=True): if disabled: doubleclick = 'this.form.submit();this.disabled=true;' @@ -43,10 +44,12 @@ def form_actions(more=[Div(css_class='clearfix')], doubleclick = 'return true;' return FormActions( + *more, Submit(name, label, css_class=css_class, # para impedir resubmissão do form onclick=doubleclick), - *more) + css_class='form-group row justify-content-between' + ) class SaplFormLayout(Layout): @@ -58,7 +61,7 @@ class SaplFormLayout(Layout): if not buttons: buttons = form_actions(label=save_label, more=[ HTML('%s' % cancel_label) + ' class="btn btn-dark">%s' % cancel_label) if cancel_label else None]) _fields = list(to_fieldsets(fields)) diff --git a/sapl/crud/base.py b/sapl/crud/base.py index faa0e1287..ca5469bf0 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -160,7 +160,7 @@ class ListWithSearchForm(forms.Form): placeholder=_('Filtrar Lista'), css_class='input-lg'), StrictButton( - _('Filtrar'), css_class='btn-default btn-lg', + _('Filtrar'), css_class='btn-outline-primary btn-lg', type='submit')) ) diff --git a/sapl/crud/tests/stub_app/templates/base.html b/sapl/crud/tests/stub_app/templates/base.html index 8a9dc002b..fcf92e5eb 100644 --- a/sapl/crud/tests/stub_app/templates/base.html +++ b/sapl/crud/tests/stub_app/templates/base.html @@ -12,9 +12,9 @@ {# Feedback messages #} {% for message in messages %} -