Browse Source

Merge branch 'master' into docker-sapl-2

pull/1023/head
Edward 9 years ago
committed by GitHub
parent
commit
7df8234642
  1. 0
      bug.txt
  2. 11
      gunicorn_start.sh
  3. 2
      requirements/requirements.txt
  4. 51
      sapl/base/migrations/0002_auto_20170331_1900.py
  5. 33
      sapl/base/models.py
  6. 3
      sapl/base/search_indexes.py
  7. 3
      sapl/compilacao/templatetags/compilacao_filters.py
  8. 2
      sapl/crispy_layout_mixin.py
  9. 12
      sapl/legacy/management/commands/recria_constraints.py
  10. 28
      sapl/legacy/migracao_documentos.py
  11. 117
      sapl/legacy/migration.py
  12. 6
      sapl/legacy/scripts/migra_um_db.sh
  13. 3
      sapl/materia/models.py
  14. 23
      sapl/materia/signals.py
  15. 7
      sapl/materia/urls.py
  16. 24
      sapl/materia/views.py
  17. 4
      sapl/norma/models.py
  18. 21
      sapl/norma/signals.py
  19. 1
      sapl/norma/views.py
  20. 1
      sapl/parlamentares/views.py
  21. 4
      sapl/protocoloadm/forms.py
  22. 39
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  23. 50
      sapl/relatorios/views.py
  24. 2
      sapl/rules/map_rules.py
  25. 13
      sapl/rules/tests/test_rules.py
  26. 50
      sapl/sessao/views.py
  27. 1
      sapl/settings.py
  28. 2
      sapl/templates/base.html
  29. 45
      sapl/templates/sessao/sessaoplenaria_filter.html
  30. 1
      sapl/templates/sessao/sessaoplenaria_form.html
  31. 3
      sapl/test_urls.py
  32. 20
      sapl/utils.py

0
bug.txt

11
gunicorn_start.sh

@ -2,6 +2,15 @@
# As seen in http://tutos.readthedocs.org/en/latest/source/ndg.html # As seen in http://tutos.readthedocs.org/en/latest/source/ndg.html
SAPL_DIR="/var/interlegis/sapl"
# Seta um novo diretório foi passado como raiz para o SAPL
# caso esse tenha sido passado como parâmetro
if [ "$1" ]
then
SAPL_DIR="$1"
fi
NAME="SAPL" # Name of the application (*) NAME="SAPL" # Name of the application (*)
DJANGODIR=/var/interlegis/sapl/ # Django project directory (*) DJANGODIR=/var/interlegis/sapl/ # Django project directory (*)
SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*) SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock # we will communicate using this unix socket (*)
@ -12,7 +21,7 @@ NUM_WORKERS=3 # how many worker processes shou
DJANGO_SETTINGS_MODULE=sapl.settings # which settings file should Django use (*) DJANGO_SETTINGS_MODULE=sapl.settings # which settings file should Django use (*)
DJANGO_WSGI_MODULE=sapl.wsgi # WSGI module name (*) DJANGO_WSGI_MODULE=sapl.wsgi # WSGI module name (*)
echo "Starting $NAME as `whoami`" echo "Starting $NAME as `whoami` on base dir $SAPL_DIR"
# Create the run directory if it doesn't exist # Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE) RUNDIR=$(dirname $SOCKFILE)

2
requirements/requirements.txt

@ -19,7 +19,7 @@ django-sass-processor==0.4.6
djangorestframework djangorestframework
drfdocs drfdocs
easy-thumbnails==2.3 easy-thumbnails==2.3
trml2pdf==0.4.2 git+git://github.com/interlegis/trml2pdf.git
libsass==0.11.1 libsass==0.11.1
psycopg2==2.6.2 psycopg2==2.6.2
python-decouple==3.0 python-decouple==3.0

51
sapl/base/migrations/0002_auto_20170331_1900.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-03-31 19:00
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('base', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Argumento',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('argumento', models.CharField(max_length=50, verbose_name='Argumento')),
],
options={
'verbose_name': 'Argumento da constraint',
'verbose_name_plural': 'Argumentos da constraint',
},
),
migrations.CreateModel(
name='Constraint',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nome_tabela', models.CharField(max_length=50, verbose_name='Nome da tabela')),
('nome_constraint', models.CharField(max_length=100, verbose_name='Nome da constraint')),
('nome_model', models.CharField(max_length=50, verbose_name='Nome da model')),
('tipo_constraint', models.CharField(max_length=50, verbose_name='Tipo da constraint')),
],
options={
'verbose_name': 'Constraint removida',
'verbose_name_plural': 'Constraints removidas',
},
),
migrations.AddField(
model_name='problemamigracao',
name='eh_importante',
field=models.BooleanField(default=False, verbose_name='É importante?'),
),
migrations.AddField(
model_name='argumento',
name='constraint',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='base.Constraint'),
),
]

33
sapl/base/models.py

@ -61,16 +61,45 @@ class ProblemaMigracao(models.Model):
content_object = GenericForeignKey('content_type', 'object_id') content_object = GenericForeignKey('content_type', 'object_id')
nome_campo = models.CharField(max_length=100, nome_campo = models.CharField(max_length=100,
blank=True, blank=True,
verbose_name='Nome do(s) Campo(s)') verbose_name=_('Nome do(s) Campo(s)'))
problema = models.CharField(max_length=300, verbose_name=_('Problema')) problema = models.CharField(max_length=300, verbose_name=_('Problema'))
descricao = models.CharField(max_length=300, verbose_name=_('Descrição')) descricao = models.CharField(max_length=300, verbose_name=_('Descrição'))
eh_stub = models.BooleanField(verbose_name='É stub?') eh_stub = models.BooleanField(verbose_name=_('É stub?'))
eh_importante = models.BooleanField(
default=False, verbose_name=_('É importante?'))
class Meta: class Meta:
verbose_name = _('Problema na Migração') verbose_name = _('Problema na Migração')
verbose_name_plural = _('Problemas na Migração') verbose_name_plural = _('Problemas na Migração')
@reversion.register()
class Constraint(models.Model):
nome_tabela = models.CharField(
max_length=50, verbose_name=_('Nome da tabela'))
nome_constraint = models.CharField(
max_length=100, verbose_name=_('Nome da constraint'))
nome_model = models.CharField(
max_length=50, verbose_name=_('Nome da model'))
tipo_constraint = models.CharField(
max_length=50, verbose_name=_('Tipo da constraint'))
class Meta:
verbose_name = _('Constraint removida')
verbose_name_plural = _('Constraints removidas')
@reversion.register()
class Argumento(models.Model):
constraint = models.ForeignKey(Constraint)
argumento = models.CharField(
max_length=50, verbose_name=_('Argumento'))
class Meta:
verbose_name = _('Argumento da constraint')
verbose_name_plural = _('Argumentos da constraint')
@reversion.register() @reversion.register()
class AppConfig(models.Model): class AppConfig(models.Model):

3
sapl/base/search_indexes.py

@ -1,8 +1,9 @@
import os.path import os.path
import textract
import textract
from django.template import Context, loader from django.template import Context, loader
from haystack import indexes from haystack import indexes
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa
from sapl.norma.models import NormaJuridica from sapl.norma.models import NormaJuridica

3
sapl/compilacao/templatetags/compilacao_filters.py

@ -211,7 +211,7 @@ def heranca(request, d, ignore_ultimo=0, ignore_primeiro=0):
ta_id = str(d.ta_id) ta_id = str(d.ta_id)
d_pk = str(d.pk) d_pk = str(d.pk)
if ta_id not in ta_dpts_parents or d_pk not in ta_dpts_parents[ta_id]: if ta_id not in ta_dpts_parents or d_pk not in ta_dpts_parents[ta_id]:
#print('recarregando estrutura temporaria de heranças') # print('recarregando estrutura temporaria de heranças')
dpts_parents = {} dpts_parents = {}
ta_dpts_parents[ta_id] = dpts_parents ta_dpts_parents[ta_id] = dpts_parents
update_dispositivos_parents(dpts_parents, ta_id) update_dispositivos_parents(dpts_parents, ta_id)
@ -296,6 +296,7 @@ def urldetail_content_type(obj):
def list(obj): def list(obj):
return [obj, ] return [obj, ]
@register.filter @register.filter
def can_use_dynamic_editing(texto_articulado, user): def can_use_dynamic_editing(texto_articulado, user):
return texto_articulado.can_use_dynamic_editing(user) return texto_articulado.can_use_dynamic_editing(user)

2
sapl/crispy_layout_mixin.py

@ -1,12 +1,12 @@
from math import ceil from math import ceil
import rtyaml
from crispy_forms.bootstrap import FormActions from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit
from django import template from django import template
from django.utils import formats from django.utils import formats
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import rtyaml
def heads_and_tails(list_of_lists): def heads_and_tails(list_of_lists):

12
sapl/legacy/management/commands/recria_constraints.py

@ -0,0 +1,12 @@
from django.core.management.base import BaseCommand
from sapl.legacy.migration import recria_constraints
class Command(BaseCommand):
help = (u'Recria constraints do PostgreSQL excluidas durante '
'migração de dados')
def handle(self, *args, **options):
recria_constraints()

28
sapl/legacy/migracao_documentos.py

@ -4,6 +4,7 @@ import re
import magic import magic
from django.db.models.signals import post_delete, post_save
from sapl.base.models import CasaLegislativa from sapl.base.models import CasaLegislativa
from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa,
Proposicao) Proposicao)
@ -12,6 +13,8 @@ from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import DocumentoAdministrativo from sapl.protocoloadm.models import DocumentoAdministrativo
from sapl.sessao.models import SessaoPlenaria from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MEDIA_ROOT from sapl.settings import MEDIA_ROOT
from sapl.utils import delete_texto, save_texto
# MIGRAÇÃO DE DOCUMENTOS ################################################### # MIGRAÇÃO DE DOCUMENTOS ###################################################
EXTENSOES = { EXTENSOES = {
@ -160,7 +163,29 @@ def migrar_docs_por_ids(tipo):
tipo.__name__, id, destino)) 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(): 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 # aqui supomos que uma pasta chamada sapl_documentos está em MEDIA_ROOT
# com o conteúdo da pasta de mesmo nome do zope # 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á # Os arquivos da pasta serão movidos para a nova estrutura e a pasta será
@ -186,3 +211,6 @@ def migrar_documentos():
len(sobrando))) len(sobrando)))
for doc in sobrando: for doc in sobrando:
print(' {}'. format(doc)) print(' {}'. format(doc))
#
# reconexão dos sinais desligados no inicio da migração de documentos
conecta_sinais_indexacao()

117
sapl/legacy/migration.py

@ -13,13 +13,15 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db import OperationalError, ProgrammingError, connections, models 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
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.db.models.signals import post_delete, post_save
from model_mommy import mommy from model_mommy import mommy
from model_mommy.mommy import foreign_key_required, make from model_mommy.mommy import foreign_key_required, make
from sapl.base.models import Autor, ProblemaMigracao from sapl.base.models import Argumento, Autor, Constraint, ProblemaMigracao
from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.legacy.models import Protocolo as ProtocoloLegado from sapl.legacy.models import Protocolo as ProtocoloLegado
from sapl.materia.models import (Proposicao, StatusTramitacao, TipoDocumento, from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa,
StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao, TipoMateriaLegislativa, TipoProposicao,
Tramitacao) Tramitacao)
from sapl.norma.models import (AssuntoNorma, NormaJuridica, from sapl.norma.models import (AssuntoNorma, NormaJuridica,
@ -28,7 +30,7 @@ from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import Protocolo, StatusTramitacaoAdministrativo from sapl.protocoloadm.models import Protocolo, StatusTramitacaoAdministrativo
from sapl.sessao.models import ExpedienteMateria, OrdemDia from sapl.sessao.models import ExpedienteMateria, OrdemDia
from sapl.settings import PROJECT_DIR from sapl.settings import PROJECT_DIR
from sapl.utils import normalize from sapl.utils import delete_texto, normalize, save_texto
# BASE ###################################################################### # BASE ######################################################################
# apps to be migrated, in app dependency order (very important) # apps to be migrated, in app dependency order (very important)
@ -109,6 +111,10 @@ def warn(msg):
print('CUIDADO! ' + msg) print('CUIDADO! ' + msg)
def erro(msg):
print('ERRO: ' + msg)
def get_fk_related(field, value, label=None): def get_fk_related(field, value, label=None):
if value is None and field.null is False: if value is None and field.null is False:
value = 0 value = 0
@ -197,6 +203,12 @@ def iter_sql_records(sql, db):
record.__dict__.update(zip(fieldnames, row)) record.__dict__.update(zip(fieldnames, row))
yield record yield record
# Todos os models têm no máximo uma constraint unique together
# Isso é necessário para que o método delete_constraints funcione corretamente
assert all(len(model._meta.unique_together) <= 1
for app in appconfs
for model in app.models.values())
def delete_constraints(model): def delete_constraints(model):
# pega nome da unique constraint dado o nome da tabela # pega nome da unique constraint dado o nome da tabela
@ -210,40 +222,66 @@ def delete_constraints(model):
for r in result: for r in result:
if r[0].endswith('key'): if r[0].endswith('key'):
words_list = r[0].split('_') words_list = r[0].split('_')
one_to_one_constraints.append([table, r[0], words_list, model]) constraint = Constraint.objects.create(
nome_tabela=table, nome_constraint=r[0],
nome_model=model.__name__, tipo_constraint='one_to_one')
for w in words_list:
Argumento.objects.create(constraint=constraint, argumento=w)
else: else:
args = None
args_list = []
if model._meta.unique_together: if model._meta.unique_together:
args = model._meta.unique_together[0] args_list = model._meta.unique_together[0]
args_list = list(args) constraint = Constraint.objects.create(
unique_constraints.append([table, r[0], args_list, model]) nome_tabela=table, nome_constraint=r[0],
nome_model=model.__name__,
tipo_constraint='unique_together')
for a in args_list:
Argumento.objects.create(constraint=constraint,
argumento=a)
warn('Excluindo unique constraint de nome %s' % r[0]) warn('Excluindo unique constraint de nome %s' % r[0])
exec_sql("ALTER TABLE %s DROP CONSTRAINT %s;" % exec_sql("ALTER TABLE %s DROP CONSTRAINT %s;" %
(table, r[0])) (table, r[0]))
def recreate_constraints(): def recria_constraints():
if one_to_one_constraints: constraints = Constraint.objects.all()
for constraint in one_to_one_constraints: for con in constraints:
table, name, args, model = constraint if con.tipo_constraint == 'one_to_one':
nome_tabela = con.nome_tabela
nome_constraint = con.nome_constraint
args = [a.argumento for a in con.argumento_set.all()]
args_string = '' args_string = ''
args_string = "(" + "_".join(map(str, args[2:-1])) + ")" args_string = "(" + "_".join(map(str, args[2:-1])) + ")"
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" % try:
(table, name, args_string)) exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
if unique_constraints: (nome_tabela, nome_constraint, args_string))
for constraint in unique_constraints: except ProgrammingError:
table, name, args, model = constraint info('A constraint %s já foi recriada!' % nome_constraint)
if con.tipo_constraint == 'unique_together':
nome_tabela = con.nome_tabela
nome_constraint = con.nome_constraint
# Pegando explicitamente o primeiro valor do filter,
# pois pode ser que haja mais de uma ocorrência
model = ContentType.objects.filter(
model=con.nome_model.lower())[0].model_class()
args = [a.argumento for a in con.argumento_set.all()]
for i in range(len(args)): for i in range(len(args)):
if isinstance(model._meta.get_field(args[i]), if isinstance(model._meta.get_field(args[i]),
models.ForeignKey): models.ForeignKey):
args[i] = args[i] + '_id' args[i] = args[i] + '_id'
args_string = '' args_string = ''
args_string += "(" + ', '.join(map(str, args)) + ")" args_string += "(" + ', '.join(map(str, args)) + ")"
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" % try:
(table, name, args_string)) exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
one_to_one_constraints.clear() (nome_tabela, nome_constraint, args_string))
unique_constraints.clear() 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): def obj_desnecessario(obj):
@ -262,8 +300,8 @@ def get_last_value(model):
def alter_sequence(model, id): def alter_sequence(model, id):
sequence_name = '%s_id_seq' % model._meta.db_table sequence_name = '%s_id_seq' % model._meta.db_table
exec_sql('ALTER SEQUENCE %s RESTART WITH %s MINVALUE %s;' % ( exec_sql('ALTER SEQUENCE %s RESTART WITH %s MINVALUE -1;' % (
sequence_name, id, id)) sequence_name, id))
def save_with_id(new, id): def save_with_id(new, id):
@ -278,8 +316,7 @@ def save_relation(obj, nome_campo='', problema='', descricao='',
eh_stub=False): eh_stub=False):
link = ProblemaMigracao( link = ProblemaMigracao(
content_object=obj, nome_campo=nome_campo, problema=problema, content_object=obj, nome_campo=nome_campo, problema=problema,
descricao=descricao, eh_stub=eh_stub, descricao=descricao, eh_stub=eh_stub,)
)
link.save() link.save()
@ -416,6 +453,8 @@ class DataMigrator:
call([PROJECT_DIR.child('manage.py'), 'flush', call([PROJECT_DIR.child('manage.py'), 'flush',
'--database=default', '--no-input'], stdout=PIPE) '--database=default', '--no-input'], stdout=PIPE)
desconecta_sinais_indexacao()
info('Começando migração: %s...' % obj) info('Começando migração: %s...' % obj)
self._do_migrate(obj) self._do_migrate(obj)
@ -427,7 +466,7 @@ class DataMigrator:
for obj in self.to_delete: for obj in self.to_delete:
msg = 'A entrada de PK %s da model %s não pode ser ' \ msg = 'A entrada de PK %s da model %s não pode ser ' \
'excluida' % (obj.pk, obj._meta.model_name) 'excluida' % (obj.pk, obj._meta.model_name)
descricao = 'Um ou mais objetos protegidos ' descricao = 'Um ou mais objetos protegidos'
warn(msg + ' => ' + descricao) warn(msg + ' => ' + descricao)
save_relation(obj=obj, problema=msg, save_relation(obj=obj, problema=msg,
descricao=descricao, eh_stub=False) descricao=descricao, eh_stub=False)
@ -435,8 +474,8 @@ class DataMigrator:
info('Deletando stubs desnecessários...') info('Deletando stubs desnecessários...')
while self.delete_stubs(): while self.delete_stubs():
pass pass
info('Recriando unique constraints...')
# recreate_constraints() conecta_sinais_indexacao()
def _do_migrate(self, obj): def _do_migrate(self, obj):
if isinstance(obj, AppConfig): if isinstance(obj, AppConfig):
@ -731,3 +770,23 @@ def make_with_log(model, _quantity=None, make_m2m=False, **attrs):
return stub return stub
make_with_log.required = foreign_key_required 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)

6
sapl/legacy/scripts/migra_um_db.sh

@ -23,3 +23,9 @@ echo "--- MIGRACAO DE DADOS ---" | tee -a $LOG
echo >> $LOG echo >> $LOG
DATABASE_NAME=$1 ./manage.py migracao_25_31 -f --settings sapl.legacy_migration_settings |& tee -a $LOG DATABASE_NAME=$1 ./manage.py migracao_25_31 -f --settings sapl.legacy_migration_settings |& tee -a $LOG
echo >> $LOG echo >> $LOG
echo "--- RECRIANDO CONSTRAINTS ---" | tee -a $LOG
echo >> $LOG
DATABASE_NAME=$1 ./manage.py recria_constraints --settings sapl.legacy_migration_settings |& tee -a $LOG
echo >> $LOG

3
sapl/materia/models.py

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import reversion
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -7,7 +8,6 @@ from django.db import models
from django.utils import formats from django.utils import formats
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
import reversion
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
@ -18,7 +18,6 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, SaplGenericForeignKey,
SaplGenericRelation, restringe_tipos_de_arquivo_txt, SaplGenericRelation, restringe_tipos_de_arquivo_txt,
texto_upload_path) texto_upload_path)
EM_TRAMITACAO = [(1, 'Sim'), EM_TRAMITACAO = [(1, 'Sim'),
(0, 'Não')] (0, 'Não')]

23
sapl/materia/signals.py

@ -1,26 +1,7 @@
from django.db.models.signals import post_delete, post_save from django.db.models.signals import post_delete, post_save
from sapl.settings import PROJECT_DIR from sapl.utils import save_texto, delete_texto
from subprocess import PIPE, call
from threading import Thread
from .models import DocumentoAcessorio, MateriaLegislativa
from .models import MateriaLegislativa, DocumentoAcessorio
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
post_save.connect(save_texto, sender=MateriaLegislativa) post_save.connect(save_texto, sender=MateriaLegislativa)

7
sapl/materia/urls.py

@ -4,10 +4,9 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
AcompanhamentoExcluirView, AcompanhamentoExcluirView,
AcompanhamentoMateriaView, AcompanhamentoMateriaView,
AdicionarVariasAutorias, AnexadaCrud, AdicionarVariasAutorias, AnexadaCrud,
AssuntoMateriaCrud, AssuntoMateriaCrud, AutoriaCrud,
AutoriaCrud, ConfirmarProposicao, ConfirmarProposicao, CriarProtocoloMateriaView,
CriarProtocoloMateriaView, DespachoInicialCrud, DespachoInicialCrud, DocumentoAcessorioCrud,
DocumentoAcessorioCrud,
DocumentoAcessorioEmLoteView, DocumentoAcessorioEmLoteView,
LegislacaoCitadaCrud, MateriaAssuntoCrud, LegislacaoCitadaCrud, MateriaAssuntoCrud,
MateriaLegislativaCrud, MateriaLegislativaCrud,

24
sapl/materia/views.py

@ -43,21 +43,19 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm, AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, DocumentoAcessorioForm, MateriaAssuntoForm,
MateriaAssuntoForm, MateriaLegislativaFilterSet, MateriaLegislativaFilterSet, MateriaSimplificadaForm,
MateriaSimplificadaForm, PrimeiraTramitacaoEmLoteFilterSet, PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm,
ReceberProposicaoForm, RelatoriaForm, RelatoriaForm, TramitacaoEmLoteFilterSet,
TramitacaoEmLoteFilterSet, filtra_tramitacao_destino, filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status, filtra_tramitacao_destino_and_status,
filtra_tramitacao_status) filtra_tramitacao_status)
from .models import (AssuntoMateria, AcompanhamentoMateria, from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
Anexada, Autoria, DespachoInicial, DespachoInicial, DocumentoAcessorio, MateriaAssunto,
DocumentoAcessorio, MateriaLegislativa, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
MateriaAssunto, Numeracao, Orgao, RegimeTramitacao, Relatoria, StatusTramitacao,
Origem, Proposicao, RegimeTramitacao, Relatoria, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
StatusTramitacao, TipoDocumento, TipoFimRelatoria, TipoProposicao, Tramitacao, UnidadeTramitacao)
TipoMateriaLegislativa, TipoProposicao, Tramitacao,
UnidadeTramitacao)
AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia') AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia')

4
sapl/norma/models.py

@ -7,8 +7,8 @@ from model_utils import Choices
from sapl.compilacao.models import TextoArticulado from sapl.compilacao.models import TextoArticulado
from sapl.materia.models import MateriaLegislativa from sapl.materia.models import MateriaLegislativa
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
restringe_tipos_de_arquivo_txt) restringe_tipos_de_arquivo_txt, texto_upload_path)
@reversion.register() @reversion.register()

21
sapl/norma/signals.py

@ -1,27 +1,8 @@
from django.db.models.signals import post_delete, post_save from django.db.models.signals import post_delete, post_save
from sapl.settings import PROJECT_DIR from sapl.utils import save_texto, delete_texto
from subprocess import PIPE, call
from threading import Thread
from .models import NormaJuridica from .models import NormaJuridica
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
post_save.connect(save_texto, sender=NormaJuridica) post_save.connect(save_texto, sender=NormaJuridica)
post_delete.connect(delete_texto, sender=NormaJuridica) post_delete.connect(delete_texto, sender=NormaJuridica)

1
sapl/norma/views.py

@ -4,6 +4,7 @@ from django.http import JsonResponse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
from django_filters.views import FilterView from django_filters.views import FilterView
from sapl.base.models import AppConfig from sapl.base.models import AppConfig
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,

1
sapl/parlamentares/views.py

@ -22,7 +22,6 @@ from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa, NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
SituacaoMilitar, TipoAfastamento, TipoDependente, Votante) SituacaoMilitar, TipoAfastamento, TipoDependente, Votante)
CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa') CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa')
PartidoCrud = CrudAux.build(Partido, 'partidos') PartidoCrud = CrudAux.build(Partido, 'partidos')
SessaoLegislativaCrud = CrudAux.build(SessaoLegislativa, 'sessao_legislativa') SessaoLegislativaCrud = CrudAux.build(SessaoLegislativa, 'sessao_legislativa')

4
sapl/protocoloadm/forms.py

@ -544,10 +544,10 @@ class DocumentoAdministrativoForm(ModelForm):
ano_protocolo = forms.ChoiceField(required=False, ano_protocolo = forms.ChoiceField(required=False,
label=Protocolo._meta. label=Protocolo._meta.
get_field('ano').verbose_name, get_field('ano').verbose_name,
choices=RANGE_ANOS, choices=RANGE_ANOS,
widget=forms.Select( widget=forms.Select(
attrs={'class': 'selector'})) attrs={'class': 'selector'}))
class Meta: class Meta:
model = DocumentoAdministrativo model = DocumentoAdministrativo

39
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -101,7 +101,7 @@ def inf_basicas(inf_basicas_dic):
tmp += '\t\t<para style="P1">Informações Básicas</para>\n' tmp += '\t\t<para style="P1">Informações Básicas</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Tipo da Sessão: </b> ' + \ tmp += '\t\t<para style="P2" spaceAfter="5"><b>Tipo da Sessão: </b> ' + \
nom_sessao + '</para>\n' nom_sessao + '</para>\n'
@ -120,7 +120,7 @@ def mesa(lst_mesa):
tmp = '' tmp = ''
tmp += '\t\t<para style="P1">Mesa Diretora</para>\n' tmp += '\t\t<para style="P1">Mesa Diretora</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
for mesa in lst_mesa: for mesa in lst_mesa:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \ tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
@ -136,7 +136,7 @@ def presenca(lst_presenca_sessao):
tmp = '' tmp = ''
tmp += '\t\t<para style="P1">Lista de Presença da Sessão</para>\n' tmp += '\t\t<para style="P1">Lista de Presença da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
for presenca in lst_presenca_sessao: for presenca in lst_presenca_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \ tmp += '\t\t<para style="P2" spaceAfter="5">' + \
@ -154,10 +154,10 @@ def expedientes(lst_expedientes):
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
for expediente in lst_expedientes: for idx, expediente in enumerate(lst_expedientes):
tmp += '\t\t<para style="P2"><b>' + \ tmp += '\t\t<para style="P2"><b>' + '<br/> ' + \
expediente['nom_expediente'] + ': </b></para>\n' + \ expediente['nom_expediente'] + ': </b></para>\n' + \
'<para style="P2">' + \ '<para style="P2">' + \
expediente['txt_expediente'] + '</para>\n' expediente['txt_expediente'] + '</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> </font>\n'
@ -171,7 +171,7 @@ def expediente_materia(lst_expediente_materia):
tmp = '' tmp = ''
tmp += '\t\t<para style="P1">Matérias do Expediente</para>\n\n' tmp += '\t\t<para style="P1">Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n' tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n' tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
@ -181,8 +181,12 @@ def expediente_materia(lst_expediente_materia):
txt_ementa = expediente_materia['txt_ementa'].replace('&', '&amp;') txt_ementa = expediente_materia['txt_ementa'].replace('&', '&amp;')
tmp += '<td><para style="P4">' + txt_ementa + '</para></td>\n' tmp += '<td><para style="P4">' + txt_ementa + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \ tmp += '<td><para style="P3"><b>' + \
str(expediente_materia['nom_resultado']) + '</b></para>\n' + '<para style="P3">' + \ str(expediente_materia['nom_resultado']) + '</b></para>\n' + '<para style="P3">'
str(expediente_materia['votacao_observacao']) + '</para></td></tr>\n' if expediente_materia['votacao_observacao'] != txt_ementa:
tmp += str(expediente_materia['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n' tmp += '\t\t</blockTable>\n'
return tmp return tmp
@ -195,7 +199,7 @@ def oradores_expediente(lst_oradores_expediente):
tmp = '' tmp = ''
tmp += '\t\t<para style="P1">Oradores do Expediente</para>\n' tmp += '\t\t<para style="P1">Oradores do Expediente</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
for orador_expediente in lst_oradores_expediente: for orador_expediente in lst_oradores_expediente:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + str(orador_expediente['num_ordem']) + '</b> - ' + orador_expediente[ tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + str(orador_expediente['num_ordem']) + '</b> - ' + orador_expediente[
@ -210,7 +214,7 @@ def presenca_ordem_dia(lst_presenca_ordem_dia):
tmp = '' tmp = ''
tmp += '\t\t<para style="P1">Lista de Presença da Ordem do Dia</para>\n' tmp += '\t\t<para style="P1">Lista de Presença da Ordem do Dia</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
for presenca_ordem_dia in lst_presenca_ordem_dia: for presenca_ordem_dia in lst_presenca_ordem_dia:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \ tmp += '\t\t<para style="P2" spaceAfter="5">' + \
@ -226,7 +230,7 @@ def votacao(lst_votacao):
tmp = '' tmp = ''
tmp += '<para style="P1">Matérias da Ordem do Dia</para>\n\n' tmp += '<para style="P1">Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n' tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n' tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
@ -236,8 +240,12 @@ def votacao(lst_votacao):
txt_ementa = votacao['txt_ementa'].replace('&', '&amp;') txt_ementa = votacao['txt_ementa'].replace('&', '&amp;')
tmp += '<td><para style="P4">' + txt_ementa + '</para></td>\n' tmp += '<td><para style="P4">' + txt_ementa + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \ tmp += '<td><para style="P3"><b>' + \
str(votacao['nom_resultado']) + '</b></para>\n' + '<para style="P3">' + \ str(votacao['nom_resultado']) + '</b></para>\n' + '<para style="P3">'
str(votacao['votacao_observacao']) + '</para></td></tr>\n' if votacao['votacao_observacao'] != txt_ementa:
tmp += str(votacao['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n' tmp += '\t\t</blockTable>\n'
return tmp return tmp
@ -250,7 +258,7 @@ def oradores(lst_oradores):
tmp = '' tmp = ''
tmp += '\t\t<para style="P1">Oradores das Explicações Pessoais</para>\n' tmp += '\t\t<para style="P1">Oradores das Explicações Pessoais</para>\n'
tmp += '\t\t<para style="P2">\n' tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n' tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n' tmp += '\t\t</para>\n'
for orador in lst_oradores: for orador in lst_oradores:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \ tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
@ -290,6 +298,7 @@ def principal(cabecalho_dic, rodape_dic, imagem, sessao, inf_basicas_dic, lst_me
tmp += oradores(lst_oradores) tmp += oradores(lst_oradores)
tmp += '\t</story>\n' tmp += '\t</story>\n'
tmp += '</document>\n' tmp += '</document>\n'
tmp_pdf = parseString(tmp) tmp_pdf = parseString(tmp)
return tmp_pdf return tmp_pdf
# if hasattr(context.temp_folder,arquivoPdf): # if hasattr(context.temp_folder,arquivoPdf):

50
sapl/relatorios/views.py

@ -8,15 +8,14 @@ from sapl.base.models import Autor, CasaLegislativa
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.materia.models import (Autoria, MateriaLegislativa, Numeracao, from sapl.materia.models import (Autoria, MateriaLegislativa, Numeracao,
Tramitacao, UnidadeTramitacao) Tramitacao, UnidadeTramitacao)
from sapl.parlamentares.models import (CargoMesa, ComposicaoMesa, Filiacao, from sapl.parlamentares.models import CargoMesa, Filiacao, Parlamentar
Parlamentar)
from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo, from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
TramitacaoAdministrativo) TramitacaoAdministrativo)
from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao, from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, Orador, IntegranteMesa, Orador, OradorExpediente,
OradorExpediente, OrdemDia, PresencaOrdemDia, OrdemDia, PresencaOrdemDia, RegistroVotacao,
RegistroVotacao, SessaoPlenaria, SessaoPlenaria, SessaoPlenariaPresenca,
SessaoPlenariaPresenca, TipoExpediente) TipoExpediente)
from sapl.settings import STATIC_ROOT from sapl.settings import STATIC_ROOT
from sapl.utils import UF from sapl.utils import UF
@ -519,14 +518,14 @@ def get_sessao_plenaria(sessao, casa):
# Exibe os Expedientes # Exibe os Expedientes
lst_expedientes = [] lst_expedientes = []
for tip_expediente in TipoExpediente.objects.all(): expedientes = ExpedienteSessao.objects.filter(
for expediente in ExpedienteSessao.objects.filter( sessao_plenaria=sessao).order_by('tipo__nome')
sessao_plenaria=sessao, tipo=tip_expediente): for e in expedientes:
dic_expedientes = {} dic_expedientes = {}
dic_expedientes["nom_expediente"] = str(tip_expediente) dic_expedientes["nom_expediente"] = e.tipo.nome
dic_expedientes["txt_expediente"] = (expediente.conteudo) dic_expedientes["txt_expediente"] = e.conteudo
if dic_expedientes: if dic_expedientes:
lst_expedientes.append(dic_expedientes) lst_expedientes.append(dic_expedientes)
# Lista das matérias do Expediente, incluindo o resultado das votacoes # Lista das matérias do Expediente, incluindo o resultado das votacoes
lst_expediente_materia = [] lst_expediente_materia = []
@ -595,18 +594,16 @@ def get_sessao_plenaria(sessao, casa):
dic_expediente_materia["nom_autor"] = 'Desconhecido' dic_expediente_materia["nom_autor"] = 'Desconhecido'
dic_expediente_materia["votacao_observacao"] = ' ' dic_expediente_materia["votacao_observacao"] = ' '
if not expediente_materia.resultado: resultados = expediente_materia.registrovotacao_set.all()
resultado = RegistroVotacao.objects.filter( if resultados:
tipo_resultado_votacao=expediente_materia.tipo_votacao) for i in resultados:
for i in resultado:
dic_expediente_materia["nom_resultado"] = ( dic_expediente_materia["nom_resultado"] = (
i.tipo_resultado_votacao.nome) i.tipo_resultado_votacao.nome)
dic_expediente_materia["votacao_observacao"] = ( dic_expediente_materia["votacao_observacao"] = (
expediente_materia.observacao) i.observacao)
else: else:
dic_expediente_materia["nom_resultado"] = _("Matéria não votada") dic_expediente_materia["nom_resultado"] = _("Matéria não votada")
dic_expediente_materia["votacao_observacao"] = _("Vazio") dic_expediente_materia["votacao_observacao"] = _(" ")
lst_expediente_materia.append(dic_expediente_materia) lst_expediente_materia.append(dic_expediente_materia)
# Lista dos oradores do Expediente # Lista dos oradores do Expediente
@ -711,16 +708,15 @@ def get_sessao_plenaria(sessao, casa):
dic_votacao["nom_autor"] = 'Desconhecido' dic_votacao["nom_autor"] = 'Desconhecido'
dic_votacao["votacao_observacao"] = ' ' dic_votacao["votacao_observacao"] = ' '
if not votacao.resultado: resultados = votacao.registrovotacao_set.all()
resultado = RegistroVotacao.objects.filter( if resultados:
tipo_resultado_votacao=votacao.tipo_votacao) for i in resultados:
for i in resultado:
dic_votacao["nom_resultado"] = i.tipo_resultado_votacao.nome dic_votacao["nom_resultado"] = i.tipo_resultado_votacao.nome
if votacao.observacao: if votacao.observacao:
dic_votacao["votacao_observacao"] = votacao.observacao dic_votacao["votacao_observacao"] = i.observacao
else: else:
dic_votacao["nom_resultado"] = _("Matéria não votada") dic_votacao["nom_resultado"] = _("Matéria não votada")
dic_votacao["votacao_observacao"] = _("Vazio") dic_votacao["votacao_observacao"] = _(" ")
lst_votacao.append(dic_votacao) lst_votacao.append(dic_votacao)
# Lista dos oradores nas Explicações Pessoais # Lista dos oradores nas Explicações Pessoais

2
sapl/rules/map_rules.py

@ -197,6 +197,8 @@ rules_group_geral = {
(base.CasaLegislativa, __listdetailchange__), (base.CasaLegislativa, __listdetailchange__),
(base.ProblemaMigracao, []), (base.ProblemaMigracao, []),
(base.Argumento, []),
(base.Constraint, []),
(base.TipoAutor, __base__), (base.TipoAutor, __base__),
(base.Autor, __base__), (base.Autor, __base__),

13
sapl/rules/tests/test_rules.py

@ -6,7 +6,8 @@ from django.contrib.contenttypes.models import ContentType
from django.utils import six from django.utils import six
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.base.models import CasaLegislativa, ProblemaMigracao from sapl.base.models import (CasaLegislativa, ProblemaMigracao, Argumento,
Constraint)
from sapl.compilacao.models import (PerfilEstruturalTextoArticulado, from sapl.compilacao.models import (PerfilEstruturalTextoArticulado,
TipoDispositivo, TipoDispositivo,
TipoDispositivoRelationship) TipoDispositivoRelationship)
@ -56,11 +57,15 @@ def test_models_in_rules_patterns(model_item):
__fp__in__test_permission_of_models_in_rules_patterns = { __fp__in__test_permission_of_models_in_rules_patterns = {
map_rules.RP_ADD: [CasaLegislativa, map_rules.RP_ADD: [CasaLegislativa,
ProblemaMigracao, ProblemaMigracao,
Argumento,
Constraint,
TipoDispositivo, TipoDispositivo,
TipoDispositivoRelationship, TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado], PerfilEstruturalTextoArticulado],
map_rules.RP_CHANGE: [ProblemaMigracao, map_rules.RP_CHANGE: [ProblemaMigracao,
Argumento,
Constraint,
AcompanhamentoMateria, AcompanhamentoMateria,
TipoDispositivo, TipoDispositivo,
TipoDispositivoRelationship, TipoDispositivoRelationship,
@ -68,17 +73,23 @@ __fp__in__test_permission_of_models_in_rules_patterns = {
map_rules.RP_DELETE: [CasaLegislativa, map_rules.RP_DELETE: [CasaLegislativa,
ProblemaMigracao, ProblemaMigracao,
Argumento,
Constraint,
TipoDispositivo, TipoDispositivo,
TipoDispositivoRelationship, TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado], PerfilEstruturalTextoArticulado],
map_rules.RP_LIST: [ProblemaMigracao, map_rules.RP_LIST: [ProblemaMigracao,
Argumento,
Constraint,
AcompanhamentoMateria, AcompanhamentoMateria,
TipoDispositivo, TipoDispositivo,
TipoDispositivoRelationship, TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado], PerfilEstruturalTextoArticulado],
map_rules.RP_DETAIL: [ProblemaMigracao, map_rules.RP_DETAIL: [ProblemaMigracao,
Argumento,
Constraint,
AcompanhamentoMateria, AcompanhamentoMateria,
TipoDispositivo, TipoDispositivo,
TipoDispositivoRelationship, TipoDispositivoRelationship,

50
sapl/sessao/views.py

@ -164,7 +164,8 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
def get_rows(self, object_list): def get_rows(self, object_list):
for obj in object_list: for obj in object_list:
if not obj.resultado: resultados = obj.registrovotacao_set.all()
if not resultados:
if obj.votacao_aberta: if obj.votacao_aberta:
url = '' url = ''
if obj.tipo_votacao == 1: if obj.tipo_votacao == 1:
@ -208,6 +209,8 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
else: else:
obj.resultado = '''Não há resultado''' obj.resultado = '''Não há resultado'''
else: else:
resultado = resultados[0].tipo_resultado_votacao.nome
resultado_observacao = resultados[0].observacao
if self.request.user.has_module_perms(AppConfig.label): if self.request.user.has_module_perms(AppConfig.label):
url = '' url = ''
if obj.tipo_votacao == 1: if obj.tipo_votacao == 1:
@ -228,10 +231,13 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
'pk': obj.sessao_plenaria_id, 'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id, 'oid': obj.materia_id,
'mid': obj.pk}) 'mid': obj.pk})
obj.resultado = '<a href="%s">%s</a>' % (url, obj.resultado = ('<a href="%s">%s</a><br/>%s' %
obj.resultado) (url,
resultado,
resultado_observacao))
else: else:
obj.resultado = '%s' % (obj.resultado) obj.resultado = ('%s<br/>%s' %
(resultado, resultado_observacao))
return [self._as_row(obj) for obj in object_list] return [self._as_row(obj) for obj in object_list]
@ -268,7 +274,8 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
def get_rows(self, object_list): def get_rows(self, object_list):
for obj in object_list: for obj in object_list:
if not obj.resultado: resultados = obj.registrovotacao_set.all()
if not resultados:
if obj.votacao_aberta: if obj.votacao_aberta:
url = '' url = ''
if obj.tipo_votacao == 1: if obj.tipo_votacao == 1:
@ -310,7 +317,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
obj.resultado = btn_abrir obj.resultado = btn_abrir
else: else:
url = '' url = ''
resultado = resultados[0].tipo_resultado_votacao.nome
if self.request.user.has_module_perms(AppConfig.label): if self.request.user.has_module_perms(AppConfig.label):
if obj.tipo_votacao == 1: if obj.tipo_votacao == 1:
url = reverse( url = reverse(
@ -332,7 +339,9 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
'oid': obj.materia_id, 'oid': obj.materia_id,
'mid': obj.pk}) 'mid': obj.pk})
obj.resultado = '<a href="%s">%s</a>' % (url, obj.resultado = '<a href="%s">%s</a>' % (url,
obj.resultado) resultado)
else:
obj.resultado = '%s' % (resultado)
return [self._as_row(obj) for obj in object_list] return [self._as_row(obj) for obj in object_list]
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
@ -604,7 +613,7 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
cronometro_ordem = AppsAppConfig.attr('cronometro_ordem') cronometro_ordem = AppsAppConfig.attr('cronometro_ordem')
if (not cronometro_discurso or not cronometro_aparte if (not cronometro_discurso or not cronometro_aparte
or not cronometro_ordem): or not cronometro_ordem):
msg = _( msg = _(
'Você precisa primeiro configurar os cronômetros \ 'Você precisa primeiro configurar os cronômetros \
nas Configurações da Aplicação') nas Configurações da Aplicação')
@ -982,12 +991,14 @@ class ResumoView(DetailView):
materias_expediente = [] materias_expediente = []
for m in materias: for m in materias:
ementa = m.observacao ementa = m.observacao
titulo = m.materia titulo = m.materia
numero = m.numero_ordem numero = m.numero_ordem
if m.resultado: resultado = m.registrovotacao_set.all()
resultado = m.resultado if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else: else:
resultado = _('Matéria não votada') resultado = _('Matéria não votada')
@ -1039,7 +1050,6 @@ class ResumoView(DetailView):
# Matérias Ordem do Dia # Matérias Ordem do Dia
ordem = OrdemDia.objects.filter( ordem = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id) sessao_plenaria_id=self.object.id)
materias_ordem = [] materias_ordem = []
for o in ordem: for o in ordem:
ementa = o.observacao ementa = o.observacao
@ -1047,8 +1057,9 @@ class ResumoView(DetailView):
numero = o.numero_ordem numero = o.numero_ordem
# Verificar resultado # Verificar resultado
if o.resultado: resultado = o.registrovotacao_set.all()
resultado = o.resultado if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else: else:
resultado = _('Matéria não votada') resultado = _('Matéria não votada')
@ -2065,9 +2076,9 @@ class PautaSessaoDetailView(DetailView):
situacao = m.materia.tramitacao_set.last().status situacao = m.materia.tramitacao_set.last().status
if situacao is None: if situacao is None:
situacao = _("Não informada") situacao = _("Não informada")
resultado = m.registrovotacao_set.all()
if m.resultado: if resultado:
resultado = m.resultado resultado = resultado[0].tipo_resultado_votacao.nome
else: else:
resultado = _('Matéria não votada') resultado = _('Matéria não votada')
@ -2118,8 +2129,9 @@ class PautaSessaoDetailView(DetailView):
numero = o.numero_ordem numero = o.numero_ordem
# Verificar resultado # Verificar resultado
if o.resultado: resultado = o.registrovotacao_set.all()
resultado = o.resultado if resultado:
resultado = resultado[0].tipo_resultado_votacao.nome
else: else:
resultado = _('Matéria não votada') resultado = _('Matéria não votada')
@ -2436,7 +2448,7 @@ def mudar_ordem_materia_sessao(request):
sessao_plenaria=pk_sessao, sessao_plenaria=pk_sessao,
numero_ordem=posicao_inicial) numero_ordem=posicao_inicial)
except ObjectDoesNotExist: except ObjectDoesNotExist:
raise # TODO tratar essa exceção raise # TODO tratar essa exceção
# Se a posição inicial for menor que a final, todos que # Se a posição inicial for menor que a final, todos que
# estiverem acima da nova posição devem ter sua ordem decrementada # estiverem acima da nova posição devem ter sua ordem decrementada

1
sapl/settings.py

@ -237,6 +237,7 @@ BOWER_INSTALLED_APPS = (
'jQuery-Mask-Plugin#1.14.0', 'jQuery-Mask-Plugin#1.14.0',
'jsdiff#2.2.2', 'jsdiff#2.2.2',
'https://github.com/interlegis/drunken-parrot-flat-ui.git', 'https://github.com/interlegis/drunken-parrot-flat-ui.git',
'jquery-query-object#2.2.3',
) )
# Additional search paths for SASS files when using the @import statement # Additional search paths for SASS files when using the @import statement

2
sapl/templates/base.html

@ -224,6 +224,8 @@
<script type="text/javascript" src="{% static 'js/app.js' %}"></script> <script type="text/javascript" src="{% static 'js/app.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-query-object/jquery.query-object.js' %}"></script>
{% block extra_js %}{% endblock %} {% block extra_js %}{% endblock %}
{% endblock foot_js %} {% endblock foot_js %}

45
sapl/templates/sessao/sessaoplenaria_filter.html

@ -9,16 +9,11 @@
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %}
{% endif %} {% endif %}
</a> </a>
{% if filter_url %}
<a href="{% url 'sapl.sessao:pesquisar_sessao' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}
{% block detail_content %} {% block detail_content %}
{% if not filter_url %} {% crispy filter.form %}
{% crispy filter.form %}
{% endif %}
{% if filter_url %} {% if filter_url %}
<p></p> <p></p>
@ -51,3 +46,41 @@
{% endblock detail_content %} {% endblock detail_content %}
{% block table_content %} {% block table_content %}
{% endblock table_content %} {% endblock table_content %}
{% block extra_js %}
<script type="text/javascript">
var querystring = "{{filter_url|safe}}"
// Esse IF garante que já existe uma querystring, ou seja, algo já foi pesquisado
if(querystring.length != 0){
$('#id_data_inicio__year').on({
change: function(){
window.location.search = jQuery.query.set("data_inicio__year", $('#id_data_inicio__year').val());
}
})
$('#id_data_inicio__month').on({
change: function(){
window.location.search = jQuery.query.set("data_inicio__month", $('#id_data_inicio__month').val());
}
})
$('#id_data_inicio__day').on({
change: function(){
window.location.search = jQuery.query.set("data_inicio__day", $('#id_data_inicio__day').val());
}
})
$('#id_tipo').on({
change: function(){
window.location.search = jQuery.query.set("tipo", $('#id_tipo').val());
}
})
}
</script>
{% endblock %}

1
sapl/templates/sessao/sessaoplenaria_form.html

@ -31,7 +31,6 @@
$(function() { $(function() {
function altera_legislatura(){ function altera_legislatura(){
console.debug('hey');
var id_legislatura = $("#id_legislatura").val(); var id_legislatura = $("#id_legislatura").val();
var id_sessao_leg = $("#id_sessao_legislativa").val(); var id_sessao_leg = $("#id_sessao_legislativa").val();
$("#id_sessao_legislativa option").remove(); $("#id_sessao_legislativa option").remove();

3
sapl/test_urls.py

@ -361,6 +361,7 @@ for item in _lista_urls:
__lista_urls.append((oper, item))""" __lista_urls.append((oper, item))"""
@pytest.mark.skip(reason="TODO: Lento demais. Precisa ser refatorado")
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
@pytest.mark.parametrize('url_item', _lista_urls) @pytest.mark.parametrize('url_item', _lista_urls)
def test_permissions_urls_for_users_by_apps(url_item, client): def test_permissions_urls_for_users_by_apps(url_item, client):
@ -402,7 +403,7 @@ def test_permissions_urls_for_users_by_apps(url_item, client):
container, como é o caso de proposições que possui restrição container, como é o caso de proposições que possui restrição
por usuário e não por, ou não tem, o campo permission_required por usuário e não por, ou não tem, o campo permission_required
""" """
if PermissionRequiredForAppCrudMixin in type.mro(key.view_class): if issubclass(key.view_class, PermissionRequiredForAppCrudMixin):
# essa classe deve informar app_label # essa classe deve informar app_label
assert hasattr(key.view_class, 'app_label') assert hasattr(key.view_class, 'app_label')
# app_label deve ter conteudo # app_label deve ter conteudo

20
sapl/utils.py

@ -5,6 +5,8 @@ import re
from datetime import date from datetime import date
from functools import wraps from functools import wraps
from unicodedata import normalize as unicodedata_normalize from unicodedata import normalize as unicodedata_normalize
from subprocess import PIPE, call
from threading import Thread
import django_filters import django_filters
import magic import magic
@ -22,7 +24,7 @@ from floppyforms import ClearableFileInput
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.settings import BASE_DIR from sapl.settings import BASE_DIR, PROJECT_DIR
sapl_logger = logging.getLogger(BASE_DIR.name) sapl_logger = logging.getLogger(BASE_DIR.name)
@ -632,3 +634,19 @@ def texto_upload_path(instance, filename, subpath=''):
} }
return path return path
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()

Loading…
Cancel
Save