Browse Source

Merge branch 'master' of github.com:interlegis/sapl into 1487-abertura-do-painel

pull/1499/head
João Pedro Sconetto 8 years ago
parent
commit
6ac9395394
  1. 2
      docker-compose.yml
  2. 34
      docs/credits.txt
  3. 15
      sapl/compilacao/models.py
  4. 4
      sapl/decorators.py
  5. 50
      sapl/legacy/migracao_documentos.py
  6. 69
      sapl/legacy/migracao_usuarios.py
  7. 41
      sapl/legacy/migration.py
  8. 13
      sapl/legacy/models.py
  9. 7
      sapl/legacy/scripts/migra_dbs.sh
  10. 10
      sapl/legacy/scripts/recria_dbs_postgres.sh
  11. 8
      sapl/materia/email_utils.py
  12. 32
      sapl/materia/forms.py
  13. 5
      sapl/materia/models.py
  14. 43
      sapl/materia/views.py
  15. 4
      sapl/norma/forms.py
  16. 11
      sapl/norma/views.py
  17. 1
      sapl/painel/views.py
  18. 6
      sapl/parlamentares/forms.py
  19. 38
      sapl/parlamentares/migrations/0010_corrige_data_inicio_mandato.py
  20. 6
      sapl/parlamentares/models.py
  21. 13
      sapl/parlamentares/views.py
  22. 62
      sapl/protocoloadm/forms.py
  23. 22
      sapl/protocoloadm/tests/test_protocoloadm.py
  24. 83
      sapl/protocoloadm/views.py
  25. 10
      sapl/relatorios/views.py
  26. 4
      sapl/sessao/forms.py
  27. 9
      sapl/sessao/views.py
  28. 2
      sapl/settings.py
  29. 4
      sapl/templates/materia/prop_devolvidas_list.html
  30. 3
      sapl/templates/materia/prop_pendentes_list.html
  31. 3
      sapl/templates/materia/prop_recebidas_list.html
  32. 4
      sapl/templates/materia/proposicao_detail.html
  33. 3
      sapl/templates/materia/recibo_proposicao.html
  34. 2
      sapl/templates/protocoloadm/protocolo_filter.html
  35. 4
      sapl/templates/protocoloadm/protocolo_list.html
  36. 3
      sapl/templates/protocoloadm/protocolo_mostrar.html
  37. 12
      sapl/templates/protocoloadm/tramitacaoadministrativo_form.html
  38. 6
      sapl/utils.py

2
docker-compose.yml

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

34
docs/credits.txt

@ -0,0 +1,34 @@
Créditos do SAPL - até versão 2.5
=================================
Obrigado aos colaboradores:
- Adriano Gomes
- Angelo Marcondes Neto
- Claudio Morale
- Daniel C. Azevedo
- Davi Lima de Medeiros
- Edson Ma
- Fernando Ciciliati Júnior
- Gustavo Lepri
- Halison Casimiro
- Helder Vieira
- Jean Rodrigo Ferri
- João Lima
- José Borges
- Leandro Roberto
- Leonardo Caballero
- Luciano Di Fázio
- Luis Fernando Pires Machado
- Marcio Mazza
- Marcos Fragomeni
- Maria Cristina André de Mello
- Marta Maria Pincowsca Cardoso Maia
- Paulo Fernandes de Souza Júnior
- Petronio Barbosa Carvalho
- Ricardo Esperandio
- Rodrigo Barbosa Luz
- Sesóstris Vieira
- Sérgio Damiati
- Wilton Souza Alencar
- Wu Man Qi

15
sapl/compilacao/models.py

@ -1,4 +1,3 @@
from datetime import datetime
import reversion import reversion
from django.contrib import messages from django.contrib import messages
@ -10,6 +9,7 @@ from django.db.models.aggregates import Max
from django.db.models.deletion import PROTECT from django.db.models.deletion import PROTECT
from django.http.response import Http404 from django.http.response import Http404
from django.template import defaultfilters from django.template import defaultfilters
from django.utils import timezone
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -357,9 +357,9 @@ class TextoArticulado(TimestampedMixin):
if not ta.data: if not ta.data:
ta.data = getattr(obj, map_fields['data'] ta.data = getattr(obj, map_fields['data']
if map_fields['data'] else 'xxx', if map_fields['data'] else 'xxx',
datetime.now()) timezone.now())
if not ta.data: if not ta.data:
ta.data = datetime.now() ta.data = timezone.now()
ta.ementa = getattr( ta.ementa = getattr(
obj, map_fields['ementa'] obj, map_fields['ementa']
@ -370,15 +370,16 @@ class TextoArticulado(TimestampedMixin):
obj, map_fields['observacao'] obj, map_fields['observacao']
if map_fields['observacao'] else 'xxx', '') if map_fields['observacao'] else 'xxx', '')
now = timezone.now()
ta.numero = getattr( ta.numero = getattr(
obj, map_fields['numero'] obj, map_fields['numero']
if map_fields['numero'] else 'xxx', int('%s%s%s' % ( if map_fields['numero'] else 'xxx', int('%s%s%s' % (
int(datetime.now().year), int(now.year),
int(datetime.now().month), int(now.month),
int(datetime.now().day)))) int(now.day))))
ta.ano = getattr(obj, map_fields['ano'] ta.ano = getattr(obj, map_fields['ano']
if map_fields['ano'] else 'xxx', datetime.now().year) if map_fields['ano'] else 'xxx', now.year)
ta.save() ta.save()
return ta return ta

4
sapl/decorators.py

@ -1,6 +1,6 @@
from datetime import date
from functools import wraps from functools import wraps
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -18,7 +18,7 @@ def vigencia_atual(decorated_method):
string_displayed = decorated_method(self) string_displayed = decorated_method(self)
if hasattr(self, 'data_inicio') and hasattr(self, 'data_fim'): if hasattr(self, 'data_inicio') and hasattr(self, 'data_fim'):
today = date.today() today = timezone.now().today().date()
e_atual = self.data_inicio <= today <= self.data_fim e_atual = self.data_inicio <= today <= self.data_fim
string_displayed = "{} {}".format( string_displayed = "{} {}".format(
string_displayed, "(Atual)" if e_atual else "") string_displayed, "(Atual)" if e_atual else "")

50
sapl/legacy/migracao_documentos.py

@ -5,6 +5,7 @@ import re
import magic import magic
from sapl.base.models import CasaLegislativa from sapl.base.models import CasaLegislativa
from sapl.legacy.migration import warn
from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa, from sapl.materia.models import (DocumentoAcessorio, MateriaLegislativa,
Proposicao) Proposicao)
from sapl.norma.models import NormaJuridica from sapl.norma.models import NormaJuridica
@ -21,6 +22,7 @@ EXTENSOES = {
'application/vnd.oasis.opendocument.text': '.odt', 'application/vnd.oasis.opendocument.text': '.odt',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx', # noqa
'application/xml': '.xml', 'application/xml': '.xml',
'text/xml': '.xml',
'application/zip': '.zip', 'application/zip': '.zip',
'image/jpeg': '.jpeg', 'image/jpeg': '.jpeg',
'image/png': '.png', 'image/png': '.png',
@ -90,11 +92,11 @@ DOCS = {
], ],
} }
DOCS = {tipo: [(campo, DOCS = {model: [(campo,
os.path.join('sapl_documentos', origem), os.path.join('sapl_documentos', origem),
os.path.join('sapl', destino)) os.path.join('sapl', destino))
for campo, origem, destino in campos] for campo, origem, destino in campos]
for tipo, campos in DOCS.items()} for model, campos in DOCS.items()}
def em_media(caminho): def em_media(caminho):
@ -125,10 +127,14 @@ def migrar_docs_logo():
# a pasta props_sapl deve conter apenas o origem e metadatas! # a pasta props_sapl deve conter apenas o origem e metadatas!
# Edit: Aparentemente há diretório que contém properties ao invés de # Edit: Aparentemente há diretório que contém properties ao invés de
# metadata. O assert foi modificado para essa situação. # metadata. O assert foi modificado para essa situação.
assert set(os.listdir(em_media(props_sapl))) < { sobrando = set(os.listdir(em_media(props_sapl))) - {
'logo_casa.gif', '.metadata', 'logo_casa.gif.metadata', 'logo_casa.gif', '.metadata', 'logo_casa.gif.metadata',
'.properties', 'logo_casa.gif.properties', '.objects'} '.properties', 'logo_casa.gif.properties', '.objects'}
if sobrando:
warn('Os seguintes arquivos da pasta props_sapl foram ignorados: ' +
', '.join(sobrando))
mover_documento(origem, destino) mover_documento(origem, destino)
casa = get_casa_legislativa() casa = get_casa_legislativa()
casa.logotipo = destino casa.logotipo = destino
@ -152,9 +158,9 @@ def get_extensao(caminho):
)) from e )) from e
def migrar_docs_por_ids(tipo): def migrar_docs_por_ids(model):
for campo, base_origem, base_destino in DOCS[tipo]: for campo, base_origem, base_destino in DOCS[model]:
print('#### Migrando {} de {} ####'.format(campo, tipo.__name__)) print('#### Migrando {} de {} ####'.format(campo, model.__name__))
dir_origem, nome_origem = os.path.split(em_media(base_origem)) dir_origem, nome_origem = os.path.split(em_media(base_origem))
pat = re.compile('^{}$'.format(nome_origem.format('(\d+)'))) pat = re.compile('^{}$'.format(nome_origem.format('(\d+)')))
@ -168,11 +174,15 @@ def migrar_docs_por_ids(tipo):
match = pat.match(arq) match = pat.match(arq)
if match: if match:
# associa documento ao objeto # associa documento ao objeto
origem = os.path.join(dir_origem, match.group(0))
id = match.group(1)
try: try:
origem = os.path.join(dir_origem, match.group(0)) obj = model.objects.get(pk=id)
id = match.group(1) except model.DoesNotExist:
obj = tipo.objects.get(pk=id) msg = ' {} (pk={}) não encontrado para documento em [{}]'
print(msg.format(
model.__name__, id, origem))
else:
extensao = get_extensao(origem) extensao = get_extensao(origem)
if hasattr(obj, "ano"): if hasattr(obj, "ano"):
destino = base_destino.format(id, extensao, obj.ano) destino = base_destino.format(id, extensao, obj.ano)
@ -185,19 +195,19 @@ def migrar_docs_por_ids(tipo):
setattr(obj, campo, destino) setattr(obj, campo, destino)
obj.save() obj.save()
except tipo.DoesNotExist:
msg = ' {} (pk={}) não encontrado para documento em [{}]'
print(msg.format(
tipo.__name__, id, destino))
def migrar_documentos(): def migrar_documentos():
# 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á
# apagada # apagada
#
# Isto significa que para rodar novamente esta função é preciso
# restaurar a pasta sapl_documentos ao estado inicial
migrar_docs_logo() migrar_docs_logo()
for tipo in [ for model in [
Parlamentar, Parlamentar,
MateriaLegislativa, MateriaLegislativa,
DocumentoAcessorio, DocumentoAcessorio,
@ -207,7 +217,7 @@ def migrar_documentos():
DocumentoAdministrativo, DocumentoAdministrativo,
DocumentoAcessorioAdministrativo, DocumentoAcessorioAdministrativo,
]: ]:
migrar_docs_por_ids(tipo) migrar_docs_por_ids(model)
sobrando = [os.path.join(dir, file) sobrando = [os.path.join(dir, file)
for (dir, _, files) in os.walk(em_media('sapl_documentos')) for (dir, _, files) in os.walk(em_media('sapl_documentos'))

69
sapl/legacy/migracao_usuarios.py

@ -0,0 +1,69 @@
import yaml
from django.conf import settings
from django.contrib.auth.models import Group, User
def le_yaml_dados_zope(caminho_yaml):
with open(caminho_yaml, 'r') as f:
dados = yaml.load(f.read())
return dados
PERFIL_LEGADO_PARA_NOVO = [
('Autor', 'Autor'),
('Operador', 'Operador Geral'),
('Operador Comissao', 'Operador de Comissões'),
('Operador Materia', 'Operador de Matéria'),
('Operador Modulo Administrativo', 'Operador Administrativo'),
('Operador Norma', 'Operador de Norma Jurídica'),
('Operador Parlamentar', 'Parlamentar'),
('Operador Protocolo', 'Operador de Protocolo Administrativo'),
('Operador Sessao Plenaria', 'Operador de Sessão Plenária'),
]
ADMINISTRADORES = ['Administrador', 'Manager']
VOTANTE = Group.objects.get(name='Votante')
def migra_usuarios(caminho_yaml):
"""
Existe um método em nosso projeto interno de **consulta a todos os sapls**
que exporta os dados de usuários (e nome da casa e url interna)
como um yaml.
Esse yaml é lido por essa rotina e os usuários são criados se necessário
e seus perfis ajustados.
Os seguintes perfis no legado não correspondem a nenhum no código atual
e estão sendo **ignorados**:
* Operador Mesa Diretora
Contei apenas **8 usuários**, em todas as bases, que tem esse perfil
e não tem nem "Operador" nem "Operador Sessao Plenaria"
* Operador Ordem Dia
Contei apenas **16 usuários**, em todas as bases, que tem esse perfil
e não tem nem "Operador" nem "Operador Sessao Plenaria"
* Operador Tabela Auxiliar
A edição das tabelas auxiliares deve ser feita por um administrador
* Operador Lexml
Também podemos assumir que essa é uma tarefa de um administrador
"""
dados = le_yaml_dados_zope(caminho_yaml)
db = settings.DATABASES['legacy']['NAME']
nome, url, usuarios_perfis = dados[db]
for nome, perfis in usuarios_perfis:
usuario, _ = User.objects.get_or_create(username=nome)
for legado, novo in PERFIL_LEGADO_PARA_NOVO:
if legado in perfis:
grupo = Group.objects.get(name=novo)
usuario.groups.add(grupo)
# Manager
if any(a in perfis for a in ADMINISTRADORES):
usuario.is_staff = True
usuario.save()
# Votante
if 'Parlamentar' in perfis:
usuario.groups.add(VOTANTE)

41
sapl/legacy/migration.py

@ -16,8 +16,10 @@ from django.db import connections, transaction
from django.db.models import Count, Max from django.db.models import Count, Max
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from sapl.base.models import AppConfig as AppConf
from sapl.base.models import Autor, ProblemaMigracao, TipoAutor from sapl.base.models import Autor, ProblemaMigracao, TipoAutor
from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.legacy.models import TipoNumeracaoProtocolo
from sapl.materia.models import (AcompanhamentoMateria, Proposicao, from sapl.materia.models import (AcompanhamentoMateria, Proposicao,
StatusTramitacao, TipoDocumento, StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao, TipoMateriaLegislativa, TipoProposicao,
@ -206,6 +208,22 @@ def fill_vinculo_norma_juridica():
TipoVinculoNormaJuridica.objects.bulk_create(lista_objs) TipoVinculoNormaJuridica.objects.bulk_create(lista_objs)
def fill_tipo_numeracao_protocolo():
letra = 'A'
try:
tipo = TipoNumeracaoProtocolo.objects.latest('dat_inicial_protocolo')
if 'POR ANO' in tipo.des_numeracao_protocolo:
letra = 'A'
elif 'POR LEGISLATURA' in tipo.des_numeracao_protocolo:
letra = 'L'
elif 'CONSECUTIVO' in tipo.des_numeracao_protocolo:
letra = 'U'
except Exception as e:
pass
appconf = AppConf(sequencia_numeracao=letra)
appconf.save()
# Uma anomalia no sapl 2.5 causa a duplicação de registros de votação. # 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 # Essa duplicação deve ser eliminada para que não haja erro no sapl 3.1
def excluir_registrovotacao_duplicados(): def excluir_registrovotacao_duplicados():
@ -234,6 +252,21 @@ def excluir_registrovotacao_duplicados():
assert 0 assert 0
def delete_old(legacy_model, cols_values):
def eq_clause(col, value):
if value is None:
return '{} IS NULL'.format(col)
else:
return '{}="{}"'.format(col, value)
delete_sql = 'delete from {} where {}'.format(
legacy_model._meta.db_table,
' and '.join([eq_clause(col, value)
for col, value in cols_values.items()]))
exec_sql(delete_sql, 'legacy')
class DataMigrator: class DataMigrator:
def __init__(self): def __init__(self):
@ -305,6 +338,7 @@ class DataMigrator:
'--database=default', '--no-input'], stdout=PIPE) '--database=default', '--no-input'], stdout=PIPE)
fill_vinculo_norma_juridica() fill_vinculo_norma_juridica()
fill_tipo_numeracao_protocolo()
info('Começando migração: %s...' % obj) info('Começando migração: %s...' % obj)
self._do_migrate(obj) self._do_migrate(obj)
@ -345,6 +379,10 @@ class DataMigrator:
with reversion.create_revision(): with reversion.create_revision():
new.save() new.save()
reversion.set_comment('Objeto criado pela migração') reversion.set_comment('Objeto criado pela migração')
# apaga registro do legado
delete_old(legacy_model, old.__dict__)
old_records = iter_sql_records( old_records = iter_sql_records(
'select * from ' + legacy_model._meta.db_table, 'legacy') 'select * from ' + legacy_model._meta.db_table, 'legacy')
else: else:
@ -355,6 +393,9 @@ class DataMigrator:
new.save() new.save()
reversion.set_comment('Objeto criado pela migração') reversion.set_comment('Objeto criado pela migração')
# apaga registro do legado
delete_old(legacy_model, {legacy_pk_name: new.id})
old_records = legacy_model.objects.all().order_by(legacy_pk_name) old_records = legacy_model.objects.all().order_by(legacy_pk_name)
ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model) ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model)

13
sapl/legacy/models.py

@ -968,6 +968,19 @@ class TipoNormaJuridica(models.Model):
db_table = 'tipo_norma_juridica' db_table = 'tipo_norma_juridica'
class TipoNumeracaoProtocolo(models.Model):
seq_tip_num_protocolo = models.AutoField(primary_key=True)
tip_numeracao_protocolo = models.IntegerField()
des_numeracao_protocolo = models.CharField(max_length=50)
dat_inicial_protocolo = models.DateTimeField()
vlr_inicial_protocolo = models.IntegerField()
ind_excluido = models.IntegerField()
class Meta:
managed = False
db_table = 'tipo_numeracao_protocolo'
class TipoProposicao(models.Model): class TipoProposicao(models.Model):
tip_proposicao = models.AutoField(primary_key=True) tip_proposicao = models.AutoField(primary_key=True)
des_tipo_proposicao = models.CharField(max_length=50) des_tipo_proposicao = models.CharField(max_length=50)

7
sapl/legacy/scripts/migra_dbs.sh

@ -3,9 +3,8 @@
# rodar esse script na raiz do projeto # rodar esse script na raiz do projeto
if [ $# -eq 2 ]; then if [ $# -eq 2 ]; then
parallel -eta --verbose ./sapl/legacy/scripts/migra_um_db.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_' | grep -v '_copy$') ::: $1 ::: $2 parallel -eta --verbose -j+0 ./sapl/legacy/scripts/migra_um_db.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_' | grep -v '_copy$') ::: $1 ::: $2
else else
echo "USO:" echo "USO:"
echo " ./sapl/legacy/scripts/migra_dbs.sh [usuário mysql] [senha mysql]" echo " $0 [usuário mysql] [senha mysql]"
fi; fi;

10
sapl/legacy/scripts/recria_dbs_postgres.sh

@ -1,11 +1,11 @@
#!/bin/bash
# (Re)cria todos os bancos postgres para migração # (Re)cria todos os bancos postgres para migração
# cria um banco postgres (de mesmo nome) para cada banco mysql cujo nome começa com "sapl_" # cria um banco postgres (de mesmo nome) para cada banco mysql cujo nome começa com "sapl_"
if [ $# -eq 2 ]; then if [ $# -eq 2 ]; then
parallel --verbose ./recria_um_db_postgres.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_' | grep -v '_copy$') parallel --verbose -j+0 ./recria_um_db_postgres.sh :::: <(mysql -u $1 -p$2 -e 'show databases;' | grep '^sapl_' | grep -v '_copy$')
else else
echo "USO:" echo "USO:"
echo " ./recria_dbs_postgres.sh [usuário mysql] [senha mysql]" echo " $0 [usuário mysql] [senha mysql]"
fi; fi;

8
sapl/materia/email_utils.py

@ -1,8 +1,9 @@
from datetime import datetime from datetime import datetime as dt
from django.core.mail import EmailMultiAlternatives, get_connection, send_mail from django.core.mail import EmailMultiAlternatives, get_connection, send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template import Context, loader from django.template import Context, loader
from django.utils import timezone
from sapl.base.models import CasaLegislativa from sapl.base.models import CasaLegislativa
from sapl.settings import EMAIL_SEND_USER from sapl.settings import EMAIL_SEND_USER
@ -150,8 +151,9 @@ def criar_email_tramitacao(base_url, casa_legislativa, materia, status,
templates = load_email_templates(['email/tramitacao.txt', templates = load_email_templates(['email/tramitacao.txt',
'email/tramitacao.html'], 'email/tramitacao.html'],
{"casa_legislativa": casa_nome, {"casa_legislativa": casa_nome,
"data_registro": datetime.now().strftime( "data_registro": dt.strftime(
"%d/%m/%Y"), timezone.now(),
"%d/%m/%Y"),
"cod_materia": materia.id, "cod_materia": materia.id,
"logotipo": casa_legislativa.logotipo, "logotipo": casa_legislativa.logotipo,
"descricao_materia": materia.ementa, "descricao_materia": materia.ementa,

32
sapl/materia/forms.py

@ -1,6 +1,5 @@
import os import os
from datetime import date, datetime
import django_filters import django_filters
from crispy_forms.bootstrap import Alert, FormActions, InlineRadios from crispy_forms.bootstrap import Alert, FormActions, InlineRadios
@ -18,6 +17,7 @@ from django.forms import ModelChoiceField, ModelForm, widgets
from django.forms.forms import Form from django.forms.forms import Form
from django.forms.models import ModelMultipleChoiceField from django.forms.models import ModelMultipleChoiceField
from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select
from django.utils import timezone
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -215,7 +215,7 @@ class TramitacaoForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(TramitacaoForm, self).__init__(*args, **kwargs) super(TramitacaoForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = datetime.now().date() self.fields['data_tramitacao'].initial = timezone.now().date()
def clean(self): def clean(self):
cleaned_data = super(TramitacaoForm, self).clean() cleaned_data = super(TramitacaoForm, self).clean()
@ -245,7 +245,7 @@ class TramitacaoForm(ModelForm):
'destino da última adicionada!') 'destino da última adicionada!')
raise ValidationError(msg) raise ValidationError(msg)
if cleaned_data['data_tramitacao'] > datetime.now().date(): if cleaned_data['data_tramitacao'] > timezone.now().date():
msg = _( msg = _(
'A data de tramitação deve ser ' + 'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!') 'menor ou igual a data de hoje!')
@ -1164,10 +1164,10 @@ class ProposicaoForm(forms.ModelForm):
return super().save(commit) return super().save(commit)
inst.ano = datetime.now().year inst.ano = timezone.now().year
numero__max = Proposicao.objects.filter( numero__max = Proposicao.objects.filter(
autor=inst.autor, autor=inst.autor,
ano=datetime.now().year).aggregate(Max('numero_proposicao')) ano=timezone.now().year).aggregate(Max('numero_proposicao'))
numero__max = numero__max['numero_proposicao__max'] numero__max = numero__max['numero_proposicao__max']
inst.numero_proposicao = ( inst.numero_proposicao = (
numero__max + 1) if numero__max else 1 numero__max + 1) if numero__max else 1
@ -1376,7 +1376,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
cd = self.cleaned_data cd = self.cleaned_data
if 'devolver' in self.data: if 'devolver' in self.data:
self.instance.data_devolucao = datetime.now() self.instance.data_devolucao = timezone.now()
self.instance.data_recebimento = None self.instance.data_recebimento = None
self.instance.data_envio = None self.instance.data_envio = None
self.instance.save() self.instance.save()
@ -1398,7 +1398,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
elif 'incorporar' in self.data: elif 'incorporar' in self.data:
self.instance.justificativa_devolucao = '' self.instance.justificativa_devolucao = ''
self.instance.data_devolucao = None self.instance.data_devolucao = None
self.instance.data_recebimento = datetime.now() self.instance.data_recebimento = timezone.now()
self.instance.materia_de_vinculo = cd['materia_de_vinculo'] self.instance.materia_de_vinculo = cd['materia_de_vinculo']
if self.instance.texto_articulado.exists(): if self.instance.texto_articulado.exists():
@ -1435,7 +1435,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
) == TipoMateriaLegislativa: ) == TipoMateriaLegislativa:
numero__max = MateriaLegislativa.objects.filter( numero__max = MateriaLegislativa.objects.filter(
tipo=proposicao.tipo.tipo_conteudo_related, tipo=proposicao.tipo.tipo_conteudo_related,
ano=datetime.now().year).aggregate(Max('numero')) ano=timezone.now().year).aggregate(Max('numero'))
numero__max = numero__max['numero__max'] numero__max = numero__max['numero__max']
# dados básicos # dados básicos
@ -1443,8 +1443,8 @@ class ConfirmarProposicaoForm(ProposicaoForm):
materia.numero = (numero__max + 1) if numero__max else 1 materia.numero = (numero__max + 1) if numero__max else 1
materia.tipo = proposicao.tipo.tipo_conteudo_related materia.tipo = proposicao.tipo.tipo_conteudo_related
materia.ementa = proposicao.descricao materia.ementa = proposicao.descricao
materia.ano = datetime.now().year materia.ano = timezone.now().year
materia.data_apresentacao = datetime.now() materia.data_apresentacao = timezone.now()
materia.em_tramitacao = True materia.em_tramitacao = True
materia.regime_tramitacao = cd['regime_tramitacao'] materia.regime_tramitacao = cd['regime_tramitacao']
@ -1483,7 +1483,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
anexada = Anexada() anexada = Anexada()
anexada.materia_principal = proposicao.materia_de_vinculo anexada.materia_principal = proposicao.materia_de_vinculo
anexada.materia_anexada = materia anexada.materia_anexada = materia
anexada.data_anexacao = datetime.now() anexada.data_anexacao = timezone.now()
anexada.save() anexada.save()
self.instance.results['messages']['success'].append(_( self.instance.results['messages']['success'].append(_(
@ -1555,18 +1555,18 @@ class ConfirmarProposicaoForm(ProposicaoForm):
numeracao = sapl.base.models.AppConfig.attr('sequencia_numeracao') numeracao = sapl.base.models.AppConfig.attr('sequencia_numeracao')
if numeracao == 'A': if numeracao == 'A':
nm = Protocolo.objects.filter( nm = Protocolo.objects.filter(
ano=date.today().year).aggregate(Max('numero')) ano=timezone.now().year).aggregate(Max('numero'))
elif numeracao == 'U': elif numeracao == 'U':
nm = Protocolo.objects.all().aggregate(Max('numero')) nm = Protocolo.objects.all().aggregate(Max('numero'))
protocolo = Protocolo() protocolo = Protocolo()
protocolo.numero = (nm['numero__max'] + 1) if nm['numero__max'] else 1 protocolo.numero = (nm['numero__max'] + 1) if nm['numero__max'] else 1
protocolo.ano = date.today().year protocolo.ano = timezone.now().year
protocolo.data = date.today() protocolo.data = timezone.now()
protocolo.hora = datetime.now().time() protocolo.hora = timezone.now().time()
# TODO transformar campo timestamp em auto_now_add # TODO transformar campo timestamp em auto_now_add
protocolo.timestamp = datetime.now() protocolo.timestamp = timezone.now()
protocolo.tipo_protocolo = '1' protocolo.tipo_protocolo = '1'
protocolo.interessado = str(proposicao.autor) protocolo.interessado = str(proposicao.autor)

5
sapl/materia/models.py

@ -1,4 +1,3 @@
from datetime import datetime
import reversion import reversion
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
@ -6,7 +5,7 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import models from django.db import models
from django.utils import formats from django.utils import formats, timezone
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
@ -711,7 +710,7 @@ class Proposicao(models.Model):
def title_type(self): def title_type(self):
return '%s nº _____ %s' % ( return '%s nº _____ %s' % (
self.tipo, formats.date_format( self.tipo, formats.date_format(
self.data_envio if self.data_envio else datetime.now(), self.data_envio if self.data_envio else timezone.now(),
"\d\e d \d\e F \d\e Y")) "\d\e d \d\e F \d\e Y"))
class Meta: class Meta:

43
sapl/materia/views.py

@ -14,7 +14,7 @@ from django.http import HttpResponse, JsonResponse
from django.http.response import Http404, HttpResponseRedirect from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.template import RequestContext, loader from django.template import RequestContext, loader
from django.utils import formats from django.utils import formats, timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
@ -284,7 +284,7 @@ def recuperar_materia(request):
ano = request.GET.get('ano', '') ano = request.GET.get('ano', '')
param = {'tipo': tipo} param = {'tipo': tipo}
param['data_apresentacao__year'] = ano if ano else datetime.now().year param['data_apresentacao__year'] = ano if ano else timezone.now().year
materia = MateriaLegislativa.objects.filter(**param).order_by( materia = MateriaLegislativa.objects.filter(**param).order_by(
'tipo', 'ano', 'numero').values_list('numero', 'ano').last() 'tipo', 'ano', 'numero').values_list('numero', 'ano').last()
@ -293,7 +293,7 @@ def recuperar_materia(request):
'ano': materia[1]}) 'ano': materia[1]})
else: else:
response = JsonResponse( response = JsonResponse(
{'numero': 1, 'ano': ano if ano else datetime.now().year}) {'numero': 1, 'ano': ano if ano else timezone.now().year})
return response return response
@ -323,14 +323,14 @@ def criar_materia_proposicao(proposicao):
tipo_materia = TipoMateriaLegislativa.objects.get( tipo_materia = TipoMateriaLegislativa.objects.get(
descricao=proposicao.tipo.descricao) descricao=proposicao.tipo.descricao)
numero = MateriaLegislativa.objects.filter( numero = MateriaLegislativa.objects.filter(
ano=datetime.now().year).order_by('numero').last().numero + 1 ano=timezone.now().year).order_by('numero').last().numero + 1
regime = RegimeTramitacao.objects.get(descricao='Normal') regime = RegimeTramitacao.objects.get(descricao='Normal')
return MateriaLegislativa.objects.create( return MateriaLegislativa.objects.create(
tipo=tipo_materia, tipo=tipo_materia,
ano=datetime.now().year, ano=timezone.now().year,
numero=numero, numero=numero,
data_apresentacao=datetime.now(), data_apresentacao=timezone.now(),
regime_tramitacao=regime, regime_tramitacao=regime,
em_tramitacao=True, em_tramitacao=True,
ementa=proposicao.descricao, ementa=proposicao.descricao,
@ -616,7 +616,7 @@ class ProposicaoCrud(Crud):
'Texto associado.') 'Texto associado.')
else: else:
p.data_devolucao = None p.data_devolucao = None
p.data_envio = datetime.now() p.data_envio = timezone.now()
p.save() p.save()
if p.texto_articulado.exists(): if p.texto_articulado.exists():
@ -940,7 +940,7 @@ class TramitacaoCrud(MasterDetailCrud):
] = local.unidade_tramitacao_destino.pk ] = local.unidade_tramitacao_destino.pk
else: else:
self.initial['unidade_tramitacao_local'] = '' self.initial['unidade_tramitacao_local'] = ''
self.initial['data_tramitacao'] = datetime.now() self.initial['data_tramitacao'] = timezone.now()
return self.initial return self.initial
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -1023,7 +1023,11 @@ class TramitacaoCrud(MasterDetailCrud):
url = reverse('sapl.materia:tramitacao_list', url = reverse('sapl.materia:tramitacao_list',
kwargs={'pk': tramitacao.materia.id}) kwargs={'pk': tramitacao.materia.id})
if tramitacao.pk != materia.tramitacao_set.last().pk: ultima_tramitacao = materia.tramitacao_set.order_by(
'-data_tramitacao',
'-id').first()
if tramitacao.pk != ultima_tramitacao.pk:
msg = _('Somente a última tramitação pode ser deletada!') msg = _('Somente a última tramitação pode ser deletada!')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
@ -1067,7 +1071,7 @@ class DocumentoAcessorioCrud(MasterDetailCrud):
super(MasterDetailCrud.CreateView, self).__init__(**kwargs) super(MasterDetailCrud.CreateView, self).__init__(**kwargs)
def get_initial(self): def get_initial(self):
self.initial['data'] = datetime.now().date() self.initial['data'] = timezone.now().date()
return self.initial return self.initial
@ -1629,13 +1633,16 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
tipo = TipoDocumento.objects.get(descricao=request.POST['tipo']) tipo = TipoDocumento.objects.get(descricao=request.POST['tipo'])
tz = timezone.get_current_timezone()
for materia_id in marcadas: for materia_id in marcadas:
doc = DocumentoAcessorio() doc = DocumentoAcessorio()
doc.materia_id = materia_id doc.materia_id = materia_id
doc.tipo = tipo doc.tipo = tipo
doc.arquivo = request.FILES['arquivo'] doc.arquivo = request.FILES['arquivo']
doc.nome = request.POST['nome'] doc.nome = request.POST['nome']
doc.data = datetime.strptime(request.POST['data'], "%d/%m/%Y") doc.data = tz.localize(datetime.strptime(
request.POST['data'], "%d/%m/%Y"))
doc.autor = request.POST['autor'] doc.autor = request.POST['autor']
doc.ementa = request.POST['ementa'] doc.ementa = request.POST['ementa']
doc.save() doc.save()
@ -1692,20 +1699,22 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id') marcadas = request.POST.getlist('materia_id')
tz = timezone.get_current_timezone()
if len(marcadas) == 0: if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.') msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
if request.POST['data_encaminhamento']: if request.POST['data_encaminhamento']:
data_encaminhamento = datetime.strptime( data_encaminhamento = tz.localize(datetime.strptime(
request.POST['data_encaminhamento'], "%d/%m/%Y") request.POST['data_encaminhamento'], "%d/%m/%Y"))
else: else:
data_encaminhamento = None data_encaminhamento = None
if request.POST['data_fim_prazo']: if request.POST['data_fim_prazo']:
data_fim_prazo = datetime.strptime( data_fim_prazo = tz.localize(datetime.strptime(
request.POST['data_fim_prazo'], "%d/%m/%Y") request.POST['data_fim_prazo'], "%d/%m/%Y"))
else: else:
data_fim_prazo = None data_fim_prazo = None
@ -1716,8 +1725,8 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
for materia_id in marcadas: for materia_id in marcadas:
t = Tramitacao( t = Tramitacao(
materia_id=materia_id, materia_id=materia_id,
data_tramitacao=datetime.strptime( data_tramitacao=tz.localize(datetime.strptime(
request.POST['data_tramitacao'], "%d/%m/%Y"), request.POST['data_tramitacao'], "%d/%m/%Y")),
data_encaminhamento=data_encaminhamento, data_encaminhamento=data_encaminhamento,
data_fim_prazo=data_fim_prazo, data_fim_prazo=data_fim_prazo,
unidade_tramitacao_local_id=request.POST[ unidade_tramitacao_local_id=request.POST[

4
sapl/norma/forms.py

@ -1,4 +1,3 @@
from datetime import datetime
import django_filters import django_filters
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
@ -7,6 +6,7 @@ from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models from django.db import models
from django.forms import ModelForm, widgets from django.forms import ModelForm, widgets
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.crispy_layout_mixin import form_actions, to_row from sapl.crispy_layout_mixin import form_actions, to_row
@ -154,7 +154,7 @@ class NormaJuridicaForm(ModelForm):
def save(self, commit=False): def save(self, commit=False):
norma = self.instance norma = self.instance
norma.timestamp = datetime.now() norma.timestamp = timezone.now()
norma.materia = self.cleaned_data['materia'] norma.materia = self.cleaned_data['materia']
norma = super(NormaJuridicaForm, self).save(commit=True) norma = super(NormaJuridicaForm, self).save(commit=True)
return norma return norma

11
sapl/norma/views.py

@ -1,8 +1,8 @@
from datetime import datetime
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import JsonResponse from django.http import JsonResponse
from django.utils import timezone
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
@ -64,6 +64,13 @@ class NormaPesquisaView(FilterView):
filterset_class = NormaFilterSet filterset_class = NormaFilterSet
paginate_by = 10 paginate_by = 10
def get_queryset(self):
qs = super().get_queryset()
qs.select_related('tipo', 'materia')
return qs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(NormaPesquisaView, self).get_context_data(**kwargs) context = super(NormaPesquisaView, self).get_context_data(**kwargs)
@ -197,7 +204,7 @@ def recuperar_numero_norma(request):
ano = request.GET.get('ano', '') ano = request.GET.get('ano', '')
param = {'tipo': tipo} param = {'tipo': tipo}
param['ano'] = ano if ano else datetime.now().year param['ano'] = ano if ano else timezone.now().year
norma = NormaJuridica.objects.filter(**param).order_by( norma = NormaJuridica.objects.filter(**param).order_by(
'tipo', 'ano', 'numero').values_list('numero', 'ano').last() 'tipo', 'ano', 'numero').values_list('numero', 'ano').last()

1
sapl/painel/views.py

@ -1,5 +1,4 @@
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import user_passes_test
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist

6
sapl/parlamentares/forms.py

@ -1,4 +1,4 @@
from datetime import date, timedelta from datetime import timedelta
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Fieldset, Layout from crispy_forms.layout import Fieldset, Layout
@ -9,6 +9,7 @@ from django.core.exceptions import ValidationError
from django.db import transaction from django.db import transaction
from django.db.models import Q from django.db.models import Q
from django.forms import ModelForm from django.forms import ModelForm
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms.widgets import ClearableFileInput from floppyforms.widgets import ClearableFileInput
@ -168,7 +169,8 @@ def validar_datas(data_filiacao, data_desfiliacao, parlamentar, filiacao):
return [True, ''] return [True, '']
# data ficticia de desfiliacao # data ficticia de desfiliacao
df_desfiliacao = data_desfiliacao if data_desfiliacao else date.today() today = timezone.now()
df_desfiliacao = data_desfiliacao if data_desfiliacao else today
# se não puder haver filiação no mesmo dia de desfiliação, basta # se não puder haver filiação no mesmo dia de desfiliação, basta
# retirar os timedelta abaixo # retirar os timedelta abaixo

38
sapl/parlamentares/migrations/0010_corrige_data_inicio_mandato.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
import json
import os
from datetime import timedelta
from django.core.management import call_command
def altera_data_inicio_mandato(apps, schema_editor):
Mandato = apps.get_model("parlamentares", "Mandato")
mandatos = Mandato.objects.all()
for mandato in mandatos:
data_inicio = mandato.data_inicio_mandato
data_inicio_legislatura = mandato.legislatura.data_inicio
days = abs((data_inicio - data_inicio_legislatura).days)
if days >= 60:
mandato.data_inicio_mandato = data_inicio_legislatura
mandato.save()
class Migration(migrations.Migration):
dependencies = [
# A dependencia real desse script é o arquivo 0001_initial.py, mas
# isso gera um erro (Conflicting migrations detected; multiple leaf
# nodes in the migration graph). para não ocasionar problemas de migração,
# vamos manter a ordem padrão do django.
('parlamentares', '0009_auto_20170905_1617'),
]
operations = [
migrations.RunPython(altera_data_inicio_mandato),
]

6
sapl/parlamentares/models.py

@ -1,7 +1,7 @@
from datetime import datetime
import reversion import reversion
from django.db import models from django.db import models
from django.utils import timezone
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
@ -26,7 +26,7 @@ class Legislatura(models.Model):
verbose_name_plural = _('Legislaturas') verbose_name_plural = _('Legislaturas')
def atual(self): def atual(self):
current_year = datetime.now().year current_year = timezone.now().year
return self.data_inicio.year <= current_year <= self.data_fim.year return self.data_inicio.year <= current_year <= self.data_fim.year
@vigencia_atual @vigencia_atual
@ -489,7 +489,7 @@ class Mandato(models.Model):
self.legislatura.data_inicio, self.legislatura.data_inicio,
self.legislatura.data_fim, self.legislatura.data_fim,
f.data, f.data,
f.data_desfiliacao or datetime.max.date())] f.data_desfiliacao or timezone.datetime.max.date())]
@reversion.register() @reversion.register()

13
sapl/parlamentares/views.py

@ -10,6 +10,7 @@ from django.db.models.aggregates import Count
from django.http import JsonResponse from django.http import JsonResponse
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
from django.templatetags.static import static from django.templatetags.static import static
from django.utils import timezone
from django.utils.datastructures import MultiValueDictKeyError from django.utils.datastructures import MultiValueDictKeyError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
@ -226,10 +227,8 @@ def json_date_convert(date):
string "dd/mm/yyyy" string "dd/mm/yyyy"
:return: :return:
''' '''
dia, mes, ano = date.split('/')
return datetime.date(day=int(dia), return datetime.strptime(date, "%d/%m/%Y").date()
month=int(mes),
year=int(ano))
def frente_atualiza_lista_parlamentares(request): def frente_atualiza_lista_parlamentares(request):
@ -660,7 +659,7 @@ class MesaDiretoraView(FormView):
sessoes = SessaoLegislativa.objects.filter( sessoes = SessaoLegislativa.objects.filter(
legislatura=legislatura).order_by("data_inicio") legislatura=legislatura).order_by("data_inicio")
year = datetime.now().year year = timezone.now().year
sessao_atual = sessoes.filter(data_inicio__year=year).first() sessao_atual = sessoes.filter(data_inicio__year=year).first()
mesa = sessao_atual.composicaomesa_set.all() if sessao_atual else [] mesa = sessao_atual.composicaomesa_set.all() if sessao_atual else []
@ -715,7 +714,7 @@ def altera_field_mesa(request):
# Caso a mudança tenha sido no campo legislatura, a sessão # Caso a mudança tenha sido no campo legislatura, a sessão
# atual deve ser a primeira daquela legislatura # atual deve ser a primeira daquela legislatura
else: else:
year = datetime.now().year year = timezone.now().year
try: try:
sessao_selecionada = sessoes.get(data_inicio__year=year).id sessao_selecionada = sessoes.get(data_inicio__year=year).id
except ObjectDoesNotExist: except ObjectDoesNotExist:
@ -883,7 +882,7 @@ def altera_field_mesa_public_view(request):
# atual deve ser a primeira daquela legislatura # atual deve ser a primeira daquela legislatura
else: else:
try: try:
year = datetime.now().year year = timezone.now().year
sessao_selecionada = sessoes.get(data_inicio__year=year).id sessao_selecionada = sessoes.get(data_inicio__year=year).id
except ObjectDoesNotExist as e: except ObjectDoesNotExist as e:
sessao_selecionada = sessoes.first().id sessao_selecionada = sessoes.first().id

62
sapl/protocoloadm/forms.py

@ -1,4 +1,3 @@
from datetime import datetime
import django_filters import django_filters
from crispy_forms.bootstrap import InlineRadios from crispy_forms.bootstrap import InlineRadios
@ -8,6 +7,7 @@ from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models from django.db import models
from django.forms import ModelForm from django.forms import ModelForm
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
@ -441,28 +441,26 @@ class TramitacaoAdmForm(ModelForm):
'texto', 'texto',
] ]
widgets = {
'data_tramitacao': forms.DateInput(format='%d/%m/%Y'),
'data_encaminhamento': forms.DateInput(format='%d/%m/%Y'),
'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'),
}
def clean(self): def clean(self):
super(TramitacaoAdmForm, self).clean() cleaned_data = super(TramitacaoAdmForm, self).clean()
data_enc_form = self.cleaned_data['data_encaminhamento'] if 'data_encaminhamento' in cleaned_data:
data_prazo_form = self.cleaned_data['data_fim_prazo'] data_enc_form = cleaned_data['data_encaminhamento']
data_tram_form = self.cleaned_data['data_tramitacao'] if 'data_fim_prazo' in cleaned_data:
data_prazo_form = cleaned_data['data_fim_prazo']
if 'data_tramitacao' in cleaned_data:
data_tram_form = cleaned_data['data_tramitacao']
if self.errors: if not self.is_valid():
return self.errors return cleaned_data
ultima_tramitacao = TramitacaoAdministrativo.objects.filter( ultima_tramitacao = TramitacaoAdministrativo.objects.filter(
documento_id=self.instance.documento_id).exclude( documento_id=self.instance.documento_id).exclude(
id=self.instance.id).last() id=self.instance.id).order_by(
'-data_tramitacao',
'-id').first()
if not self.instance.data_tramitacao: if not self.instance.data_tramitacao:
if ultima_tramitacao: if ultima_tramitacao:
destino = ultima_tramitacao.unidade_tramitacao_destino destino = ultima_tramitacao.unidade_tramitacao_destino
if (destino != self.cleaned_data['unidade_tramitacao_local']): if (destino != self.cleaned_data['unidade_tramitacao_local']):
@ -470,7 +468,7 @@ class TramitacaoAdmForm(ModelForm):
'destino da última adicionada!') 'destino da última adicionada!')
raise ValidationError(msg) raise ValidationError(msg)
if self.cleaned_data['data_tramitacao'] > datetime.now().date(): if self.cleaned_data['data_tramitacao'] > timezone.now().date():
msg = _( msg = _(
'A data de tramitação deve ser ' + 'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!') 'menor ou igual a data de hoje!')
@ -516,25 +514,33 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
'texto', 'texto',
] ]
widgets = {
'data_encaminhamento': forms.DateInput(format='%d/%m/%Y'),
'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'),
}
def clean(self): def clean(self):
super(TramitacaoAdmEditForm, self).clean() ultima_tramitacao = TramitacaoAdministrativo.objects.filter(
documento_id=self.instance.documento_id).order_by(
local = self.instance.unidade_tramitacao_local '-data_tramitacao',
data_tram = self.instance.data_tramitacao '-id').first()
# Se a Tramitação que está sendo editada não for a mais recente,
# ela não pode ter seu destino alterado.
if ultima_tramitacao != self.instance:
if self.cleaned_data['unidade_tramitacao_destino'] != \
self.instance.unidade_tramitacao_destino:
raise ValidationError(
'Você não pode mudar a Unidade de Destino desta '
'tramitação, pois irá conflitar com a Unidade '
'Local da tramitação seguinte')
self.cleaned_data['data_tramitacao'] = \
self.instance.data_tramitacao
self.cleaned_data['unidade_tramitacao_local'] = \
self.instance.unidade_tramitacao_local
self.cleaned_data['data_tramitacao'] = data_tram
self.cleaned_data['unidade_tramitacao_local'] = local
return super(TramitacaoAdmEditForm, self).clean() return super(TramitacaoAdmEditForm, self).clean()
class DocumentoAdministrativoForm(ModelForm): class DocumentoAdministrativoForm(ModelForm):
data = forms.DateField(initial=datetime.today) data = forms.DateField(initial=timezone.now)
ano_protocolo = forms.ChoiceField(required=False, ano_protocolo = forms.ChoiceField(required=False,
label=Protocolo._meta. label=Protocolo._meta.

22
sapl/protocoloadm/tests/test_protocoloadm.py

@ -1,4 +1,4 @@
import datetime from datetime import date, timedelta
import pytest import pytest
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@ -145,7 +145,7 @@ def test_create_tramitacao(admin_client):
unidade_tramitacao_destino=unidade_tramitacao_destino_1, unidade_tramitacao_destino=unidade_tramitacao_destino_1,
status=status, status=status,
documento=documento_adm, documento=documento_adm,
data_tramitacao=datetime.date(2016, 8, 21)) data_tramitacao=date(2016, 8, 21))
response = admin_client.post( response = admin_client.post(
reverse( reverse(
@ -155,7 +155,7 @@ def test_create_tramitacao(admin_client):
'unidade_tramitacao_destino': unidade_tramitacao_local_1.pk, 'unidade_tramitacao_destino': unidade_tramitacao_local_1.pk,
'documento': documento_adm.pk, 'documento': documento_adm.pk,
'status': status.pk, 'status': status.pk,
'data_tramitacao': datetime.date(2016, 8, 21)}, 'data_tramitacao': date(2016, 8, 21)},
follow=True) follow=True)
msg = force_text(_('A origem da nova tramitação deve ser igual ao ' msg = force_text(_('A origem da nova tramitação deve ser igual ao '
@ -173,7 +173,7 @@ def test_create_tramitacao(admin_client):
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk, 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk,
'documento': documento_adm.pk, 'documento': documento_adm.pk,
'status': status.pk, 'status': status.pk,
'data_tramitacao': datetime.date(2016, 8, 20)}, 'data_tramitacao': date(2016, 8, 20)},
follow=True) follow=True)
msg = _('A data da nova tramitação deve ser ' + msg = _('A data da nova tramitação deve ser ' +
@ -191,7 +191,7 @@ def test_create_tramitacao(admin_client):
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk, 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk,
'documento': documento_adm.pk, 'documento': documento_adm.pk,
'status': status.pk, 'status': status.pk,
'data_tramitacao': datetime.date.today() + datetime.timedelta( 'data_tramitacao': date.today() + timedelta(
days=1)}, days=1)},
follow=True) follow=True)
@ -210,8 +210,8 @@ def test_create_tramitacao(admin_client):
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk, 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk,
'documento': documento_adm.pk, 'documento': documento_adm.pk,
'status': status.pk, 'status': status.pk,
'data_tramitacao': datetime.date(2016, 8, 21), 'data_tramitacao': date(2016, 8, 21),
'data_encaminhamento': datetime.date(2016, 8, 20)}, 'data_encaminhamento': date(2016, 8, 20)},
follow=True) follow=True)
msg = force_text(_('A data de encaminhamento deve ser ' + msg = force_text(_('A data de encaminhamento deve ser ' +
@ -229,8 +229,8 @@ def test_create_tramitacao(admin_client):
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk, 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk,
'documento': documento_adm.pk, 'documento': documento_adm.pk,
'status': status.pk, 'status': status.pk,
'data_tramitacao': datetime.date(2016, 8, 21), 'data_tramitacao': date(2016, 8, 21),
'data_fim_prazo': datetime.date(2016, 8, 20)}, 'data_fim_prazo': date(2016, 8, 20)},
follow=True) follow=True)
msg = _('A data fim de prazo deve ser ' + msg = _('A data fim de prazo deve ser ' +
@ -248,12 +248,12 @@ def test_create_tramitacao(admin_client):
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk, 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.pk,
'documento': documento_adm.pk, 'documento': documento_adm.pk,
'status': status.pk, 'status': status.pk,
'data_tramitacao': datetime.date(2016, 8, 21)}, 'data_tramitacao': date(2016, 8, 21)},
follow=True) follow=True)
tramitacao = TramitacaoAdministrativo.objects.last() tramitacao = TramitacaoAdministrativo.objects.last()
# Verifica se a tramitacao que obedece as regras de negócios é criada # Verifica se a tramitacao que obedece as regras de negócios é criada
assert tramitacao.data_tramitacao == datetime.date(2016, 8, 21) assert tramitacao.data_tramitacao == date(2016, 8, 21)
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)

83
sapl/protocoloadm/views.py

@ -1,4 +1,3 @@
from datetime import date, datetime
from braces.views import FormValidMessageMixin from braces.views import FormValidMessageMixin
from django.contrib import messages from django.contrib import messages
@ -8,7 +7,9 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import Max, Q from django.db.models import Max, Q
from django.http import Http404, HttpResponse, JsonResponse from django.http import Http404, HttpResponse, JsonResponse
from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView from django.views.generic import CreateView, ListView
from django.views.generic.base import RedirectView, TemplateView from django.views.generic.base import RedirectView, TemplateView
@ -295,7 +296,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
if numeracao == 'A': if numeracao == 'A':
numero = Protocolo.objects.filter( numero = Protocolo.objects.filter(
ano=date.today().year).aggregate(Max('numero')) ano=timezone.now().year).aggregate(Max('numero'))
elif numeracao == 'L': elif numeracao == 'L':
legislatura = Legislatura.objects.last() legislatura = Legislatura.objects.last()
data_inicio = legislatura.data_inicio data_inicio = legislatura.data_inicio
@ -309,10 +310,10 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
f.tipo_processo = '0' # TODO validar o significado f.tipo_processo = '0' # TODO validar o significado
f.anulado = False f.anulado = False
f.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 f.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1
f.ano = datetime.now().year f.ano = timezone.now().year
f.data = datetime.now().date() f.data = timezone.now()
f.hora = datetime.now().time() f.hora = timezone.now().time()
f.timestamp = datetime.now() f.timestamp = timezone.now()
f.assunto_ementa = self.request.POST['assunto'] f.assunto_ementa = self.request.POST['assunto']
f.save() f.save()
@ -334,7 +335,7 @@ class CriarDocumentoProtocolo(PermissionRequiredMixin, CreateView):
kwargs={'pk': self.kwargs['pk']}) kwargs={'pk': self.kwargs['pk']})
def criar_documento(self, protocolo): def criar_documento(self, protocolo):
curr_year = datetime.now().date().year curr_year = timezone.now().year
numero_max = DocumentoAdministrativo.objects.filter( numero_max = DocumentoAdministrativo.objects.filter(
tipo=protocolo.tipo_documento, ano=curr_year tipo=protocolo.tipo_documento, ano=curr_year
@ -343,7 +344,7 @@ class CriarDocumentoProtocolo(PermissionRequiredMixin, CreateView):
doc = {} doc = {}
doc['tipo'] = protocolo.tipo_documento doc['tipo'] = protocolo.tipo_documento
doc['ano'] = curr_year doc['ano'] = curr_year
doc['data'] = datetime.today() doc['data'] = timezone.now()
doc['numero_protocolo'] = protocolo.numero doc['numero_protocolo'] = protocolo.numero
doc['ano_protocolo'] = protocolo.ano doc['ano_protocolo'] = protocolo.ano
doc['protocolo'] = protocolo.id doc['protocolo'] = protocolo.id
@ -430,7 +431,7 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
if numeracao == 'A': if numeracao == 'A':
numero = Protocolo.objects.filter( numero = Protocolo.objects.filter(
ano=date.today().year).aggregate(Max('numero')) ano=timezone.now().year).aggregate(Max('numero'))
elif numeracao == 'U': elif numeracao == 'U':
numero = Protocolo.objects.all().aggregate(Max('numero')) numero = Protocolo.objects.all().aggregate(Max('numero'))
@ -441,10 +442,10 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo.numero = ( protocolo.numero = (
numero['numero__max'] + 1) if numero['numero__max'] else 1 numero['numero__max'] + 1) if numero['numero__max'] else 1
protocolo.ano = datetime.now().year protocolo.ano = timezone.now().year
protocolo.data = datetime.now().date() protocolo.data = timezone.now().date()
protocolo.hora = datetime.now().time() protocolo.hora = timezone.now().time()
protocolo.timestamp = datetime.now() protocolo.timestamp = timezone.now()
protocolo.tipo_protocolo = 0 protocolo.tipo_protocolo = 0
protocolo.tipo_processo = '1' # TODO validar o significado protocolo.tipo_processo = '1' # TODO validar o significado
@ -482,7 +483,7 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
lista_comissoes = Comissao.objects.filter(Q( lista_comissoes = Comissao.objects.filter(Q(
data_extincao__isnull=True) | Q( data_extincao__isnull=True) | Q(
data_extincao__gt=date.today())).values_list('id', flat=True) data_extincao__gt=timezone.now())).values_list('id', flat=True)
model_comissao = ContentType.objects.get_for_model(Comissao) model_comissao = ContentType.objects.get_for_model(Comissao)
autor_comissoes = Autor.objects.filter( autor_comissoes = Autor.objects.filter(
content_type=model_comissao, object_id__in=lista_comissoes) content_type=model_comissao, object_id__in=lista_comissoes)
@ -585,6 +586,33 @@ class TramitacaoAdmCrud(MasterDetailCrud):
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
form_class = TramitacaoAdmForm form_class = TramitacaoAdmForm
def get_initial(self):
local = DocumentoAdministrativo.objects.get(
pk=self.kwargs['pk']).tramitacaoadministrativo_set.order_by(
'-data_tramitacao',
'-id').first()
if local:
self.initial['unidade_tramitacao_local'
] = local.unidade_tramitacao_destino.pk
else:
self.initial['unidade_tramitacao_local'] = ''
self.initial['data_tramitacao'] = timezone.now().date()
return self.initial
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
primeira_tramitacao = not(TramitacaoAdministrativo.objects.filter(
documento_id=int(kwargs['root_pk'])).exists())
# Se não for a primeira tramitação daquela matéria, o campo
# não pode ser modificado
if not primeira_tramitacao:
context['form'].fields[
'unidade_tramitacao_local'].widget.attrs['disabled'] = True
return context
class UpdateView(MasterDetailCrud.UpdateView): class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm form_class = TramitacaoAdmEditForm
@ -593,12 +621,37 @@ class TramitacaoAdmCrud(MasterDetailCrud):
def get_queryset(self): def get_queryset(self):
qs = super(MasterDetailCrud.ListView, self).get_queryset() qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']} kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao', '-id') return qs.filter(**kwargs).order_by('-data_tramitacao',
'-id')
class DetailView(DocumentoAdministrativoMixin, class DetailView(DocumentoAdministrativoMixin,
MasterDetailCrud.DetailView): MasterDetailCrud.DetailView):
pass pass
class DeleteView(MasterDetailCrud.DeleteView):
def delete(self, request, *args, **kwargs):
tramitacao = TramitacaoAdministrativo.objects.get(
id=self.kwargs['pk'])
documento = DocumentoAdministrativo.objects.get(
id=tramitacao.documento.id)
url = reverse(
'sapl.protocoloadm:tramitacaoadministrativo_list',
kwargs={'pk': tramitacao.documento.id})
ultima_tramitacao = \
documento.tramitacaoadministrativo_set.order_by(
'-data_tramitacao',
'-id').first()
if tramitacao.pk != ultima_tramitacao.pk:
msg = _('Somente a última tramitação pode ser deletada!')
messages.add_message(request, messages.ERROR, msg)
return HttpResponseRedirect(url)
else:
tramitacao.delete()
return HttpResponseRedirect(url)
class DocumentoAcessorioAdministrativoCrud(MasterDetailCrud): class DocumentoAcessorioAdministrativoCrud(MasterDetailCrud):
model = DocumentoAcessorioAdministrativo model = DocumentoAcessorioAdministrativo

10
sapl/relatorios/views.py

@ -1,9 +1,10 @@
import html import html
import re import re
from datetime import datetime from datetime import datetime as dt
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
@ -88,7 +89,7 @@ def get_rodape(casa):
linha2 = linha2 + " - " linha2 = linha2 + " - "
linha2 = linha2 + str(_("E-mail: ")) + casa.email linha2 = linha2 + str(_("E-mail: ")) + casa.email
data_emissao = datetime.today().strftime("%d/%m/%Y") data_emissao = dt.strftime(timezone.now(), "%d/%m/%Y")
return [linha1, linha2, data_emissao] return [linha1, linha2, data_emissao]
@ -932,8 +933,11 @@ def get_etiqueta_protocolos(prots):
dic = {} dic = {}
dic['titulo'] = str(p.numero) + '/' + str(p.ano) dic['titulo'] = str(p.numero) + '/' + str(p.ano)
tz_hora = timezone.localtime(p.timestamp)
dic['data'] = '<b>Data: </b>' + p.data.strftime( dic['data'] = '<b>Data: </b>' + p.data.strftime(
"%d/%m/%Y") + ' - <b>Horário: </b>' + p.hora.strftime("%H:%M") "%d/%m/%Y") + ' - <b>Horário: </b>' + tz_hora.strftime("%H:%M")
dic['txt_assunto'] = p.assunto_ementa dic['txt_assunto'] = p.assunto_ementa
dic['txt_interessado'] = p.interessado dic['txt_interessado'] = p.interessado

4
sapl/sessao/forms.py

@ -15,7 +15,7 @@ from sapl.materia.models import (MateriaLegislativa, StatusTramitacao,
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
MateriaPesquisaOrderingFilter, autor_label, MateriaPesquisaOrderingFilter, autor_label,
autor_modal) autor_modal, timezone)
from .models import (Bancada, ExpedienteMateria, Orador, OradorExpediente, from .models import (Bancada, ExpedienteMateria, Orador, OradorExpediente,
OrdemDia, SessaoPlenaria, SessaoPlenariaPresenca) OrdemDia, SessaoPlenaria, SessaoPlenariaPresenca)
@ -132,7 +132,7 @@ class ExpedienteMateriaForm(ModelForm):
data_ordem = forms.CharField( data_ordem = forms.CharField(
label='Data Sessão', label='Data Sessão',
initial=datetime.now().strftime('%d/%m/%Y'), initial=datetime.strftime(timezone.now(), '%d/%m/%Y'),
widget=forms.TextInput(attrs={'readonly': 'readonly'})) widget=forms.TextInput(attrs={'readonly': 'readonly'}))
class Meta: class Meta:

9
sapl/sessao/views.py

@ -1,4 +1,3 @@
from datetime import datetime
from re import sub from re import sub
from django.contrib import messages from django.contrib import messages
@ -10,6 +9,7 @@ from django.db.models import Max, Q
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
from django.http import JsonResponse from django.http import JsonResponse
from django.http.response import Http404, HttpResponseRedirect from django.http.response import Http404, HttpResponseRedirect
from django.utils import timezone
from django.utils.datastructures import MultiValueDictKeyError from django.utils.datastructures import MultiValueDictKeyError
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.html import strip_tags from django.utils.html import strip_tags
@ -2429,7 +2429,8 @@ class PesquisarSessaoPlenariaView(FilterView):
kwargs = {'data': self.request.GET or None} kwargs = {'data': self.request.GET or None}
qs = self.get_queryset() qs = self.get_queryset().select_related(
'tipo', 'sessao_legislativa', 'legislatura')
qs = qs.distinct().order_by( qs = qs.distinct().order_by(
'-legislatura__numero', '-data_inicio', '-numero') '-legislatura__numero', '-data_inicio', '-numero')
@ -2575,7 +2576,7 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
expediente.numero_ordem = posicao expediente.numero_ordem = posicao
else: else:
expediente.numero_ordem = 1 expediente.numero_ordem = 1
expediente.data_ordem = datetime.now() expediente.data_ordem = timezone.now()
expediente.tipo_votacao = request.POST['tipo_votacao_%s' % m] expediente.tipo_votacao = request.POST['tipo_votacao_%s' % m]
expediente.save() expediente.save()
@ -2644,7 +2645,7 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
ordem_dia.numero_ordem = posicao ordem_dia.numero_ordem = posicao
else: else:
ordem_dia.numero_ordem = 1 ordem_dia.numero_ordem = 1
ordem_dia.data_ordem = datetime.now() ordem_dia.data_ordem = timezone.now()
ordem_dia.tipo_votacao = tipo_votacao ordem_dia.tipo_votacao = tipo_votacao
ordem_dia.save() ordem_dia.save()

2
sapl/settings.py

@ -209,7 +209,7 @@ LANGUAGES = (
TIME_ZONE = 'America/Sao_Paulo' TIME_ZONE = 'America/Sao_Paulo'
USE_I18N = True USE_I18N = True
USE_L10N = True USE_L10N = True
USE_TZ = False USE_TZ = True
# DATE_FORMAT = 'N j, Y' # DATE_FORMAT = 'N j, Y'
DATE_FORMAT = 'd/m/Y' DATE_FORMAT = 'd/m/Y'
SHORT_DATE_FORMAT = 'd/m/Y' SHORT_DATE_FORMAT = 'd/m/Y'

4
sapl/templates/materia/prop_devolvidas_list.html

@ -1,6 +1,6 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load tz %}
{% block base_content %} {% block base_content %}
<fieldset> <fieldset>
<legend>Proposições Não Incorporadas</legend> <legend>Proposições Não Incorporadas</legend>
@ -20,7 +20,7 @@
<tbody> <tbody>
{% for prop in object_list %} {% for prop in object_list %}
<tr> <tr>
<td><a href="{% url 'sapl.materia:proposicao_detail' prop.pk %}">{{ prop.data_devolucao|date:"d/m/Y H:i:s" }}</a></td> <td><a href="{% url 'sapl.materia:proposicao_detail' prop.pk %}">{{ prop.data_devolucao|localtime|date:"d/m/Y H:i:s" }}</a></td>
<td>{{ prop.tipo.descricao }}</td> <td>{{ prop.tipo.descricao }}</td>
<td>{{ prop.descricao }}</td> <td>{{ prop.descricao }}</td>
<td>{{ prop.autor }}</td> <td>{{ prop.autor }}</td>

3
sapl/templates/materia/prop_pendentes_list.html

@ -1,5 +1,6 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load tz %}
{% block base_content %} {% block base_content %}
<fieldset> <fieldset>
<legend>Proposições Não Recebidas</legend> <legend>Proposições Não Recebidas</legend>
@ -18,7 +19,7 @@
<tbody> <tbody>
{% for prop in object_list %} {% for prop in object_list %}
<tr> <tr>
<td><a href="{% url 'sapl.materia:proposicao_detail' prop.pk %}">{{ prop.data_envio|date:"d/m/Y H:i:s" }}</a></td> <td><a href="{% url 'sapl.materia:proposicao_detail' prop.pk %}">{{ prop.data_envio|localtime|date:"d/m/Y H:i:s" }}</a></td>
<td>{{ prop.tipo.descricao }}</td> <td>{{ prop.tipo.descricao }}</td>
<td>{{ prop.descricao }}</td> <td>{{ prop.descricao }}</td>
<td>{{ prop.autor }}</td> <td>{{ prop.autor }}</td>

3
sapl/templates/materia/prop_recebidas_list.html

@ -1,5 +1,6 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% load tz %}
{% block base_content %} {% block base_content %}
<fieldset> <fieldset>
<legend>Proposições Incorporadas</legend> <legend>Proposições Incorporadas</legend>
@ -19,7 +20,7 @@
<tbody> <tbody>
{% for prop in object_list %} {% for prop in object_list %}
<tr> <tr>
<td><a href="{% url 'sapl.materia:proposicao_detail' prop.pk %}">{{ prop.data_recebimento|date:"d/m/Y H:i:s" }}</a></td> <td><a href="{% url 'sapl.materia:proposicao_detail' prop.pk %}">{{ prop.data_recebimento|localtime|date:"d/m/Y H:i:s" }}</a></td>
<td>{{ prop.tipo.descricao }}</td> <td>{{ prop.tipo.descricao }}</td>
<td>{{ prop.descricao }}</td> <td>{{ prop.descricao }}</td>
<td>{{ prop.autor }}</td> <td>{{ prop.autor }}</td>

4
sapl/templates/materia/proposicao_detail.html

@ -1,6 +1,6 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n common_tags %} {% load i18n common_tags %}
{% load tz %}
{% block sub_actions %}{{block.super}} {% block sub_actions %}{{block.super}}
<div class="actions btn-group btn-group-sm {%block sub_actions_pull%}{% endblock%}" role="group"> <div class="actions btn-group btn-group-sm {%block sub_actions_pull%}{% endblock%}" role="group">
{% if object.texto_articulado.exists %} {% if object.texto_articulado.exists %}
@ -62,7 +62,7 @@
<div class="col-sm-9"> <div class="col-sm-9">
<div class="alert alert-danger alert-dismissible fade in" role="alert"> <div class="alert alert-danger alert-dismissible fade in" role="alert">
<strong>{% trans "Proposição devolvida em:" %} {{ object.data_devolucao|date:"DATETIME_FORMAT"}}</strong> <strong>{% trans "Proposição devolvida em:" %} {{ object.data_devolucao|localtime|date:"DATETIME_FORMAT"}}</strong>
<div >{% trans "Justificativa:" %} {{object.justificativa_devolucao}}</div> <div >{% trans "Justificativa:" %} {{object.justificativa_devolucao}}</div>
</div> </div>
</div> </div>

3
sapl/templates/materia/recibo_proposicao.html

@ -1,4 +1,5 @@
{% load i18n %} {% load i18n %}
{% load tz %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load static %} {% load static %}
@ -49,7 +50,7 @@
</tr> </tr>
<tr> <tr>
<td>Autor: <b>{{proposicao.autor}}</b></td> <td>Autor: <b>{{proposicao.autor}}</b></td>
<td>Data de Envio: <b>{{proposicao.data_envio|date:"d/m/Y H:i:s"}}</b></td> <td>Data de Envio: <b>{{proposicao.data_envio|localtime|date:"d/m/Y H:i:s"}}</b></td>
</tr> </tr>
<tr> <tr>
<td>Descrição: <b>{{proposicao.descricao}}</b></td> <td>Descrição: <b>{{proposicao.descricao}}</b></td>

2
sapl/templates/protocoloadm/protocolo_filter.html

@ -1,5 +1,6 @@
{% extends "protocoloadm/protocoloadm_detail.html" %} {% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %} {% load i18n %}
{% load tz %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load static %} {% load static %}
@ -44,6 +45,7 @@
</br> </br>
<strong>Assunto:</strong> {{ p.assunto_ementa|default_if_none:"Não informado"}}</br> <strong>Assunto:</strong> {{ p.assunto_ementa|default_if_none:"Não informado"}}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.hora|date:"G:i:s" }}</br> <strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.hora|date:"G:i:s" }}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y"|default_if_none:"Não informado" }} - Horário: {{ p.timestamp|localtime|date:"G:i:s" }}</br>
{% if p.tipo_processo == 0 %} {% if p.tipo_processo == 0 %}
<strong>Interessado:</strong> {{ p.interessado|default_if_none:"Não informado" }}</br> <strong>Interessado:</strong> {{ p.interessado|default_if_none:"Não informado" }}</br>

4
sapl/templates/protocoloadm/protocolo_list.html

@ -1,8 +1,8 @@
{% extends "protocoloadm/protocoloadm_detail.html" %} {% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %} {% load i18n %}
{% load tz %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load static %} {% load static %}
{% block detail_content %} {% block detail_content %}
{% if protocolos %} {% if protocolos %}
<table> <table>
@ -20,7 +20,7 @@
<img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual"> <img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual">
</a></br> </a></br>
<strong>Assunto:</strong> {{ p.assunto_ementa }}</br> <strong>Assunto:</strong> {{ p.assunto_ementa }}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y" }} - Horário: {{ p.hora|date:"H:m:s" }}</br> <strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y" }} - Horário: {{ p.timestamp|localtime|date:"H:m:s" }}</br>
<strong>Natureza do Processo:</strong> <strong>Natureza do Processo:</strong>
{% if p.tipo_processo == 0 %} {% if p.tipo_processo == 0 %}
Administrativo </br> Administrativo </br>

3
sapl/templates/protocoloadm/protocolo_mostrar.html

@ -1,11 +1,12 @@
{% extends "protocoloadm/protocoloadm_detail.html" %} {% extends "protocoloadm/protocoloadm_detail.html" %}
{% load i18n %} {% load i18n %}
{% load tz %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block detail_content %} {% block detail_content %}
<strong>Protocolo: </strong>{{ protocolo.numero|stringformat:'06d' }}/{{ protocolo.ano }}</br> <strong>Protocolo: </strong>{{ protocolo.numero|stringformat:'06d' }}/{{ protocolo.ano }}</br>
<strong>Assunto: </strong> {{ protocolo.assunto_ementa|default:"Não informado" }}</br> <strong>Assunto: </strong> {{ protocolo.assunto_ementa|default:"Não informado" }}</br>
<strong>Data Protocolo: </strong> {{ protocolo.data|date:"d/m/Y" }} - Horário: {{ protocolo.hora|date:"H:i" }}</br> <strong>Data Protocolo: </strong> {{ protocolo.data|date:"d/m/Y" }} - Horário: {{ protocolo.timestamp|localtime|date:"H:i" }}</br>
{% if protocolo.tipo_processo == 0 %} {% if protocolo.tipo_processo == 0 %}
<strong>Interessado:</strong> {{ protocolo.interessado|default_if_none:"Não informado" }}</br> <strong>Interessado:</strong> {{ protocolo.interessado|default_if_none:"Não informado" }}</br>

12
sapl/templates/protocoloadm/tramitacaoadministrativo_form.html

@ -0,0 +1,12 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% block extra_js %}
<script language="Javascript">
// Caso o campo esteja desabilitado (quando não é a primeira tramitação),
// habilita ele no momento do submit para que o valor de unidade local
// não seja enviado como vazio
$('form').submit(function(){
$('#id_unidade_tramitacao_local').prop('disabled', false);
});
</script>
{% endblock extra_js %}

6
sapl/utils.py

@ -2,7 +2,6 @@ import hashlib
import logging import logging
import os import os
import re import re
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
@ -18,7 +17,7 @@ from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRel,
GenericRelation) GenericRelation)
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Q from django.db.models import Q
from django.utils import six from django.utils import six, timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_filters.filterset import STRICTNESS from django_filters.filterset import STRICTNESS
from floppyforms import ClearableFileInput from floppyforms import ClearableFileInput
@ -303,7 +302,8 @@ UF = [
('EX', 'Exterior'), ('EX', 'Exterior'),
] ]
RANGE_ANOS = [(year, year) for year in range(date.today().year, 1889, -1)] RANGE_ANOS = [(year, year) for year in range(timezone.now().year,
1889, -1)]
RANGE_MESES = [ RANGE_MESES = [
(1, 'Janeiro'), (1, 'Janeiro'),

Loading…
Cancel
Save