Browse Source

Conserta o clean

pull/1323/head
Eduardo Calil 9 years ago
parent
commit
7796935fa4
  1. 5
      Dockerfile
  2. 0
      bug.txt
  3. 2
      docker-compose.yml
  4. 8
      docs/instalacao31.rst
  5. 1
      envfile
  6. 24
      sapl/base/migrations/0004_auto_20170714_1838.py
  7. 4
      sapl/base/models.py
  8. 5
      sapl/base/urls.py
  9. 21
      sapl/base/views.py
  10. 26
      sapl/legacy/migracao_documentos.py
  11. 142
      sapl/legacy/migration.py
  12. 4
      sapl/legacy/scripts/fix_tables.sql
  13. 68
      sapl/materia/forms.py
  14. 19
      sapl/materia/views.py
  15. 6
      sapl/norma/forms.py
  16. 12
      sapl/painel/views.py
  17. 34
      sapl/protocoloadm/forms.py
  18. 41
      sapl/protocoloadm/views.py
  19. 27
      sapl/sessao/views.py
  20. 4
      sapl/settings.py
  21. 2
      sapl/templates/crud/detail.html
  22. 10
      sapl/templates/materia/materialegislativa_filter.html
  23. 2
      sapl/templates/navbar.yaml
  24. 45
      sapl/templates/painel/index.html
  25. 2
      sapl/templates/protocoloadm/MateriaTemplate.html
  26. 2
      sapl/templates/protocoloadm/protocolo_list.html
  27. 8
      sapl/templates/search/search.html
  28. 8
      sapl/templates/sessao/mesa.html
  29. 20
      sapl/templates/sessao/pauta_sessao_detail.html
  30. 35
      scrap-js.js

5
Dockerfile

@ -4,7 +4,7 @@ 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 py3-lxml \
py3-magic postgresql-client poppler-utils vim
RUN apk add --no-cache python3 nginx && \
RUN apk add --no-cache python3 nginx tzdata && \
python3 -m ensurepip && \
rm -r /usr/lib/python*/ensurepip && \
pip3 install --upgrade pip setuptools && \
@ -30,6 +30,9 @@ RUN pip install -r /var/interlegis/sapl/requirements/dev-requirements.txt --upgr
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

0
bug.txt

2
docker-compose.yml

@ -10,7 +10,7 @@ sapldb:
ports:
- "5532:5432"
sapl:
image: interlegis/sapl:3.1.11-BETA
image: interlegis/sapl:3.1.17-BETA
volumes:
- sapl_data:/var/interlegis/sapl/data
- sapl_media:/var/interlegis/sapl/media

8
docs/instalacao31.rst

@ -93,7 +93,7 @@ Criar o ambiente virtual de desenvolvimento para o SAPL
-------------------------------------------------------
* ::
mkvirtualenv sapl -a /var/interlegis/sapl -p /usr/bin/python3
mkvirtualenv -a /var/interlegis/sapl -p python3 -r requirements/requirements.txt sapl
Instalação e configuração das dependências do projeto
-----------------------------------------------------
@ -119,9 +119,9 @@ Instalação e configuração das dependências do projeto
* (caso você já possua uma instalação do postrgresql anterior ao processo de instalação do ambiente de desenvolvimento do SAPL em sua máquina e sábia como fazer, esteja livre para proceder como desejar, porém, ao configurar o arquivo ``.env`` no próximo passo, as mesmas definições deverão ser usadas)
* **Ajustar as permissões - onde sapl31 trocar por usuario**::
* **Ajustar as permissões - onde $USER trocar por usuario**::
sudo chown -R sapl31:sapl31 /var/interlegis/
eval $(echo "sudo chown -R $USER:$USER /var/interlegis/")
@ -178,7 +178,7 @@ Copie a chave que aparecerá, edite o arquivo .env e altere o valor do parâmetr
* Instalar as dependências do ``bower``::
sudo chown -R sapl31:sapl31 /home/sapl31/
eval $(echo "sudo chown -R $USER:$USER /home/$USER/")
./manage.py bower install
* Atualizar e/ou criar as tabelas da base de dados para refletir o modelo da versão clonada::

1
envfile

@ -1 +0,0 @@
EMAIL_HOST_USER=foo

24
sapl/base/migrations/0004_auto_20170714_1838.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-07-14 18:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0003_auto_20170519_1106'),
]
operations = [
migrations.RemoveField(
model_name='problemamigracao',
name='eh_importante',
),
migrations.AddField(
model_name='problemamigracao',
name='critico',
field=models.BooleanField(default=False, verbose_name='Crítico'),
),
]

4
sapl/base/models.py

@ -65,8 +65,8 @@ class ProblemaMigracao(models.Model):
problema = models.CharField(max_length=300, verbose_name=_('Problema'))
descricao = models.CharField(max_length=300, verbose_name=_('Descrição'))
eh_stub = models.BooleanField(verbose_name=_('É stub?'))
eh_importante = models.BooleanField(
default=False, verbose_name=_('É importante?'))
critico = models.BooleanField(
default=False, verbose_name=_('Crítico'))
class Meta:
verbose_name = _('Problema na Migração')

5
sapl/base/urls.py

@ -16,7 +16,8 @@ from .views import (AppConfigCrud, CasaLegislativaCrud, HelpView,
RelatorioMateriasPorAnoAutorTipoView,
RelatorioMateriasPorAutorView,
RelatorioMateriasTramitacaoView,
RelatorioPresencaSessaoView)
RelatorioPresencaSessaoView,
SaplSearchView)
app_name = AppConfig.name
@ -100,6 +101,6 @@ urlpatterns = [
name='login'),
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'),
url(r'^sistema/search/', include('haystack.urls')),
url(r'^sistema/search/', SaplSearchView(), name='haystack_search'),
] + recuperar_senha

21
sapl/base/views.py

@ -14,6 +14,8 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView
from django_filters.views import FilterView
from haystack.views import SearchView
from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm
from sapl.base.models import Autor, TipoAutor
from sapl.crud.base import CrudAux
@ -454,3 +456,22 @@ class AppConfigCrud(CrudAux):
def get(self, request, *args, **kwargs):
return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
class SaplSearchView(SearchView):
results_per_page = 10
def get_context(self):
context = super(SaplSearchView, self).get_context()
if 'models' in self.request.GET:
models = self.request.GET.getlist('models')
else:
models = []
context['models'] = ''
for m in models:
context['models'] = context['models'] + '&models=' + m
return context

26
sapl/legacy/migracao_documentos.py

@ -14,7 +14,6 @@ from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo,
DocumentoAdministrativo)
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MEDIA_ROOT
from sapl.utils import delete_texto, save_texto
# MIGRAÇÃO DE DOCUMENTOS ###################################################
EXTENSOES = {
@ -192,29 +191,7 @@ def migrar_docs_por_ids(tipo):
tipo.__name__, id, destino))
def desconecta_sinais_indexacao():
post_save.disconnect(save_texto, NormaJuridica)
post_save.disconnect(save_texto, DocumentoAcessorio)
post_save.disconnect(save_texto, MateriaLegislativa)
post_delete.disconnect(delete_texto, NormaJuridica)
post_delete.disconnect(delete_texto, DocumentoAcessorio)
post_delete.disconnect(delete_texto, MateriaLegislativa)
def conecta_sinais_indexacao():
post_save.connect(save_texto, NormaJuridica)
post_save.connect(save_texto, DocumentoAcessorio)
post_save.connect(save_texto, MateriaLegislativa)
post_delete.connect(delete_texto, NormaJuridica)
post_delete.connect(delete_texto, DocumentoAcessorio)
post_delete.connect(delete_texto, MateriaLegislativa)
def migrar_documentos():
# precisamos excluir os sinais de post_save e post_delete para não que o
# computador não trave com a criação de threads desnecessárias
desconecta_sinais_indexacao()
# aqui supomos que uma pasta chamada sapl_documentos está em MEDIA_ROOT
# com o conteúdo da pasta de mesmo nome do zope
# Os arquivos da pasta serão movidos para a nova estrutura e a pasta será
@ -241,6 +218,3 @@ def migrar_documentos():
len(sobrando)))
for doc in sobrando:
print(' {}'. format(doc))
#
# reconexão dos sinais desligados no inicio da migração de documentos
conecta_sinais_indexacao()

142
sapl/legacy/migration.py

@ -12,7 +12,7 @@ from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import OperationalError, ProgrammingError, connections, models
from django.db.models import CharField, Max, ProtectedError, TextField
from django.db.models import CharField, Max, ProtectedError, TextField, Count
from django.db.models.base import ModelBase
from django.db.models.signals import post_delete, post_save
from model_mommy import mommy
@ -34,7 +34,7 @@ from sapl.protocoloadm.models import (DocumentoAdministrativo,Protocolo,
StatusTramitacaoAdministrativo)
from sapl.sessao.models import ExpedienteMateria, OrdemDia, RegistroVotacao
from sapl.settings import PROJECT_DIR
from sapl.utils import delete_texto, normalize, save_texto
from sapl.utils import normalize
# BASE ######################################################################
# apps to be migrated, in app dependency order (very important)
@ -161,6 +161,8 @@ def get_fk_related(field, value, label=None):
ct = ContentType.objects.get(pk=13)
value = TipoProposicao.objects.create(
id=value, descricao='Erro', content_type=ct)
ultimo_valor = get_last_value(type(value))
alter_sequence(type(value), ultimo_valor+1)
else:
value = tipo[0]
else:
@ -244,6 +246,25 @@ def delete_constraints(model):
(table, r[0]))
def problema_duplicatas(model, lista_duplicatas, argumentos):
for obj in lista_duplicatas:
pks = []
string_pks = ""
problema = "%s de PK %s não é único." % (model.__name__, obj.pk)
args_dict = {k: obj.__dict__[k]
for k in set(argumentos) & set(obj.__dict__.keys())}
for dup in model.objects.filter(**args_dict):
pks.append(dup.pk)
string_pks = "(" + ", ".join(map(str, pks)) + ")"
descricao = "As entradas de PK %s são idênticas, mas " \
"apenas uma deve existir" % string_pks
with reversion.create_revision():
warn(problema + ' => ' + descricao)
save_relation(obj=obj, problema=problema,
descricao=descricao, eh_stub=False, critico=True)
reversion.set_comment('%s não é único.' % model.__name__)
def recria_constraints():
constraints = Constraint.objects.all()
for con in constraints:
@ -253,6 +274,8 @@ def recria_constraints():
args = [a.argumento for a in con.argumento_set.all()]
args_string = ''
args_string = "(" + "_".join(map(str, args[2:-1])) + ")"
model = ContentType.objects.filter(
model=con.nome_model.lower())[0].model_class()
try:
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(nome_tabela, nome_constraint, args_string))
@ -272,18 +295,30 @@ def recria_constraints():
args[i] = args[i] + '_id'
args_string = ''
args_string += "(" + ', '.join(map(str, args)) + ")"
try:
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(nome_tabela, nome_constraint, args_string))
except ProgrammingError:
info('A constraint %s já foi recriada!' % nome_constraint)
except Exception as err:
problema = re.findall('\(.*?\)', err.args[0])
erro('A constraint [%s] da tabela [%s] não pode ser recriada' %
(nome_constraint, nome_tabela))
erro('Os dados %s = %s estão duplicados. '
'Arrume antes de recriar as constraints!' %
(problema[0], problema[1]))
distintos = model.objects.distinct(*args)
todos = model.objects.all()
if hasattr(model, "content_type"):
distintos = distintos.exclude(content_type_id=None,
object_id=None)
todos = todos.exclude(content_type_id=None, object_id=None)
lista_duplicatas = list(set(todos).difference(set(distintos)))
if lista_duplicatas:
problema_duplicatas(model, lista_duplicatas, args)
else:
try:
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(nome_tabela, nome_constraint, args_string))
except ProgrammingError:
info('A constraint %s já foi recriada!' % nome_constraint)
except Exception as err:
problema = re.findall('\(.*?\)', err.args[0])
erro('A constraint [%s] da tabela [%s] não pode ser" \
recriada' % (nome_constraint, nome_tabela))
erro('Os dados %s = %s estão duplicados. '
'Arrume antes de recriar as constraints!' %
(problema[0], problema[1]))
def obj_desnecessario(obj):
@ -315,10 +350,10 @@ def save_with_id(new, id):
def save_relation(obj, nome_campo='', problema='', descricao='',
eh_stub=False):
eh_stub=False, critico=False):
link = ProblemaMigracao(
content_object=obj, nome_campo=nome_campo, problema=problema,
descricao=descricao, eh_stub=eh_stub,)
descricao=descricao, eh_stub=eh_stub, critico=critico)
link.save()
@ -373,6 +408,34 @@ def fill_vinculo_norma_juridica():
TipoVinculoNormaJuridica.objects.bulk_create(lista_objs)
# Uma anomalia no sapl 2.5 causa a duplicação de registros de votação.
# Essa duplicação deve ser eliminada para que não haja erro no sapl 3.1
def excluir_registrovotacao_duplicados():
duplicatas_ids = RegistroVotacao.objects.values(
'materia', 'ordem', 'expediente').annotate(
Count('id')).order_by().filter(id__count__gt=1)
duplicatas_queryset = RegistroVotacao.objects.filter(
materia__in=[item['materia'] for item in duplicatas_ids])
for dup in duplicatas_queryset:
lista_dups = duplicatas_queryset.filter(
materia=dup.materia, expediente=dup.expediente, ordem=dup.ordem)
primeiro_registro = lista_dups[0]
lista_dups = lista_dups.exclude(pk=primeiro_registro.pk)
for objeto in lista_dups:
if (objeto.pk > primeiro_registro.pk):
try:
objeto.delete()
except:
assert 0
else:
try:
primeiro_registro.delete()
primeiro_registro = objeto
except:
assert 0
class DataMigrator:
def __init__(self):
@ -449,8 +512,6 @@ class DataMigrator:
call([PROJECT_DIR.child('manage.py'), 'flush',
'--database=default', '--no-input'], stdout=PIPE)
desconecta_sinais_indexacao()
fill_vinculo_norma_juridica()
info('Começando migração: %s...' % obj)
self._do_migrate(obj)
@ -468,11 +529,15 @@ class DataMigrator:
save_relation(obj=obj, problema=msg,
descricao=descricao, eh_stub=False)
info('Excluindo possíveis duplicações em RegistroVotacao...')
excluir_registrovotacao_duplicados()
info('Deletando stubs desnecessários...')
while self.delete_stubs():
pass
conecta_sinais_indexacao()
info('Recriando constraints...')
recria_constraints()
def _do_migrate(self, obj):
if isinstance(obj, AppConfig):
@ -655,11 +720,25 @@ def adjust_participacao(new, old):
new.composicao = composicao
def adjust_proposicao(new, old):
def adjust_proposicao_antes_salvar(new, old):
if new.data_envio:
new.ano = new.data_envio.year
def adjust_proposicao_depois_salvar(new, old):
if not hasattr(old.dat_envio, 'year') or old.dat_envio.year == 1800:
msg = "O valor do campo data_envio (DateField) da model Proposicao"
"era inválido"
descricao = 'A data 1111-11-11 foi colocada no lugar'
problema = 'O valor da data era nulo ou inválido'
warn(msg + ' => ' + descricao)
new.data_envio = date(1111, 11, 11)
with reversion.create_revision():
save_relation(obj=new, problema=problema,
descricao=descricao, eh_stub=False)
reversion.set_comment('Ajuste de data pela migração')
def adjust_normarelacionada(new, old):
tipo = TipoVinculoNormaJuridica.objects.filter(sigla=old.tip_vinculo)
assert len(tipo) == 1
@ -817,7 +896,7 @@ AJUSTE_ANTES_SALVAR = {
OrdemDia: adjust_ordemdia_antes_salvar,
Parlamentar: adjust_parlamentar,
Participacao: adjust_participacao,
Proposicao: adjust_proposicao,
Proposicao: adjust_proposicao_antes_salvar,
Protocolo: adjust_protocolo,
RegistroVotacao: adjust_registrovotacao_antes_salvar,
TipoAfastamento: adjust_tipoafastamento,
@ -830,6 +909,7 @@ AJUSTE_ANTES_SALVAR = {
AJUSTE_DEPOIS_SALVAR = {
NormaJuridica: adjust_normajuridica_depois_salvar,
OrdemDia: adjust_ordemdia_depois_salvar,
Proposicao: adjust_proposicao_depois_salvar,
Protocolo: adjust_protocolo_depois_salvar,
RegistroVotacao: adjust_registrovotacao_depois_salvar,
}
@ -865,23 +945,3 @@ def make_with_log(model, _quantity=None, make_m2m=False, **attrs):
return stub
make_with_log.required = foreign_key_required
# DISCONNECT SIGNAL ########################################################
def desconecta_sinais_indexacao():
post_save.disconnect(save_texto, NormaJuridica)
post_save.disconnect(save_texto, DocumentoAcessorio)
post_save.disconnect(save_texto, MateriaLegislativa)
post_delete.disconnect(delete_texto, NormaJuridica)
post_delete.disconnect(delete_texto, DocumentoAcessorio)
post_delete.disconnect(delete_texto, MateriaLegislativa)
def conecta_sinais_indexacao():
post_save.connect(save_texto, NormaJuridica)
post_save.connect(save_texto, DocumentoAcessorio)
post_save.connect(save_texto, MateriaLegislativa)
post_delete.connect(delete_texto, NormaJuridica)
post_delete.connect(delete_texto, DocumentoAcessorio)
post_delete.connect(delete_texto, MateriaLegislativa)

4
sapl/legacy/scripts/fix_tables.sql

@ -5,6 +5,7 @@ DROP PROCEDURE IF EXISTS verifica_campos_proposicao;
DROP PROCEDURE IF EXISTS verifica_campos_tipo_materia_legislativa;
DROP PROCEDURE IF EXISTS verifica_campos_sessao_plenaria_presenca;
DROP PROCEDURE IF EXISTS cria_lexml_registro_provedor_e_publicador;
DROP PROCEDURE IF EXISTS muda_vinculo_norma_juridica_ind_excluido;
-- Procedure para criar campo num_proposicao em proposicao
CREATE PROCEDURE verifica_campos_proposicao() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='proposicao' AND column_name='num_proposicao') THEN ALTER TABLE proposicao ADD COLUMN num_proposicao INT(11) NULL after txt_justif_devolucao; END IF; END;
-- Procedure para criar campo iind_num_automatica em tipo_materia_legislativa
@ -13,8 +14,11 @@ CREATE PROCEDURE verifica_campos_tipo_materia_legislativa() BEGIN IF NOT EXISTS
CREATE PROCEDURE verifica_campos_sessao_plenaria_presenca() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='cod_presenca_sessao') THEN ALTER TABLE sessao_plenaria_presenca DROP PRIMARY KEY, ADD cod_presenca_sessao INT AUTO_INCREMENT PRIMARY KEY FIRST; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='dat_sessao') THEN ALTER TABLE sessao_plenaria_presenca ADD COLUMN dat_sessao DATE NULL after cod_parlamentar; END IF; END;
-- Procedure para criar tabela lexml_registro_provedor e lexml_registro_publicador
CREATE PROCEDURE cria_lexml_registro_provedor_e_publicador() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_publicador') THEN CREATE TABLE lexml_registro_publicador (cod_publicador INT AUTO_INCREMENT NOT NULL, id_publicador INT, nom_publicador VARCHAR(255), adm_email VARCHAR(50), sigla VARCHAR(255), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, PRIMARY KEY (cod_publicador)); END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_provedor') THEN CREATE TABLE lexml_registro_provedor (cod_provedor INT AUTO_INCREMENT NOT NULL, id_provedor INT, nom_provedor VARCHAR(255), sgl_provedor VARCHAR(15), adm_email VARCHAR(50), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, xml_provedor LONGTEXT, PRIMARY KEY (cod_provedor)); END IF; END;
-- Procedure para mudar valor do campo ind_excluido da tabela vinculo_norma_juridica de 0 para string vazia ''
CREATE PROCEDURE muda_vinculo_norma_juridica_ind_excluido() BEGIN UPDATE vinculo_norma_juridica SET ind_excluido = '' WHERE trim(ind_excluido) = '0'; END;
-- Executa as procedures criadas acima
CALL verifica_campos_proposicao;
CALL verifica_campos_tipo_materia_legislativa;
CALL verifica_campos_sessao_plenaria_presenca;
CALL cria_lexml_registro_provedor_e_publicador;
CALL muda_vinculo_norma_juridica_ind_excluido;

68
sapl/materia/forms.py

@ -16,10 +16,14 @@ from django.db.models import Max
from django.forms import ModelForm, ModelChoiceField, widgets
from django.forms.forms import Form
from django.forms.widgets import Select
from django.utils import six
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 _
from django_filters.filterset import STRICTNESS
import django_filters
from sapl.base.models import Autor, TipoAutor
@ -586,6 +590,45 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
form_actions(save_label='Pesquisar'))
)
@property
def qs(self):
if not hasattr(self, '_qs'):
valid = self.is_bound and self.form.is_valid()
if self.is_bound and not valid:
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
# start with all the results and filter from there
qs = self.queryset.all()
for name, filter_ in six.iteritems(self.filters):
value = None
if valid:
value = self.form.cleaned_data[name]
else:
raw_value = self.form[name].value()
try:
value = self.form.fields[name].clean(raw_value)
except forms.ValidationError:
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
if value is not None: # valid & clean data
qs = qs._next_is_sticky()
qs = filter_.filter(qs, value)
self._qs = qs
return self._qs
def pega_ultima_tramitacao():
ultimas_tramitacoes = Tramitacao.objects.values(
@ -654,6 +697,18 @@ class AutoriaForm(ModelForm):
TipoAutor.objects.all().order_by('descricao'),
empty_label='Selecione',)
def __init__(self, *args, **kwargs):
super(AutoriaForm, self).__init__(*args, **kwargs)
row1 = to_row([('tipo_autor', 4),
('autor', 4),
('primeiro_autor', 4)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(_('Autoria'),
row1, form_actions(save_label='Salvar')))
class Meta:
model = Autoria
fields = ['tipo_autor', 'autor', 'primeiro_autor']
@ -664,12 +719,13 @@ class AutoriaForm(ModelForm):
if self.errors:
return self.errors
if Autoria.objects.filter(
materia=self.instance.materia,
autor=self.cleaned_data['autor'],
).exists():
msg = _('Esse Autor já foi cadastrado.')
raise ValidationError(msg)
if not self.instance.pk:
if Autoria.objects.filter(
materia=self.instance.materia,
autor=self.cleaned_data['autor'],
).exists():
msg = _('Esse Autor já foi cadastrado.')
raise ValidationError(msg)
return self.cleaned_data

19
sapl/materia/views.py

@ -959,6 +959,12 @@ class TramitacaoCrud(MasterDetailCrud):
def form_valid(self, form):
self.object = form.save()
if form.instance.status.indicador == 'F':
form.instance.materia.em_tramitacao = False
else:
form.instance.materia.em_tramitacao = True
form.instance.materia.save()
try:
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
@ -982,6 +988,12 @@ class TramitacaoCrud(MasterDetailCrud):
def form_valid(self, form):
self.object = form.save()
if form.instance.status.indicador == 'F':
form.instance.materia.em_tramitacao = False
else:
form.instance.materia.em_tramitacao = True
form.instance.materia.save()
try:
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
@ -1256,6 +1268,13 @@ class AutoriaCrud(MasterDetailCrud):
context['form'].fields['autor'].choices = autores
return context
class ListView(MasterDetailCrud.ListView):
def get_queryset(self):
qs = super().get_queryset()
return qs.order_by('-primeiro_autor', 'autor__nome')
class DespachoInicialCrud(MasterDetailCrud):
model = DespachoInicial

6
sapl/norma/forms.py

@ -144,7 +144,9 @@ class NormaJuridicaForm(ModelForm):
texto_integral = self.cleaned_data.get('texto_integral', False)
if texto_integral:
if texto_integral.size > MAX_DOC_UPLOAD_SIZE:
raise ValidationError("Arquivo muito grande. ( > 5mb )")
max_size = str(MAX_DOC_UPLOAD_SIZE / (1024 * 1024))
raise ValidationError(
"Arquivo muito grande. ( > {0}MB )".format(max_size))
return texto_integral
def save(self, commit=False):
@ -178,7 +180,7 @@ class NormaRelacionadaForm(ModelForm):
def clean(self):
super(NormaRelacionadaForm, self).clean()
if self.errors:
return self.errors
cleaned_data = self.cleaned_data

12
sapl/painel/views.py

@ -439,7 +439,7 @@ def get_votos(response, materia):
def get_votos_nominal(response, materia):
votos = {}
votos = []
if materia.tipo_votacao == 1:
tipo_votacao = 'Simbólica'
@ -468,7 +468,7 @@ def get_votos_nominal(response, materia):
else:
votos_parlamentares = VotoParlamentar.objects.filter(
votacao_id=registro.id)
votacao_id=registro.id).order_by('parlamentar__nome_parlamentar')
filiacao = Filiacao.objects.filter(
data_desfiliacao__isnull=True, parlamentar__ativo=True)
@ -481,18 +481,18 @@ def get_votos_nominal(response, materia):
try:
parlamentar_partido[v.parlamentar.nome_parlamentar]
except KeyError:
votos.update({v.parlamentar.id: {
votos.append({
'parlamentar': v.parlamentar.nome_parlamentar,
'voto': str(v.voto),
'partido': str(_('Sem Registro'))
}})
})
else:
votos.update({v.parlamentar.id: {
votos.append({
'parlamentar': v.parlamentar.nome_parlamentar,
'voto': str(v.voto),
'partido': parlamentar_partido[
v.parlamentar.nome_parlamentar]
}})
})
total = (registro.numero_votos_sim +
registro.numero_votos_nao +

34
sapl/protocoloadm/forms.py

@ -333,7 +333,10 @@ class ProtocoloDocumentForm(ModelForm):
class ProtocoloMateriaForm(ModelForm):
autor = forms.IntegerField(widget=forms.HiddenInput(), required=False)
autor = forms.ModelChoiceField(required=True,
empty_label='------',
queryset=Autor.objects.all()
)
tipo_materia = forms.ModelChoiceField(
label=_('Tipo de Matéria'),
@ -350,15 +353,6 @@ class ProtocoloMateriaForm(ModelForm):
assunto_ementa = forms.CharField(required=True,
widget=forms.Textarea, label='Ementa')
def clean_autor(self):
autor_field = self.cleaned_data['autor']
try:
autor = Autor.objects.get(id=autor_field)
except ObjectDoesNotExist:
autor_field = None
else:
autor_field = autor
return autor_field
class Meta:
model = Protocolo
@ -368,19 +362,23 @@ class ProtocoloMateriaForm(ModelForm):
'assunto_ementa',
'observacao']
def clean_autor(self):
autor_field = self.cleaned_data['autor']
try:
autor = Autor.objects.get(id=autor_field.id)
except ObjectDoesNotExist:
autor_field = None
else:
autor_field = autor
return autor_field
def __init__(self, *args, **kwargs):
row1 = to_row(
[('tipo_materia', 4),
('numero_paginas', 4)])
row2 = to_row(
[('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)])
[('autor', 4)])
row3 = to_row(
[('assunto_ementa', 12)])
row4 = to_row(
@ -389,7 +387,7 @@ class ProtocoloMateriaForm(ModelForm):
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(_('Identificação da Matéria'),
row1, HTML(autor_label), HTML(autor_modal), row2, row3,
row1, row2, row3,
row4, form_actions(save_label='Protocolar Matéria')))
super(ProtocoloMateriaForm, self).__init__(

41
sapl/protocoloadm/views.py

@ -1,8 +1,10 @@
from datetime import date, datetime
from braces.views import FormValidMessageMixin
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db.models import Max
@ -15,6 +17,7 @@ from django.views.generic.base import TemplateView
from django_filters.views import FilterView
import sapl
from sapl.base.models import Autor
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.utils import create_barcode, get_client_ip
@ -27,6 +30,10 @@ from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm,
from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
Protocolo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo)
from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import Protocolo
from sapl.comissoes.models import Comissao
from django.contrib.contenttypes.models import ContentType
TipoDocumentoAdministrativoCrud = CrudAux.build(
TipoDocumentoAdministrativo, '')
@ -419,12 +426,10 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo.numero = (
numero['numero__max'] + 1) if numero['numero__max'] else 1
protocolo.ano = datetime.now().year
protocolo.data = datetime.strptime(datetime.now().strftime("%Y-%m-%d"),
'%Y-%m-%d')
protocolo.hora = datetime.strptime(datetime.now().strftime("%H:%M"),
'%H:%M')
protocolo.timestamp = datetime.strptime(
datetime.now().strftime("%Y-%m-%d %H:%M"), "%Y-%m-%d %H:%M")
protocolo.data = datetime.now().date()
protocolo.hora = datetime.now().time()
protocolo.timestamp = datetime.now()
protocolo.tipo_protocolo = 0
protocolo.tipo_processo = '1' # TODO validar o significado
protocolo.anulado = False
@ -440,6 +445,30 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo.save()
return redirect(self.get_success_url(protocolo))
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
autores_ativos = self.autores_ativos()
autores = []
autores.append(['0', '------'])
for a in autores_ativos:
autores.append([a.id, a.__str__()])
context['form'].fields['autor'].choices = autores
return context
def autores_ativos(self):
lista_parlamentares = Parlamentar.objects.filter(ativo=True).values_list('id', flat=True)
model_parlamentar = ContentType.objects.get_for_model(Parlamentar)
autor_parlamentar = Autor.objects.filter(content_type=model_parlamentar, object_id__in=lista_parlamentares)
lista_comissoes = Comissao.objects.filter(Q(data_extincao__isnull=True)|Q(data_extincao__gt=date.today())).values_list('id', flat=True)
model_comissao = ContentType.objects.get_for_model(Comissao)
autor_comissoes = Autor.objects.filter(content_type=model_comissao, object_id__in=lista_comissoes)
autores_outros = Autor.objects.exclude(content_type__in=[model_parlamentar, model_comissao])
q = autor_parlamentar | autor_comissoes | autores_outros
return q
class ProtocoloMateriaTemplateView(PermissionRequiredMixin, TemplateView):

27
sapl/sessao/views.py

@ -1400,9 +1400,8 @@ class VotacaoEditView(SessaoPermissionMixin):
ordem_id = kwargs['oid']
if(int(request.POST['anular_votacao']) == 1):
RegistroVotacao.objects.filter(
materia_id=materia_id,
ordem_id=ordem_id).last().delete()
for r in RegistroVotacao.objects.filter(ordem_id=ordem_id):
r.delete()
ordem = OrdemDia.objects.get(
sessao_plenaria_id=self.object.id,
@ -2165,14 +2164,8 @@ class VotacaoExpedienteEditView(SessaoPermissionMixin):
expediente_id = kwargs['oid']
if(int(request.POST['anular_votacao']) == 1):
try:
RegistroVotacao.objects.get(
materia_id=materia_id,
expediente_id=expediente_id).delete()
except MultipleObjectsReturned:
RegistroVotacao.objects.filter(
materia_id=materia_id,
expediente_id=expediente_id).last().delete()
for r in RegistroVotacao.objects.filter(expediente_id=expediente_id):
r.delete()
expediente = ExpedienteMateria.objects.get(
sessao_plenaria_id=self.object.id,
@ -2296,11 +2289,13 @@ class PautaSessaoDetailView(DetailView):
ementa = o.observacao
titulo = o.materia
numero = o.numero_ordem
situacao = o.materia.tramitacao_set.last().status
if situacao is None:
situacao = _("Não informada")
# Verificar resultado
resultado = o.registrovotacao_set.all()
if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
rv = o.registrovotacao_set.all()
if rv:
resultado = rv[0].tipo_resultado_votacao.nome
else:
resultado = _('Matéria não votada')
@ -2313,6 +2308,8 @@ class PautaSessaoDetailView(DetailView):
'titulo': titulo,
'numero': numero,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'situacao': situacao,
'autor': autor
}
materias_ordem.append(mat)

4
sapl/settings.py

@ -193,7 +193,7 @@ EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='')
DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='')
SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='')
MAX_DOC_UPLOAD_SIZE = 10 * 1024 * 1024 # 10MB
MAX_DOC_UPLOAD_SIZE = 20 * 1024 * 1024 # 20MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
# Internationalization
@ -205,7 +205,7 @@ LANGUAGES = (
TIME_ZONE = 'America/Sao_Paulo'
USE_I18N = True
USE_L10N = False
USE_L10N = True
USE_TZ = False
# DATE_FORMAT = 'N j, Y'
DATE_FORMAT = 'd/m/Y'

2
sapl/templates/crud/detail.html

@ -114,4 +114,6 @@
</div>
{% include "paginacao.html" %}
{% endblock table_content %}
{% block extra_js %}{% endblock %}
{% endblock base_content %}

10
sapl/templates/materia/materialegislativa_filter.html

@ -60,10 +60,12 @@
{% endif %}
{% if m.autoria_set.all %}
<strong>Autor:</strong>
{% for a in m.autoria_set.all %}
{% if a.primeiro_autor %}
&nbsp;{{a.autor.nome}}
<strong>Autor:</strong>
{% for a in m.autoria_set.all %}
{% if not forloop.first %}
</br> {{a.autor}}
{% else %}
&nbsp;{{a.autor}}
{% endif %}
{% endfor %}
</br>

2
sapl/templates/navbar.yaml

@ -36,6 +36,8 @@
- title: {% trans 'Proposições' %}
url: sapl.materia:proposicao_list
check_permission: materia.add_proposicao
- title: {% trans 'Relatórios' %}
url: sapl.base:relatorios_list
- title: {% trans 'Sessões Plenárias' %}
url: sapl.sessao:pesquisar_sessao
- title: {% trans 'Tramitação em Lote' %}

45
sapl/templates/painel/index.html

@ -181,25 +181,38 @@
else if (data["presentes_expediente"] != null){
presentes_ordem_dia = data["presentes_expediente"]
}
if( (data["tipo_resultado"] == "Aprovado por unanimidade") || (data["tipo_resultado"] == "Aprovado por maioria") || (data["tipo_resultado"] == "Rejeitado")){
if(data["tipo_votacao"] == "Nominal") {
jQuery.each(data["votos"], function(index, parlamentar) {
$('<li />', {text: parlamentar.parlamentar + ' - ' + parlamentar.partido + ' - Voto: ' + parlamentar.voto}).appendTo(presentes);
presentes.append('<table id="parlamentares_list">');
if( (data["tipo_resultado"] == "Aprovado por Unanimidade") || (data["tipo_resultado"] == "Aprovado por maioria") || (data["tipo_resultado"] == "Rejeitado")) {
if (data["tipo_votacao"] == "Nominal") {
jQuery.each(data["votos"], function (index, parlamentar) {
$('#parlamentares_list').append('<tr> <td style="padding-right:20px">' +
parlamentar.parlamentar +
'</td> <td style="padding-right:20px">' +
parlamentar.partido + '</td> <td style="padding-right:20px">'
+ show_voto(parlamentar.voto) + '</td> </tr>')
});
}
else{
jQuery.each(presentes_ordem_dia, function(index, parlamentar) {
$('<li />', {text: parlamentar.nome + ' - ' + parlamentar.partido}).appendTo(presentes);
});
else {
jQuery.each(data["votos"], function (index, parlamentar) {
$('#parlamentares_list').append('<tr> <td style="padding-right:20px">' +
parlamentar.parlamentar +
'</td> <td style="padding-right:20px">' +
parlamentar.partido + '</td> </tr>')
});
}
}
else{
jQuery.each(presentes_ordem_dia, function(index, parlamentar) {
$('<li />', {text: parlamentar.nome + ' - ' + parlamentar.partido}).appendTo(presentes);
});
jQuery.each(presentes_ordem_dia, function (index, parlamentar) {
$('#parlamentares_list').append('<tr> <td style="padding-right:20px">' +
parlamentar.nome +
'</td> <td style="padding-right:20px">' +
parlamentar.partido + '</td> </tr>')
});
}
presentes.append('</table>');
//console.debug(presentes_ordem_dia)
var votacao = $("#votacao")
if (data["num_presentes_ordem_dia"] != null) {
@ -280,5 +293,15 @@
})
})();
});
function show_voto(voto) {
if (voto == "Sim"){
return '<font color="green"> Sim </font>'
}
else if (voto == "Não"){
return '<font color="red"> Não </font>'
}
return voto
}
</script>
</html>

2
sapl/templates/protocoloadm/MateriaTemplate.html

@ -3,7 +3,7 @@
{% block base_content %}
<div class="alert alert-success alert-dismissible fade in" role="alert">
<p align="center"><b><font color="green">Matéria procololada com sucesso!</font></b></p>
<p align="center"><b><font color="green">Matéria protocolada com sucesso!</font></b></p>
</div>
<div align="center">

2
sapl/templates/protocoloadm/protocolo_list.html

@ -20,7 +20,7 @@
<img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual">
</a></br>
<strong>Assunto:</strong> {{ p.assunto_ementa }}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y" }} - Horário: {{ p.timestamp|date:"H:m:s" }}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y" }} - Horário: {{ p.hora|date:"H:m:s" }}</br>
<strong>Natureza do Processo:</strong>
{% if p.tipo_processo == 0 %}
Administrativo </br>

8
sapl/templates/search/search.html

@ -93,9 +93,13 @@
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; Previous{% if page.has_previous %}</a>{% endif %}
{% if page.has_previous %}
<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}{{ models }}">
{% endif %}&laquo; Anterior{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}Next &raquo;{% if page.has_next %}</a>{% endif %}
{% if page.has_next %}
<a href="?q={{ query }}&amp;page={{ page.next_page_number }}{{ models }}">
{% endif %}Próxima &raquo;{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% else %}

8
sapl/templates/sessao/mesa.html

@ -20,7 +20,9 @@
<!-- Success and errors messages div end -->
<fieldset class="form-group">
<legend>Escolha da Composição da Mesa Diretora da Sessão Plenária</legend>
{% if perms.sessao.add_integrantemesa %}
<legend>Escolha da Composição da Mesa Diretora da Sessão Plenária</legend>
{% endif %}
<div class="row">
<div class="col-md-4">
<label>Composição da Mesa Diretora</label>
@ -35,12 +37,12 @@
<div class="col-md-4" align="center">
<br /><br />
{% if perms.parlamentares.add_cargomesa %}
{% if perms.sessao.add_integrantemesa %}
<input type="submit" style="display: none" name="Incluir" id="id_incluir" Value="Incluir" class="btn btn-primary" />
{% endif %}
<br />
<br />
{% if perms.parlamentares.add_composicaomesa %}
{% if perms.sessao.add_integrantemesa %}
<input type="submit" style="display: none" name="Excluir" id="id_excluir" Value="Excluir" class="btn btn-danger" />
{% endif %}
</div>

20
sapl/templates/sessao/pauta_sessao_detail.html

@ -3,7 +3,7 @@
{% load crispy_forms_tags %}
{% block base_content %}
<div align=right><a href="{% url 'sapl.relatorios:relatorio_sessao_plenaria' object.id %}">> PDF</a></li></div>
<div align=right><a href="{% url 'sapl.relatorios:relatorio_sessao_plenaria' object.id %}"> Impressão PDF</a></li></div>
<fieldset>
<legend>Identificação Básica</legend>
<table class="table">
@ -25,7 +25,7 @@
<tr>
<td>
<b>{{e.tipo}}: </b> <br />
<p style="text-indent: 50px;">{{e.conteudo}}</p>
<p style="text-indent: 50px;">{{e.conteudo|safe}}</p>
</td>
</tr>
{% endfor %}
@ -36,7 +36,7 @@
<fieldset>
<legend>Matérias do Expediente</legend>
<table class="table table-striped">
<thead class="thead-default">
<thead>
<tr>
<th>Matéria</th>
<th>Ementa</th>
@ -45,13 +45,13 @@
</thead>
{% for m in materia_expediente %}
<tr>
<td>
<td style="width:20%;">
{{m.numero}} - <a href="{% url 'sapl.sessao:pauta_expediente_detail' m.id %}">{{m.titulo}}</a>
<br />
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td>
<td>{{m.ementa|safe}}</td>
<td>{{m.situacao}}</td>
<td style="width:70%;">{{m.ementa|safe}}</td>
<td style="width:10%;">{{m.situacao}}</td>
</tr>
{% endfor %}
</table>
@ -78,7 +78,7 @@
<fieldset>
<legend>Matérias da Ordem do Dia</legend>
<table class="table table-striped">
<thead class="thead-default">
<thead>
<tr>
<th>Matéria</th>
<th>Ementa</th>
@ -87,13 +87,13 @@
</thead>
{% for m in materias_ordem %}
<tr>
<td>
<td style="width:20%;">
{{m.numero}} - <a href="{% url 'sapl.sessao:pauta_ordem_detail' m.id %}">{{m.titulo}}</a>
<br />
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td>
<td>{{m.ementa|safe}}</td>
<td>{{m.situacao}}</td>
<td style="width:70%;">{{m.ementa|safe}}</td>
<td style="width:10%;">{{m.situacao}}</td>
</tr>
{% endfor %}
</table>

35
scrap-js.js

@ -1,35 +0,0 @@
{# <script language="javascript">
function setUpHumanTest() {
var myform = document.getElementsByTagName("myform");
console.debug('hello');
// var myforms = document.getElementsByTagName("form") ;
// for (var i=0; i&lt;myforms.length; i++) {
// addEvent(myforms[i], "focus", markAsHuman, false);
// addEvent(myforms[i], "click", markAsHuman, false);
// }
}
// Generic cross-browser code for attaching events to elements
// You should really have this in a separate common JS file
var addEvent;
if (document.addEventListener) {
addEvent = function(element, type, handler) {
element.addEventListener(type, handler, null);
if (element.href) element.href="javascript:void('');" ;
}
}
else if (document.attachEvent) {
addEvent = function(element, type, handler) {
element.attachEvent("on" + type, handler);
if (element.href) element.href="javascript:void('');" ;
}
}
else {
addEvent = new Function; // not supported
}
addEvent(window, "load", setUpHumanTest, false);
</script> #}scr
Loading…
Cancel
Save