Browse Source

Merge branch '3.1.x' into 3194_colocando_campo_observacao_junto_de_ementa_em_sessao_plenaria

pull/3198/head
Edward 5 years ago
committed by GitHub
parent
commit
070f5db04e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .travis.yml
  2. 2
      docker-compose-dev.yml
  3. 2
      docker-compose.yml
  4. 38
      docs/howtogit.rst
  5. 1
      requirements/requirements.txt
  6. 2
      sapl/api/serializers.py
  7. 16
      sapl/audiencia/forms.py
  8. 168
      sapl/base/forms.py
  9. 24
      sapl/base/models.py
  10. 4
      sapl/base/urls.py
  11. 105
      sapl/base/views.py
  12. 106
      sapl/comissoes/forms.py
  13. 10
      sapl/crud/base.py
  14. 38
      sapl/materia/forms.py
  15. 23
      sapl/materia/migrations/0068_configetiquetamaterialegislativa.py
  16. 20
      sapl/materia/migrations/0069_auto_20200518_1519.py
  17. 8
      sapl/materia/models.py
  18. 4
      sapl/materia/urls.py
  19. 247
      sapl/materia/views.py
  20. 2
      sapl/norma/forms.py
  21. 8
      sapl/norma/views.py
  22. 11
      sapl/parlamentares/forms.py
  23. 3
      sapl/parlamentares/views.py
  24. 21
      sapl/protocoloadm/migrations/0033_auto_20200708_1312.py
  25. 61
      sapl/protocoloadm/models.py
  26. 4
      sapl/protocoloadm/views.py
  27. 8
      sapl/relatorios/urls.py
  28. 59
      sapl/relatorios/views.py
  29. 1
      sapl/rules/map_rules.py
  30. 158
      sapl/sessao/views.py
  31. 2
      sapl/settings.py
  32. 3
      sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js
  33. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.LICENSE.txt.gz
  34. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.gz
  35. 1
      sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.map
  36. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.map.gz
  37. 3
      sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js
  38. 4
      sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.LICENSE.txt
  39. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.LICENSE.txt.gz
  40. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.gz
  41. 1
      sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.map
  42. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.map.gz
  43. 4
      sapl/static/sapl/frontend/js/parlamentar.307451cf.js
  44. BIN
      sapl/static/sapl/frontend/js/parlamentar.307451cf.js.gz
  45. 1
      sapl/static/sapl/frontend/js/parlamentar.307451cf.js.map
  46. BIN
      sapl/static/sapl/frontend/js/parlamentar.307451cf.js.map.gz
  47. BIN
      sapl/static/sapl/frontend/js/parlamentar.35e37659.js.gz
  48. 1
      sapl/static/sapl/frontend/js/parlamentar.35e37659.js.map
  49. BIN
      sapl/static/sapl/frontend/js/parlamentar.35e37659.js.map.gz
  50. 2
      sapl/templates/base.html
  51. 14
      sapl/templates/base/autor_detail.html
  52. 51
      sapl/templates/base/autor_filter.html
  53. 19
      sapl/templates/materia/config_etiqueta_materia.html
  54. 6
      sapl/templates/materia/layouts.yaml
  55. 6
      sapl/templates/materia/materialegislativa_detail.html
  56. 2
      sapl/templates/materia/materialegislativa_filter.html
  57. 38
      sapl/templates/materia/materialegislativa_form.html
  58. 2
      sapl/templates/materia/tramitacao_detail.html
  59. 10
      sapl/templates/menu_tabelas_auxiliares.yaml
  60. 104
      sapl/templates/norma/normajuridica_form.html
  61. 3
      sapl/templates/relatorios/blocos_sessao_plenaria/materias_expediente.html
  62. 3
      sapl/templates/relatorios/blocos_sessao_plenaria/materias_ordemdia.html
  63. 40
      sapl/templates/relatorios/etiqueta_materia_legislativa.html
  64. 4
      sapl/templates/relatorios/relatorio_pauta_sessao.html
  65. 3
      sapl/templates/sessao/blocos_ata/materias_expediente.html
  66. 3
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  67. 5
      sapl/templates/sessao/blocos_resumo/materias_expediente.html
  68. 5
      sapl/templates/sessao/blocos_resumo/materias_ordem_dia.html
  69. 17
      sapl/templates/sessao/oradores_create.html
  70. 2
      sapl/webpack-stats.json
  71. 35
      scripts/gerar_hash_proposicoes.py
  72. 2
      setup.py

2
.travis.yml

@ -1,7 +1,7 @@
language: python language: python
python: python:
- 3.5 - 3.6
services: services:
- postgresql - postgresql

2
docker-compose-dev.yml

@ -4,7 +4,6 @@ services:
sapldb-dev: sapldb-dev:
container_name: sapldb-dev container_name: sapldb-dev
image: postgres:10.5-alpine image: postgres:10.5-alpine
restart: always
environment: environment:
POSTGRES_PASSWORD: sapl POSTGRES_PASSWORD: sapl
POSTGRES_USER: sapl POSTGRES_USER: sapl
@ -16,7 +15,6 @@ services:
sapl-dev: sapl-dev:
container_name: sapl-dev container_name: sapl-dev
restart: always
image: sapl:dev image: sapl:dev
build: build:
context: . context: .

2
docker-compose.yml

@ -26,7 +26,7 @@ services:
networks: networks:
- sapl-net - sapl-net
sapl: sapl:
image: interlegis/sapl:3.1.161-RC2 image: interlegis/sapl:3.1.161-RC3
#build: . #build: .
restart: always restart: always
environment: environment:

38
docs/howtogit.rst

@ -1,15 +1,17 @@
De forma muito simples e em linhas gerais o básico sobre GIT ====
De forma muito simples e em linhas gerais o básico sobre Git
====
Glosário Glosário
--------- ---------
Git - Sistema de controle de versão de aquivos Git - Sistema de controle de versão de aquivos
GitHub - É um serviço web que oferece diversas funcionalidades extras aplicadas ao git GitHub - É um serviço web que oferece diversas funcionalidades extras aplicadas ao Git
Branch - Significa ramificar seu projeto, criar um snapshot. Branch - Significa ramificar seu projeto, criar um snapshot
Merge - Significa incorporar seu branch no master Merge - Significa incorporar seu branch ao master
Pode ser útil Pode ser útil
@ -23,55 +25,49 @@ Exibir informações:
git status git status
Ver repositório:
Ver repositorio
git remote -v git remote -v
Definir repositório:
Para definir repositorio
git remote set-url origin https://github.com/interlegis/sapl.git git remote set-url origin https://github.com/interlegis/sapl.git
Criar um branch:
Para criar um branch
git checkout -b nome_branch git checkout -b nome_branch
git add arquivos git add arquivos
Para remover um branch Remover um branch:
git branch -d nome-branch git branch -d nome-branch
Commitar:
Para comitar
git commit -m "Comentário" git commit -m "Comentário"
Para enviar o branch Enviar o branch:
git push origin nome_branch git push origin nome_branch
Na base local, descartar alguma alteração feita nos arquivos:
Na base local descartar alguma alteração feita nos arquivos:
git checkout -- <arquivo> git checkout -- <arquivo>
Ao invés disso, remover todas as alterações e commits locais, recuperar o histórico mais recente do servidor e apontar para seu branch master local:
Ao invés dissoremover todas as alterações e commits locais, recuperar o histórico mais recente do servidor e apontar para seu branch master local
git fetch origin git fetch origin
git reset --hard origin/master git reset --hard origin/master
Atualizar para alguma brach especifica (ex:785-atualizar-migracao): Atualizar para algum branch específico (ex:785-atualizar-migracao):
git checkout 785-atualizar-migracao git checkout 785-atualizar-migracao
Voltar para a branch master Voltar para a branch master:
git checkout master git checkout master
Verificar 5 ultimos comits: Verificar os últimos 5 commits:
git log --oneline -n 5 git log --oneline -n 5

1
requirements/requirements.txt

@ -31,6 +31,7 @@ more-itertools==8.2.0
pysolr==3.6.0 pysolr==3.6.0
PyPDF4==1.27.0 PyPDF4==1.27.0
pyoai==2.5.0 pyoai==2.5.0
Unidecode==1.1.1
git+https://github.com/interlegis/trml2pdf git+https://github.com/interlegis/trml2pdf
git+https://github.com/interlegis/django-admin-bootstrapped git+https://github.com/interlegis/django-admin-bootstrapped

2
sapl/api/serializers.py

@ -139,7 +139,7 @@ class ParlamentarResumeSerializer(serializers.ModelSerializer):
# Caso não exista filiação com essas condições # Caso não exista filiação com essas condições
except ObjectDoesNotExist: except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Parlamentar com (data<={} e data_desfiliacao>={}) " self.logger.warning("user=" + username + ". Parlamentar com (data<={} e data_desfiliacao>={}) "
"ou (data<={} e data_desfiliacao=Null)) não possui filiação." "ou (data<={} e data_desfiliacao=Null)) não possui filiação."
.format(legislatura.data_fim, legislatura.data_fim, legislatura.data_fim)) .format(legislatura.data_fim, legislatura.data_fim, legislatura.data_fim))
filiacao = 'Não possui filiação' filiacao = 'Não possui filiação'

16
sapl/audiencia/forms.py

@ -95,8 +95,10 @@ class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
except ObjectDoesNotExist: except ObjectDoesNotExist:
msg = _('A matéria %s%s/%s não existe no cadastro' msg = _('A matéria %s%s/%s não existe no cadastro'
' de matérias legislativas.' % (tipo_materia, materia, ano_materia)) ' de matérias legislativas.' % (tipo_materia, materia, ano_materia))
self.logger.error('A MateriaLegislativa %s%s/%s não existe no cadastro' self.logger.warn(
' de matérias legislativas.' % (tipo_materia, materia, ano_materia)) 'A MateriaLegislativa %s%s/%s não existe no cadastro'
' de matérias legislativas.' % (tipo_materia, materia, ano_materia)
)
raise ValidationError(msg) raise ValidationError(msg)
else: else:
self.logger.info("MateriaLegislativa %s%s/%s obtida com sucesso." % (tipo_materia, materia, ano_materia)) self.logger.info("MateriaLegislativa %s%s/%s obtida com sucesso." % (tipo_materia, materia, ano_materia))
@ -106,8 +108,10 @@ class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
campos = [materia, tipo_materia, ano_materia] campos = [materia, tipo_materia, ano_materia]
if campos.count(None) + campos.count('') < len(campos): if campos.count(None) + campos.count('') < len(campos):
msg = _('Preencha todos os campos relacionados à Matéria Legislativa') msg = _('Preencha todos os campos relacionados à Matéria Legislativa')
self.logger.error('Algum campo relacionado à MatériaLegislativa %s%s/%s \ self.logger.warn(
não foi preenchido.' % (tipo_materia, materia, ano_materia)) 'Algum campo relacionado à MatériaLegislativa %s%s/%s \
não foi preenchido.' % (tipo_materia, materia, ano_materia)
)
raise ValidationError(msg) raise ValidationError(msg)
if not cleaned_data['numero']: if not cleaned_data['numero']:
@ -122,7 +126,9 @@ class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']: if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']:
msg = _('A hora de fim ({}) não pode ser anterior a hora de início({})' msg = _('A hora de fim ({}) não pode ser anterior a hora de início({})'
.format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio'])) .format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']))
self.logger.error('Hora de fim anterior à hora de início.') self.logger.warn(
'Hora de fim anterior à hora de início.'
)
raise ValidationError(msg) raise ValidationError(msg)
if parlamentar_autor.autor.first() not in requerimento.autores.all(): if parlamentar_autor.autor.first() not in requerimento.autores.all():

168
sapl/base/forms.py

@ -117,8 +117,7 @@ class UsuarioCreateForm(ModelForm):
data = self.cleaned_data data = self.cleaned_data
if data['password1'] != data['password2']: if data['password1'] != data['password2']:
self.logger.error('Erro de validação. Senhas informadas ({}, {}) são diferentes.'.format( self.logger.warn('Erro de validação. Senhas informadas são diferentes.')
data['password1'], data['password2']))
raise ValidationError('Senhas informadas são diferentes') raise ValidationError('Senhas informadas são diferentes')
return data return data
@ -252,8 +251,7 @@ class UsuarioEditForm(ModelForm):
data = self.cleaned_data data = self.cleaned_data
if data['password1'] and data['password1'] != data['password2']: if data['password1'] and data['password1'] != data['password2']:
self.logger.error("Erro de validação. Senhas informadas ({}, {}) são diferentes." self.logger.warn("Erro de validação. Senhas informadas são diferentes.")
.format(data['password1'], data['password2']))
raise ValidationError('Senhas informadas são diferentes') raise ValidationError('Senhas informadas são diferentes')
return data return data
@ -316,30 +314,37 @@ class SessaoLegislativaForm(FileFieldCheckMixin, ModelForm):
ult = 0 ult = 0
if numero <= ult and flag_edit: if numero <= ult and flag_edit:
self.logger.error('O número da SessaoLegislativa ({}) é menor ou igual ' self.logger.warn(
'que o de Sessões Legislativas passadas ({})'.format(numero, ult)) 'O número da SessaoLegislativa ({}) é menor ou igual '
'que o de Sessões Legislativas passadas ({})'.format(numero, ult)
)
raise ValidationError('O número da Sessão Legislativa não pode ser menor ou igual ' raise ValidationError('O número da Sessão Legislativa não pode ser menor ou igual '
'que o de Sessões Legislativas passadas') 'que o de Sessões Legislativas passadas')
if data_inicio < data_inicio_leg or \ if data_inicio < data_inicio_leg or \
data_inicio > data_fim_leg: data_inicio > data_fim_leg:
self.logger.error('A data de início ({}) da SessaoLegislativa está compreendida ' self.logger.warn(
'A data de início ({}) da SessaoLegislativa está compreendida '
'fora da data início ({}) e fim ({}) da Legislatura ' 'fora da data início ({}) e fim ({}) da Legislatura '
'selecionada'.format(data_inicio, data_inicio_leg, data_fim_leg)) 'selecionada'.format(data_inicio, data_inicio_leg, data_fim_leg)
)
raise ValidationError('A data de início da Sessão Legislativa deve estar compreendida ' raise ValidationError('A data de início da Sessão Legislativa deve estar compreendida '
'entre a data início e fim da Legislatura selecionada') 'entre a data início e fim da Legislatura selecionada')
if data_fim > data_fim_leg or \ if data_fim > data_fim_leg or \
data_fim < data_inicio_leg: data_fim < data_inicio_leg:
self.logger.error('A data de fim ({}) da SessaoLegislativa está compreendida ' self.logger.warn(
'A data de fim ({}) da SessaoLegislativa está compreendida '
'fora da data início ({}) e fim ({}) da Legislatura ' 'fora da data início ({}) e fim ({}) da Legislatura '
'selecionada.'.format(data_fim, data_inicio_leg, data_fim_leg)) 'selecionada.'.format(data_fim, data_inicio_leg, data_fim_leg)
)
raise ValidationError('A data de fim da Sessão Legislativa deve estar compreendida ' raise ValidationError('A data de fim da Sessão Legislativa deve estar compreendida '
'entre a data início e fim da Legislatura selecionada') 'entre a data início e fim da Legislatura selecionada')
if data_inicio > data_fim: if data_inicio > data_fim:
self.logger.error( self.logger.warn(
'Data início ({}) superior à data fim ({}).'.format(data_inicio, data_fim)) 'Data início ({}) superior à data fim ({}).'.format(data_inicio, data_fim)
)
raise ValidationError( raise ValidationError(
'Data início não pode ser superior à data fim') 'Data início não pode ser superior à data fim')
@ -348,8 +353,10 @@ class SessaoLegislativaForm(FileFieldCheckMixin, ModelForm):
if data_inicio_intervalo and data_fim_intervalo and \ if data_inicio_intervalo and data_fim_intervalo and \
data_inicio_intervalo > data_fim_intervalo: data_inicio_intervalo > data_fim_intervalo:
self.logger.error('Data início de intervalo ({}) superior à ' self.logger.warn(
'data fim de intervalo ({}).'.format(data_inicio_intervalo, data_fim_intervalo)) 'Data início de intervalo ({}) superior à '
'data fim de intervalo ({}).'.format(data_inicio_intervalo, data_fim_intervalo)
)
raise ValidationError('Data início de intervalo não pode ser ' raise ValidationError('Data início de intervalo não pode ser '
'superior à data fim de intervalo') 'superior à data fim de intervalo')
@ -358,10 +365,13 @@ class SessaoLegislativaForm(FileFieldCheckMixin, ModelForm):
data_inicio_intervalo < data_inicio_leg or \ data_inicio_intervalo < data_inicio_leg or \
data_inicio_intervalo > data_fim or \ data_inicio_intervalo > data_fim or \
data_inicio_intervalo > data_fim_leg: data_inicio_intervalo > data_fim_leg:
self.logger.error('A data de início do intervalo ({}) não está compreendida entre ' self.logger.warn(
'A data de início do intervalo ({}) não está compreendida entre '
'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da ' 'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da '
'própria Sessão Legislativa ({} e {}).' 'própria Sessão Legislativa ({} e {}).'.format(
.format(data_inicio_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim)) data_inicio_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim
)
)
raise ValidationError('A data de início do intervalo deve estar compreendida entre ' raise ValidationError('A data de início do intervalo deve estar compreendida entre '
'as datas de início e fim tanto da Legislatura quanto da ' 'as datas de início e fim tanto da Legislatura quanto da '
'própria Sessão Legislativa') 'própria Sessão Legislativa')
@ -370,10 +380,13 @@ class SessaoLegislativaForm(FileFieldCheckMixin, ModelForm):
data_fim_intervalo > data_fim_leg or \ data_fim_intervalo > data_fim_leg or \
data_fim_intervalo < data_inicio or \ data_fim_intervalo < data_inicio or \
data_fim_intervalo < data_inicio_leg: data_fim_intervalo < data_inicio_leg:
self.logger.error('A data de fim do intervalo ({}) não está compreendida entre ' self.logger.warn(
'A data de fim do intervalo ({}) não está compreendida entre '
'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da ' 'as datas de início ({}) e fim ({}) tanto da Legislatura quanto da '
'própria Sessão Legislativa ({} e {}).' 'própria Sessão Legislativa ({} e {}).'.format(
.format(data_fim_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim)) data_fim_intervalo, data_inicio_leg, data_fim_leg, data_inicio, data_fim
)
)
raise ValidationError('A data de fim do intervalo deve estar compreendida entre ' raise ValidationError('A data de fim do intervalo deve estar compreendida entre '
'as datas de início e fim tanto da Legislatura quanto da ' 'as datas de início e fim tanto da Legislatura quanto da '
'própria Sessão Legislativa') 'própria Sessão Legislativa')
@ -567,8 +580,9 @@ class AutorForm(ModelForm):
def valida_igualdade(self, texto1, texto2, msg): def valida_igualdade(self, texto1, texto2, msg):
if texto1 != texto2: if texto1 != texto2:
self.logger.error( self.logger.warn(
'Textos diferentes. ("{}" e "{}")'.format(texto1, texto2)) 'Textos diferentes. ("{}" e "{}")'.format(texto1, texto2)
)
raise ValidationError(msg) raise ValidationError(msg)
return True return True
@ -582,8 +596,10 @@ class AutorForm(ModelForm):
cd = self.cleaned_data cd = self.cleaned_data
if 'action_user' not in cd or not cd['action_user']: if 'action_user' not in cd or not cd['action_user']:
self.logger.error('Não Informado se o Autor terá usuário ' self.logger.warn(
'vinculado para acesso ao Sistema.') 'Não Informado se o Autor terá usuário '
'vinculado para acesso ao Sistema.'
)
raise ValidationError(_('Informe se o Autor terá usuário ' raise ValidationError(_('Informe se o Autor terá usuário '
'vinculado para acesso ao Sistema.')) 'vinculado para acesso ao Sistema.'))
@ -593,10 +609,13 @@ class AutorForm(ModelForm):
self.instance.user, self.instance.user,
get_user_model().USERNAME_FIELD) != cd['username']: get_user_model().USERNAME_FIELD) != cd['username']:
if 'status_user' not in cd or not cd['status_user']: if 'status_user' not in cd or not cd['status_user']:
self.logger.error('Foi trocado ou removido o usuário deste Autor ({}), ' self.logger.warn(
'Foi trocado ou removido o usuário deste Autor ({}), '
'mas não foi informado como se deve proceder ' 'mas não foi informado como se deve proceder '
'com o usuário que está sendo desvinculado? ({})' 'com o usuário que está sendo desvinculado? ({})'.format(
.format(cd['username'], get_user_model().USERNAME_FIELD)) cd['username'], get_user_model().USERNAME_FIELD
)
)
raise ValidationError( raise ValidationError(
_('Foi trocado ou removido o usuário deste Autor, ' _('Foi trocado ou removido o usuário deste Autor, '
'mas não foi informado como se deve proceder ' 'mas não foi informado como se deve proceder '
@ -613,8 +632,9 @@ class AutorForm(ModelForm):
if cd['action_user'] == 'A': if cd['action_user'] == 'A':
param_username = {get_user_model().USERNAME_FIELD: cd['username']} param_username = {get_user_model().USERNAME_FIELD: cd['username']}
if not User.objects.filter(**param_username).exists(): if not User.objects.filter(**param_username).exists():
self.logger.error( self.logger.warn(
'Não existe usuário com username "%s". ' % cd['username']) 'Não existe usuário com username "%s". ' % cd['username']
)
raise ValidationError( raise ValidationError(
_('Não existe usuário com username "%s". ' _('Não existe usuário com username "%s". '
'Para utilizar esse username você deve selecionar ' 'Para utilizar esse username você deve selecionar '
@ -623,7 +643,7 @@ class AutorForm(ModelForm):
if cd['action_user'] != 'N': if cd['action_user'] != 'N':
if 'username' not in cd or not cd['username']: if 'username' not in cd or not cd['username']:
self.logger.error('Username não informado.') self.logger.warn('Username não informado.')
raise ValidationError(_('O username deve ser informado.')) raise ValidationError(_('O username deve ser informado.'))
param_username = { param_username = {
@ -634,7 +654,7 @@ class AutorForm(ModelForm):
nome = autor_vinculado[0].nome nome = autor_vinculado[0].nome
error_msg = 'Já existe um autor para este ' \ error_msg = 'Já existe um autor para este ' \
'usuário ({}): {}'.format(cd['username'], nome) 'usuário ({}): {}'.format(cd['username'], nome)
self.logger.error(error_msg) self.logger.warn(error_msg)
raise ValidationError(_(error_msg)) raise ValidationError(_(error_msg))
""" """
@ -643,33 +663,34 @@ class AutorForm(ModelForm):
ainda assim para renderizar um message.danger no topo do form. ainda assim para renderizar um message.danger no topo do form.
""" """
if 'tipo' not in cd or not cd['tipo']: if 'tipo' not in cd or not cd['tipo']:
self.logger.error('Tipo do Autor não selecionado.') self.logger.warn('Tipo do Autor não selecionado.')
raise ValidationError( raise ValidationError(
_('O Tipo do Autor deve ser selecionado.')) _('O Tipo do Autor deve ser selecionado.'))
tipo = cd['tipo'] tipo = cd['tipo']
if 'nome' in cd and \
qs_autor.filter(nome=cd['nome']).exists():
raise ValidationError("Autor '%s' já existente!" % cd['nome'])
if not tipo.content_type: if not tipo.content_type:
if 'nome' not in cd or not cd['nome']: if 'nome' not in cd or not cd['nome']:
self.logger.error('Nome do Autor não informado.') self.logger.warn('Nome do Autor não informado.')
raise ValidationError( raise ValidationError(
_('O Nome do Autor deve ser informado.')) _('O Nome do Autor deve ser informado.'))
elif qs_autor.filter(nome=cd['nome']).exists():
raise ValidationError("Autor '%s' já existente!" % cd['nome'])
else: else:
if 'autor_related' not in cd or not cd['autor_related']: if 'autor_related' not in cd or not cd['autor_related']:
self.logger.error('Registro de %s não escolhido para ser ' self.logger.warn(
'vinculado ao cadastro de Autor' % tipo.descricao) 'Registro de %s não escolhido para ser '
'vinculado ao cadastro de Autor' % tipo.descricao
)
raise ValidationError( raise ValidationError(
_('Um registro de %s deve ser escolhido para ser ' _('Um registro de %s deve ser escolhido para ser '
'vinculado ao cadastro de Autor') % tipo.descricao) 'vinculado ao cadastro de Autor') % tipo.descricao)
if not tipo.content_type.model_class().objects.filter( if not tipo.content_type.model_class().objects.filter(
pk=cd['autor_related']).exists(): pk=cd['autor_related']).exists():
self.logger.error('O Registro definido (%s-%s) não está na base ' self.logger.warn(
'de %s.' % (cd['autor_related'], cd['q'], tipo.descricao)) 'O Registro definido (%s-%s) não está na base '
'de %s.' % (cd['autor_related'], cd['q'], tipo.descricao)
)
raise ValidationError( raise ValidationError(
_('O Registro definido (%s-%s) não está na base de %s.' _('O Registro definido (%s-%s) não está na base de %s.'
) % (cd['autor_related'], cd['q'], tipo.descricao)) ) % (cd['autor_related'], cd['q'], tipo.descricao))
@ -679,8 +700,10 @@ class AutorForm(ModelForm):
content_type_id=cd['tipo'].content_type_id) content_type_id=cd['tipo'].content_type_id)
if qs_autor_selected.exists(): if qs_autor_selected.exists():
autor = qs_autor_selected.first() autor = qs_autor_selected.first()
self.logger.error('Já existe um autor Cadastrado para ' self.logger.warn(
'%s' % autor.autor_related) 'Já existe um autor Cadastrado para '
'%s' % autor.autor_related
)
raise ValidationError( raise ValidationError(
_('Já existe um autor Cadastrado para %s' _('Já existe um autor Cadastrado para %s'
) % autor.autor_related) ) % autor.autor_related)
@ -744,6 +767,26 @@ class AutorForm(ModelForm):
return autor return autor
class AutorFilterSet(django_filters.FilterSet):
nome = django_filters.CharFilter(label=_('Nome do Autor'), lookup_expr='icontains')
class Meta:
model = Autor
fields = ['nome']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
row0 = to_row([('nome', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Autor'),
row0,
form_actions(label='Pesquisar')))
class AutorFormForAdmin(AutorForm): class AutorFormForAdmin(AutorForm):
status_user = forms.ChoiceField( status_user = forms.ChoiceField(
label=_('Bloqueio do Usuário Existente'), label=_('Bloqueio do Usuário Existente'),
@ -1548,12 +1591,14 @@ class ConfiguracoesAppForm(ModelForm):
casa = CasaLegislativa.objects.first() casa = CasaLegislativa.objects.first()
if not casa: if not casa:
self.logger.error('Não há casa legislativa relacionada.') self.logger.warn('Não há casa legislativa relacionada.')
raise ValidationError("Não há casa legislativa relacionada.") raise ValidationError("Não há casa legislativa relacionada.")
if not casa.logotipo and mostrar_brasao_painel: if not casa.logotipo and mostrar_brasao_painel:
self.logger.error('Não há logitipo configurado para esta ' self.logger.warn(
'CasaLegislativa ({}).'.format(casa)) 'Não há logitipo configurado para esta '
'CasaLegislativa ({}).'.format(casa)
)
raise ValidationError("Não há logitipo configurado para esta " raise ValidationError("Não há logitipo configurado para esta "
"Casa legislativa.") "Casa legislativa.")
@ -1587,8 +1632,9 @@ class RecuperarSenhaForm(PasswordResetForm):
if not email_existente: if not email_existente:
msg = 'Não existe nenhum usuário cadastrado com este e-mail.' msg = 'Não existe nenhum usuário cadastrado com este e-mail.'
self.logger.error('Não existe nenhum usuário cadastrado com este e-mail ({}).' self.logger.warn(
.format(self.data['email'])) 'Não existe nenhum usuário cadastrado com este e-mail ({}).'.format(self.data['email'])
)
raise ValidationError(msg) raise ValidationError(msg)
return self.cleaned_data return self.cleaned_data
@ -1655,8 +1701,7 @@ class AlterarSenhaForm(Form):
new_password2 = data['new_password2'] new_password2 = data['new_password2']
if new_password1 != new_password2: if new_password1 != new_password2:
self.logger.error("'Nova Senha' ({}) diferente de 'Confirmar Senha' ({})".format( self.logger.warn("'Nova Senha' diferente de 'Confirmar Senha'")
new_password1, new_password2))
raise ValidationError( raise ValidationError(
"'Nova Senha' diferente de 'Confirmar Senha'") "'Nova Senha' diferente de 'Confirmar Senha'")
@ -1665,8 +1710,9 @@ class AlterarSenhaForm(Form):
# TODO: senha atual igual a senha anterior, etc # TODO: senha atual igual a senha anterior, etc
if len(new_password1) < 6: if len(new_password1) < 6:
self.logger.error( self.logger.warn(
'A senha informada ({}) não tem o mínimo de 6 caracteres.'.format(new_password1)) 'A senha informada não tem o mínimo de 6 caracteres.'
)
raise ValidationError( raise ValidationError(
"A senha informada deve ter no mínimo 6 caracteres") "A senha informada deve ter no mínimo 6 caracteres")
@ -1675,20 +1721,24 @@ class AlterarSenhaForm(Form):
user = User.objects.get(username=username) user = User.objects.get(username=username)
if user.is_anonymous(): if user.is_anonymous():
self.logger.error( self.logger.warn(
'Não é possível alterar senha de usuário anônimo ({}).'.format(username)) 'Não é possível alterar senha de usuário anônimo ({}).'.format(username)
)
raise ValidationError( raise ValidationError(
"Não é possível alterar senha de usuário anônimo") "Não é possível alterar senha de usuário anônimo")
if not user.check_password(old_password): if not user.check_password(old_password):
self.logger.error('Senha atual informada ({}) não confere ' self.logger.warn(
'com a senha armazenada.'.format(old_password)) 'Senha atual informada não confere '
'com a senha armazenada.'
)
raise ValidationError("Senha atual informada não confere " raise ValidationError("Senha atual informada não confere "
"com a senha armazenada") "com a senha armazenada")
if user.check_password(new_password1): if user.check_password(new_password1):
self.logger.error( self.logger.warn(
'Nova senha ({}) igual à senha anterior.'.format(new_password1)) 'Nova senha igual à senha anterior.'
)
raise ValidationError( raise ValidationError(
"Nova senha não pode ser igual à senha anterior") "Nova senha não pode ser igual à senha anterior")

24
sapl/base/models.py

@ -231,24 +231,28 @@ class TipoAutor(models.Model):
@reversion.register() @reversion.register()
class Autor(models.Model): class Autor(models.Model):
user = models.OneToOneField(
user = models.OneToOneField(get_settings_auth_user_model(), get_settings_auth_user_model(),
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
null=True) null=True)
tipo = models.ForeignKey(
tipo = models.ForeignKey(TipoAutor, verbose_name=_('Tipo do Autor'), TipoAutor,
verbose_name=_('Tipo do Autor'),
on_delete=models.PROTECT) on_delete=models.PROTECT)
content_type = models.ForeignKey( content_type = models.ForeignKey(
ContentType, ContentType,
blank=True, null=True, default=None) blank=True,
null=True,
default=None)
object_id = models.PositiveIntegerField( object_id = models.PositiveIntegerField(
blank=True, null=True, default=None) blank=True,
null=True,
default=None)
autor_related = GenericForeignKey('content_type', 'object_id') autor_related = GenericForeignKey('content_type', 'object_id')
nome = models.CharField( nome = models.CharField(
max_length=120, blank=True, verbose_name=_('Nome do Autor')) max_length=120,
blank=True,
verbose_name=_('Nome do Autor'))
cargo = models.CharField(max_length=50, blank=True) cargo = models.CharField(max_length=50, blank=True)
class Meta: class Meta:

4
sapl/base/urls.py

@ -8,7 +8,8 @@ from django.contrib.auth.views import (password_reset, password_reset_complete,
password_reset_done) password_reset_done)
from django.views.generic.base import RedirectView, TemplateView from django.views.generic.base import RedirectView, TemplateView
from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud, get_estatistica, DetailUsuarioView from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud, get_estatistica, DetailUsuarioView, \
PesquisarAutorView
from sapl.settings import EMAIL_SEND_USER, MEDIA_URL from sapl.settings import EMAIL_SEND_USER, MEDIA_URL
from .apps import AppConfig from .apps import AppConfig
@ -90,6 +91,7 @@ recuperar_senha = [
urlpatterns = [ urlpatterns = [
url(r'^sistema/autor/tipo/', include(TipoAutorCrud.get_urls())), url(r'^sistema/autor/tipo/', include(TipoAutorCrud.get_urls())),
url(r'^sistema/autor/', include(AutorCrud.get_urls())), url(r'^sistema/autor/', include(AutorCrud.get_urls())),
url(r'^sistema/autor/pesquisar-autor/', PesquisarAutorView.as_view(), name='pesquisar_autor'),
url(r'^sistema/ajuda/(?P<topic>\w+)$', url(r'^sistema/ajuda/(?P<topic>\w+)$',
HelpTopicView.as_view(), name='help_topic'), HelpTopicView.as_view(), name='help_topic'),

105
sapl/base/views.py

@ -41,7 +41,7 @@ from sapl.relatorios.views import (relatorio_materia_em_tramitacao, relatorio_ma
from sapl import settings from sapl import settings
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm, AutorFilterSet
from sapl.comissoes.models import Comissao, Reuniao from sapl.comissoes.models import Comissao, Reuniao
from sapl.crud.base import CrudAux, make_pagination from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio, from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio,
@ -295,6 +295,58 @@ class AutorCrud(CrudAux):
return url_reverse return url_reverse
class PesquisarAutorView(FilterView):
model = Autor
filterset_class = AutorFilterSet
paginate_by = 10
def get_filterset_kwargs(self, filterset_class):
super().get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
qs = self.get_queryset().order_by('nome').distinct()
kwargs.update({
'queryset': qs,
})
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(page_obj.number, paginator.num_pages)
context['NO_ENTRIES_MSG'] = 'Nenhum Autor encontrado!'
context['title'] = _('Autores')
return context
def get(self, request, *args, **kwargs):
super().get(request)
data = self.filterset.data
url = ''
if data:
url = "&" + str(self.request.META['QUERY_STRING'])
if url.startswith("&page"):
ponto_comeco = url.find('nome=') - 1
url = url[ponto_comeco:]
context = self.get_context_data(filter=self.filterset,
object_list=self.object_list,
filter_url=url,
numero_res=len(self.object_list))
context['show_results'] = show_results_filter_set(self.request.GET.copy())
return self.render_to_response(context)
class RelatoriosListView(TemplateView): class RelatoriosListView(TemplateView):
template_name='base/relatorios_list.html' template_name='base/relatorios_list.html'
@ -1579,32 +1631,25 @@ def mandato_sem_data_inicio():
def get_estatistica(request): def get_estatistica(request):
materias = MateriaLegislativa.objects.all()
normas = NormaJuridica.objects.all()
datas = [
materias.order_by('-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True)
.exclude(data_ultima_atualizacao__isnull=True).first(),
normas.order_by('-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True)
.exclude(data_ultima_atualizacao__isnull=True).first()
]
json_dict = {} max_data = max(datas) if datas[0] and datas[1] else next(iter([i for i in datas if i is not None]), '')
datas = [MateriaLegislativa.objects.all().
order_by('-data_ultima_atualizacao').
values_list('data_ultima_atualizacao', flat=True).
first(),
NormaJuridica.objects.all().
order_by('-data_ultima_atualizacao').
values_list('data_ultima_atualizacao', flat=True).
first()] # Retorna [None, None] se inexistem registros
max_data = ''
if datas[0] and datas[1]:
max_data = max(datas)
else:
max_data = next(iter([i for i in datas if i is not None]), '')
json_dict["data_ultima_atualizacao"] = max_data
json_dict["num_materias_legislativas"] = MateriaLegislativa.objects.all().count()
json_dict["num_normas_juridicas "] = NormaJuridica.objects.all().count()
json_dict["num_parlamentares"] = Parlamentar.objects.all().count()
json_dict["num_sessoes_plenarias"] = SessaoPlenaria.objects.all().count()
return JsonResponse(json_dict) return JsonResponse({
"data_ultima_atualizacao": max_data,
"num_materias_legislativas": materias.count(),
"num_normas_juridicas ": normas.count(),
"num_parlamentares": Parlamentar.objects.all().count(),
"num_sessoes_plenarias": SessaoPlenaria.objects.all().count()
})
class ListarMandatoSemDataInicioView(PermissionRequiredMixin, ListView): class ListarMandatoSemDataInicioView(PermissionRequiredMixin, ListView):
@ -2020,17 +2065,23 @@ class AppConfigCrud(CrudAux):
recibo_prop_atual = AppConfig.objects.last().receber_recibo_proposicao recibo_prop_atual = AppConfig.objects.last().receber_recibo_proposicao
recibo_prop_novo = self.request.POST['receber_recibo_proposicao'] recibo_prop_novo = self.request.POST['receber_recibo_proposicao']
if recibo_prop_novo == 'False' and recibo_prop_atual: if recibo_prop_novo == 'False' and recibo_prop_atual:
props = Proposicao.objects.filter(hash_code='') props = Proposicao.objects.filter(hash_code='', data_recebimento__isnull=True).exclude(data_envio__isnull=True)
for prop in props: for prop in props:
try:
self.gerar_hash(prop) self.gerar_hash(prop)
except ValidationError as e:
form.add_error('receber_recibo_proposicao',e)
msg = _("Não foi possível mudar a configuração porque a Proposição {} não possui texto original vinculado!".format(prop))
messages.error(self.request, msg)
return super().form_invalid(form)
return super().form_valid(form) return super().form_valid(form)
def gerar_hash(self, inst): def gerar_hash(self, inst):
inst.save()
if inst.texto_original: if inst.texto_original:
try: try:
inst.hash_code = gerar_hash_arquivo( inst.hash_code = gerar_hash_arquivo(
inst.texto_original.path, str(inst.pk)) inst.texto_original.path, str(inst.pk))
inst.save()
except IOError: except IOError:
raise ValidationError("Existem proposicoes com arquivos inexistentes.") raise ValidationError("Existem proposicoes com arquivos inexistentes.")
elif inst.texto_articulado.exists(): elif inst.texto_articulado.exists():

106
sapl/comissoes/forms.py

@ -61,11 +61,17 @@ class ComposicaoForm(forms.ModelForm):
if intersecao_periodo: if intersecao_periodo:
if periodo.data_fim: if periodo.data_fim:
self.logger.error('O período informado ({} a {}) choca com períodos já cadastrados para esta comissão' self.logger.warn(
.format(periodo.data_inicio, periodo.data_fim)) 'O período informado ({} a {}) choca com períodos já cadastrados para esta comissão'.format(
periodo.data_inicio, periodo.data_fim
)
)
else: else:
self.logger.error('O período informado ({} - ) choca com períodos já cadastrados para esta comissão' self.logger.warn(
.format(periodo.data_inicio)) 'O período informado ({} - ) choca com períodos já cadastrados para esta comissão'.format(
periodo.data_inicio
)
)
raise ValidationError('O período informado choca com períodos já cadastrados para esta comissão') raise ValidationError('O período informado choca com períodos já cadastrados para esta comissão')
return data return data
@ -89,8 +95,10 @@ class PeriodoForm(forms.ModelForm):
data_fim = cleaned_data['data_fim'] data_fim = cleaned_data['data_fim']
if data_fim and data_fim < data_inicio: if data_fim and data_fim < data_inicio:
self.logger.error('A Data Final ({}) é menor que ' self.logger.warn(
'a Data Inicial({}).'.format(data_fim, data_inicio)) 'A Data Final ({}) é menor que '
'a Data Inicial({}).'.format(data_fim, data_inicio)
)
raise ValidationError('A Data Final não pode ser menor que ' raise ValidationError('A Data Final não pode ser menor que '
'a Data Inicial') 'a Data Inicial')
@ -103,9 +111,11 @@ class PeriodoForm(forms.ModelForm):
) )
if not legislatura: if not legislatura:
self.logger.error('O período informado ({} a {})' self.logger.warn(
'O período informado ({} a {})'
'não está contido em uma única ' 'não está contido em uma única '
'legislatura existente'.format(data_inicio, data_fim)) 'legislatura existente'.format(data_inicio, data_fim)
)
raise ValidationError('O período informado ' raise ValidationError('O período informado '
'deve estar contido em uma única ' 'deve estar contido em uma única '
'legislatura existente') 'legislatura existente')
@ -165,8 +175,10 @@ class ParticipacaoCreateForm(forms.ModelForm):
if data_desligamento and \ if data_desligamento and \
data_designacao > data_desligamento: data_designacao > data_desligamento:
self.logger.error('Data de designação ({}) superior ' self.logger.warn(
'à data de desligamento ({})'.format(data_designacao, data_desligamento)) 'Data de designação ({}) superior '
'à data de desligamento ({})'.format(data_designacao, data_desligamento)
)
raise ValidationError(_('Data de designação não pode ser superior ' raise ValidationError(_('Data de designação não pode ser superior '
'à data de desligamento')) 'à data de desligamento'))
@ -176,8 +188,11 @@ class ParticipacaoCreateForm(forms.ModelForm):
if cleaned_data['cargo'].nome in cargos_unicos: if cleaned_data['cargo'].nome in cargos_unicos:
msg = _('Este cargo é único para esta Comissão.') msg = _('Este cargo é único para esta Comissão.')
self.logger.error('Este cargo ({}) é único para esta Comissão.'.format( self.logger.warn(
cleaned_data['cargo'].nome)) 'Este cargo ({}) é único para esta Comissão.'.format(
cleaned_data['cargo'].nome
)
)
raise ValidationError(msg) raise ValidationError(msg)
return cleaned_data return cleaned_data
@ -253,8 +268,10 @@ class ParticipacaoEditForm(forms.ModelForm):
if data_desligamento and \ if data_desligamento and \
data_designacao > data_desligamento: data_designacao > data_desligamento:
self.logger.error('Data de designação ({}) superior ' self.logger.warn(
'à data de desligamento ({})'.format(data_designacao, data_desligamento)) 'Data de designação ({}) superior '
'à data de desligamento ({})'.format(data_designacao, data_desligamento)
)
raise ValidationError(_('Data de designação não pode ser superior ' raise ValidationError(_('Data de designação não pode ser superior '
'à data de desligamento')) 'à data de desligamento'))
@ -266,8 +283,11 @@ class ParticipacaoEditForm(forms.ModelForm):
if cleaned_data['cargo'].nome in cargos_unicos: if cleaned_data['cargo'].nome in cargos_unicos:
msg = _('Este cargo é único para esta Comissão.') msg = _('Este cargo é único para esta Comissão.')
self.logger.error('Este cargo ({}) é único para esta Comissão (id={}).' self.logger.warn(
.format(cleaned_data['cargo'].nome, composicao_id)) 'Este cargo ({}) é único para esta Comissão (id={}).'.format(
cleaned_data['cargo'].nome, composicao_id
)
)
raise ValidationError(msg) raise ValidationError(msg)
return cleaned_data return cleaned_data
@ -301,51 +321,70 @@ class ComissaoForm(forms.ModelForm):
if len(self.cleaned_data['nome']) > 100: if len(self.cleaned_data['nome']) > 100:
msg = _('Nome da Comissão informado ({}) tem mais de 50 caracteres.'.format( msg = _('Nome da Comissão informado ({}) tem mais de 50 caracteres.'.format(
self.cleaned_data['nome'])) self.cleaned_data['nome']))
self.logger.error( self.logger.warn(
'Nome da Comissão deve ter no máximo 50 caracteres.') 'Nome da Comissão deve ter no máximo 50 caracteres.'
)
raise ValidationError(msg) raise ValidationError(msg)
if (self.cleaned_data['data_extincao'] and if (self.cleaned_data['data_extincao'] and
self.cleaned_data['data_extincao'] < self.cleaned_data['data_extincao'] <
self.cleaned_data['data_criacao']): self.cleaned_data['data_criacao']):
msg = _('Data de extinção não pode ser menor que a de criação') msg = _('Data de extinção não pode ser menor que a de criação')
self.logger.error('Data de extinção ({}) não pode ser menor que a de criação ({}).' self.logger.warn(
.format(self.cleaned_data['data_extincao'], self.cleaned_data['data_criacao'])) 'Data de extinção ({}) não pode ser menor que a de criação ({}).'.format(
self.cleaned_data['data_extincao'], self.cleaned_data['data_criacao']
)
)
raise ValidationError(msg) raise ValidationError(msg)
if (self.cleaned_data['data_final_prevista_temp'] and if (self.cleaned_data['data_final_prevista_temp'] and
self.cleaned_data['data_final_prevista_temp'] < self.cleaned_data['data_final_prevista_temp'] <
self.cleaned_data['data_criacao']): self.cleaned_data['data_criacao']):
msg = _('Data Prevista para Término não pode ser menor que a de criação') msg = _('Data Prevista para Término não pode ser menor que a de criação')
self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de criação ({}).' self.logger.warn(
.format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_criacao'])) 'Data Prevista para Término ({}) não pode ser menor que a de criação ({}).'.format(
self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_criacao']
)
)
raise ValidationError(msg) raise ValidationError(msg)
if (self.cleaned_data['data_prorrogada_temp'] and if (self.cleaned_data['data_prorrogada_temp'] and
self.cleaned_data['data_prorrogada_temp'] < self.cleaned_data['data_prorrogada_temp'] <
self.cleaned_data['data_criacao']): self.cleaned_data['data_criacao']):
msg = _('Data Novo Prazo não pode ser menor que a de criação') msg = _('Data Novo Prazo não pode ser menor que a de criação')
self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de criação ({}).' self.logger.warn(
.format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_criacao'])) 'Data Novo Prazo ({}) não pode ser menor que a de criação ({}).'.format(
self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_criacao']
)
)
raise ValidationError(msg) raise ValidationError(msg)
if (self.cleaned_data['data_instalacao_temp'] and if (self.cleaned_data['data_instalacao_temp'] and
self.cleaned_data['data_instalacao_temp'] < self.cleaned_data['data_instalacao_temp'] <
self.cleaned_data['data_criacao']): self.cleaned_data['data_criacao']):
msg = _('Data de Instalação não pode ser menor que a de criação') msg = _('Data de Instalação não pode ser menor que a de criação')
self.logger.error('Data de Instalação ({}) não pode ser menor que a de criação ({}).' self.logger.warn(
.format(self.cleaned_data['data_instalacao_temp'], self.cleaned_data['data_criacao'])) 'Data de Instalação ({}) não pode ser menor que a de criação ({}).'.format(
self.cleaned_data['data_instalacao_temp'], self.cleaned_data['data_criacao']
)
)
raise ValidationError(msg) raise ValidationError(msg)
if (self.cleaned_data['data_final_prevista_temp'] and self.cleaned_data['data_instalacao_temp'] and if (self.cleaned_data['data_final_prevista_temp'] and self.cleaned_data['data_instalacao_temp'] and
self.cleaned_data['data_final_prevista_temp'] < self.cleaned_data['data_final_prevista_temp'] <
self.cleaned_data['data_instalacao_temp']): self.cleaned_data['data_instalacao_temp']):
msg = _( msg = _(
'Data Prevista para Término não pode ser menor que a de Instalação.') 'Data Prevista para Término não pode ser menor que a de Instalação.')
self.logger.error('Data Prevista para Término ({}) não pode ser menor que a de Instalação ({}).' self.logger.warn(
.format(self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_instalacao_temp'])) 'Data Prevista para Término ({}) não pode ser menor que a de Instalação ({}).'.format(
self.cleaned_data['data_final_prevista_temp'], self.cleaned_data['data_instalacao_temp']
)
)
raise ValidationError(msg) raise ValidationError(msg)
if (self.cleaned_data['data_prorrogada_temp'] and self.cleaned_data['data_instalacao_temp'] and if (self.cleaned_data['data_prorrogada_temp'] and self.cleaned_data['data_instalacao_temp'] and
self.cleaned_data['data_prorrogada_temp'] < self.cleaned_data['data_prorrogada_temp'] <
self.cleaned_data['data_instalacao_temp']): self.cleaned_data['data_instalacao_temp']):
msg = _('Data Novo Prazo não pode ser menor que a de Instalação.') msg = _('Data Novo Prazo não pode ser menor que a de Instalação.')
self.logger.error('Data Novo Prazo ({}) não pode ser menor que a de Instalação ({}).' self.logger.warn(
.format(self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_instalacao_temp'])) 'Data Novo Prazo ({}) não pode ser menor que a de Instalação ({}).'.format(
self.cleaned_data['data_prorrogada_temp'], self.cleaned_data['data_instalacao_temp']
)
)
raise ValidationError(msg) raise ValidationError(msg)
return self.cleaned_data return self.cleaned_data
@ -391,8 +430,11 @@ class ReuniaoForm(ModelForm):
self.cleaned_data['hora_inicio']): self.cleaned_data['hora_inicio']):
msg = _( msg = _(
'A hora de término da reunião não pode ser menor que a de início') 'A hora de término da reunião não pode ser menor que a de início')
self.logger.error("A hora de término da reunião ({}) não pode ser menor que a de início ({})." self.logger.warn(
.format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio'])) "A hora de término da reunião ({}) não pode ser menor que a de início ({}).".format(
self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']
)
)
raise ValidationError(msg) raise ValidationError(msg)
upload_pauta = self.cleaned_data.get('upload_pauta', False) upload_pauta = self.cleaned_data.get('upload_pauta', False)

10
sapl/crud/base.py

@ -577,8 +577,9 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
fm = model._meta.get_field(fo) fm = model._meta.get_field(fo)
except Exception as e: except Exception as e:
username = self.request.user.username username = self.request.user.username
self.logger.error( self.logger.info(
"user=" + username + ". " + str(e)) "user=" + username + ". " + str(e)
)
pass pass
if fm and hasattr(fm, 'related_model')\ if fm and hasattr(fm, 'related_model')\
@ -607,8 +608,9 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
# print(ordering) # print(ordering)
except Exception as e: except Exception as e:
logger.error(string_concat(_( logger.warn(
'ERRO: construção da tupla de ordenação.'), str(e))) string_concat(_('ERRO: construção da tupla de ordenação.'), str(e))
)
# print(queryset.query) # print(queryset.query)
if not self.request.user.is_authenticated(): if not self.request.user.is_authenticated():

38
sapl/materia/forms.py

@ -34,7 +34,7 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto,
MateriaLegislativa, Orgao, MateriaLegislativa, Orgao,
RegimeTramitacao, StatusTramitacao, RegimeTramitacao, StatusTramitacao,
TipoDocumento, TipoProposicao, TipoDocumento, TipoProposicao,
UnidadeTramitacao) UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica, from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica) TipoNormaJuridica)
from sapl.parlamentares.models import Legislatura, Partido, Parlamentar from sapl.parlamentares.models import Legislatura, Partido, Parlamentar
@ -211,10 +211,8 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
if protocolo: if protocolo:
if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists(): if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists():
self.logger.error("Protocolo %s/%s não" self.logger.warning("Protocolo %s/%s não existe" % (protocolo, ano))
" existe" % (protocolo, ano)) raise ValidationError(_('Protocolo %s/%s não existe' % (protocolo, ano)))
raise ValidationError(_('Protocolo %s/%s não'
' existe' % (protocolo, ano)))
if protocolo_antigo != protocolo: if protocolo_antigo != protocolo:
exist_materia = MateriaLegislativa.objects.filter( exist_materia = MateriaLegislativa.objects.filter(
@ -517,11 +515,9 @@ class TramitacaoForm(ModelForm):
raise ValidationError(msg) raise ValidationError(msg)
if cleaned_data['data_tramitacao'] > timezone.now().date(): if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.error('A data de tramitação informada ({}) não é ' + self.logger.warning('A data de tramitação informada ({}) não é menor ou igual a data de hoje!'
'menor ou igual a data de hoje!'.format(cleaned_data['data_tramitacao'])) .format(cleaned_data['data_tramitacao']))
msg = _( msg = _('A data de tramitação deve ser menor ou igual a data de hoje!')
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
raise ValidationError(msg) raise ValidationError(msg)
if (ultima_tramitacao and if (ultima_tramitacao and
@ -535,10 +531,8 @@ class TramitacaoForm(ModelForm):
if data_enc_form: if data_enc_form:
if data_enc_form < data_tram_form: if data_enc_form < data_tram_form:
msg = _('A data de encaminhamento deve ser ' + msg = _('A data de encaminhamento deve ser maior que a data de tramitação!')
'maior que a data de tramitação!') self.logger.warning("A data de encaminhamento ({}) deve ser maior que a data de tramitação! ({})"
self.logger.error("A data de encaminhamento ({}) deve ser "
"maior que a data de tramitação! ({})"
.format(data_enc_form, data_tram_form)) .format(data_enc_form, data_tram_form))
raise ValidationError(msg) raise ValidationError(msg)
@ -904,8 +898,7 @@ class AnexadaForm(ModelForm):
except ObjectDoesNotExist: except ObjectDoesNotExist:
msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.' msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.'
.format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano'])) .format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano']))
self.logger.error("A matéria a ser anexada não existe no cadastro" self.logger.warning("A matéria a ser anexada não existe no cadastro de matérias legislativas.")
" de matérias legislativas.")
raise ValidationError(msg) raise ValidationError(msg)
materia_principal = self.instance.materia_principal materia_principal = self.instance.materia_principal
@ -1742,11 +1735,9 @@ class TramitacaoEmLoteForm(ModelForm):
if data_enc_form: if data_enc_form:
if data_enc_form < data_tram_form: if data_enc_form < data_tram_form:
self.logger.error('A data de encaminhamento ({}) deve ser ' self.logger.warning('A data de encaminhamento ({}) deve ser maior que a data de tramitação ({})!'
'maior que a data de tramitação ({})!'
.format(data_enc_form, data_tram_form)) .format(data_enc_form, data_tram_form))
msg = _('A data de encaminhamento deve ser ' + msg = _('A data de encaminhamento deve ser maior que a data de tramitação!')
'maior que a data de tramitação!')
raise ValidationError(msg) raise ValidationError(msg)
if data_prazo_form: if data_prazo_form:
@ -2922,3 +2913,10 @@ class MateriaPesquisaSimplesForm(forms.Form):
_('A Data Final não pode ser menor que a Data Inicial')) _('A Data Final não pode ser menor que a Data Inicial'))
return cleaned_data return cleaned_data
class ConfigEtiquetaMateriaLegislativaForms(ModelForm):
class Meta:
model = ConfigEtiquetaMateriaLegislativa
fields = '__all__'

23
sapl/materia/migrations/0068_configetiquetamaterialegislativa.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-05-18 18:14
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0067_auto_20200416_1538'),
]
operations = [
migrations.CreateModel(
name='ConfigEtiquetaMateriaLegislativa',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('largura', models.FloatField(default=5)),
('altura', models.FloatField(default=3)),
],
),
]

20
sapl/materia/migrations/0069_auto_20200518_1519.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-05-18 18:19
from __future__ import unicode_literals
from django.db import migrations
def create_first(apps, schema_editor):
db_alias = schema_editor.connection.alias
Type = apps.get_model("materia", "ConfigEtiquetaMateriaLegislativa")
Type.objects.using(db_alias).create()
class Migration(migrations.Migration):
dependencies = [
('materia', '0068_configetiquetamaterialegislativa'),
]
operations = [
migrations.RunPython(create_first),
]

8
sapl/materia/models.py

@ -1116,3 +1116,11 @@ class MateriaEmTramitacao(models.Model):
def __str__(self): def __str__(self):
return '{}/{}'.format(self.materia, self.tramitacao) return '{}/{}'.format(self.materia, self.tramitacao)
class ConfigEtiquetaMateriaLegislativa(models.Model):
largura = models.FloatField(default=5)
altura = models.FloatField(default=3)
def save(self, *args, **kwargs):
self.id = 1
return super().save(*args, **kwargs)

4
sapl/materia/urls.py

@ -27,7 +27,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
proposicao_texto, recuperar_materia, proposicao_texto, recuperar_materia,
ExcluirTramitacaoEmLoteView, RetornarProposicao, ExcluirTramitacaoEmLoteView, RetornarProposicao,
MateriaPesquisaSimplesView, MateriaPesquisaSimplesView,
DespachoInicialMultiCreateView, get_zip_docacessorios, get_pdf_docacessorios) DespachoInicialMultiCreateView, get_zip_docacessorios,
get_pdf_docacessorios, configEtiquetaMateriaLegislativaCrud)
from sapl.norma.views import NormaPesquisaSimplesView from sapl.norma.views import NormaPesquisaSimplesView
from sapl.protocoloadm.views import ( from sapl.protocoloadm.views import (
FichaPesquisaAdmView, FichaSelecionaAdmView) FichaPesquisaAdmView, FichaSelecionaAdmView)
@ -172,6 +173,7 @@ urlpatterns_sistema = [
url(r'^sistema/materia/status-tramitacao/', url(r'^sistema/materia/status-tramitacao/',
include(StatusTramitacaoCrud.get_urls())), include(StatusTramitacaoCrud.get_urls())),
url(r'^sistema/materia/orgao/', include(OrgaoCrud.get_urls())), url(r'^sistema/materia/orgao/', include(OrgaoCrud.get_urls())),
url(r'^sistema/materia/config-etiqueta-materia-legislativas/',configEtiquetaMateriaLegislativaCrud, name="configEtiquetaMateriaLegislativaCrud"),
] ]
urlpatterns = urlpatterns_impressos + urlpatterns_materia + \ urlpatterns = urlpatterns_impressos + urlpatterns_materia + \

247
sapl/materia/views.py

@ -32,6 +32,8 @@ 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
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.shortcuts import render
from django_filters.views import FilterView from django_filters.views import FilterView
@ -48,7 +50,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm
ConfirmarProposicaoForm, DevolverProposicaoForm, ConfirmarProposicaoForm, DevolverProposicaoForm,
DespachoInicialCreateForm, LegislacaoCitadaForm, DespachoInicialCreateForm, LegislacaoCitadaForm,
MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm, MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm,
TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm) TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm,ConfigEtiquetaMateriaLegislativaForms)
from sapl.norma.models import LegislacaoCitada from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
@ -72,7 +74,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, De
DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao,
Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao, Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao) Tramitacao, UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa)
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@ -736,8 +738,14 @@ class ProposicaoCrud(Crud):
container_field = 'autor__user' container_field = 'autor__user'
class BaseMixin(Crud.BaseMixin): class BaseMixin(Crud.BaseMixin):
list_field_names = ['data_envio', 'data_recebimento', 'descricao', list_field_names = [
'tipo', 'conteudo_gerado_related', 'cancelado', ] 'data_envio',
'data_recebimento',
'descricao',
'tipo',
'conteudo_gerado_related',
'cancelado'
]
class BaseLocalMixin: class BaseLocalMixin:
form_class = ProposicaoForm form_class = ProposicaoForm
@ -751,22 +759,23 @@ class ProposicaoCrud(Crud):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if not self._action_is_valid(request, *args, **kwargs): if not self._action_is_valid(request, *args, **kwargs):
return redirect(reverse('sapl.materia:proposicao_detail', return redirect(reverse('sapl.materia:proposicao_detail', kwargs={'pk': kwargs['pk']}))
kwargs={'pk': kwargs['pk']}))
return super().get(self, request, *args, **kwargs) return super().get(self, request, *args, **kwargs)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if not self._action_is_valid(request, *args, **kwargs): if not self._action_is_valid(request, *args, **kwargs):
return redirect(reverse('sapl.materia:proposicao_detail', return redirect(reverse('sapl.materia:proposicao_detail', kwargs={'pk': kwargs['pk']}))
kwargs={'pk': kwargs['pk']}))
return super().post(self, request, *args, **kwargs) return super().post(self, request, *args, **kwargs)
class DetailView(Crud.DetailView): class DetailView(Crud.DetailView):
layout_key = 'Proposicao' layout_key = 'Proposicao'
permission_required = (RP_DETAIL, 'materia.detail_proposicao_enviada', permission_required = (
RP_DETAIL,
'materia.detail_proposicao_enviada',
'materia.detail_proposicao_devolvida', 'materia.detail_proposicao_devolvida',
'materia.detail_proposicao_incorporada') 'materia.detail_proposicao_incorporada'
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -785,7 +794,6 @@ class ProposicaoCrud(Crud):
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
action = request.GET.get('action', '') action = request.GET.get('action', '')
user = request.user user = request.user
username = user.username username = user.username
@ -802,10 +810,8 @@ class ProposicaoCrud(Crud):
msg_error = _('Proposição já foi enviada e recebida.') msg_error = _('Proposição já foi enviada e recebida.')
elif p.data_envio: elif p.data_envio:
msg_error = _('Proposição já foi enviada.') msg_error = _('Proposição já foi enviada.')
elif not p.texto_original and\ elif not p.texto_original and not p.texto_articulado.exists():
not p.texto_articulado.exists(): msg_error = _('Proposição não possui nenhum tipo de Texto associado.')
msg_error = _('Proposição não possui nenhum tipo de '
'Texto associado.')
else: else:
if p.texto_articulado.exists(): if p.texto_articulado.exists():
ta = p.texto_articulado.first() ta = p.texto_articulado.first()
@ -813,8 +819,7 @@ class ProposicaoCrud(Crud):
ta.editing_locked = True ta.editing_locked = True
ta.save() ta.save()
receber_recibo = BaseAppConfig.attr( receber_recibo = BaseAppConfig.attr('receber_recibo_proposicao')
'receber_recibo_proposicao')
if not receber_recibo: if not receber_recibo:
ta = p.texto_articulado.first() ta = p.texto_articulado.first()
@ -824,45 +829,39 @@ class ProposicaoCrud(Crud):
p.data_envio = timezone.now() p.data_envio = timezone.now()
p.save() p.save()
messages.success(request, _( messages.success(request, _('Proposição enviada com sucesso.'))
'Proposição enviada com sucesso.'))
try: try:
self.logger.debug("user=" + username + ". Tentando obter número do objeto MateriaLegislativa com " self.logger.debug("User={}. Tentando obter número do objeto MateriaLegislativa "
"atributos tipo={} e ano={}." "com atributos tipo={} e ano={}."
.format(p.tipo.tipo_conteudo_related, p.ano)) .format(username, p.tipo.tipo_conteudo_related, p.ano))
if p.numero_materia_futuro: if p.numero_materia_futuro:
numero = p.numero_materia_futuro numero = p.numero_materia_futuro
else: else:
numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related,
ano=p.ano).last().numero + 1 ano=p.ano).last().numero + 1
messages.success(request, _( messages.success(request, _("{}: nº {} de {} <br>Atenção! Este número é apenas um provável "
'%s : nº %s de %s <br>Atenção! Este número é apenas um provável ' "número que pode não corresponder com a realidade"
'número que pode não corresponder com a realidade' .format(p.tipo, numero, p.ano)))
% (p.tipo, numero, p.ano)))
except ValueError as e: except ValueError as e:
self.logger.error( self.logger.warning("User=" + username + ". " + str(e))
"user=" + username + "." + str(e))
pass pass
except AttributeError as e: except AttributeError as e:
self.logger.error( self.logger.warning("User=" + username + ". " + str(e))
"user=" + username + "." + str(e))
pass pass
except TypeError as e: except TypeError as e:
self.logger.error( self.logger.warning("User=" + username + ". " + str(e))
"user=" + username + "." + str(e))
pass pass
elif action == 'return': elif action == 'return':
if not p.data_envio: if not p.data_envio:
self.logger.error( self.logger.warning("User={}. Proposição (numero={}) ainda não foi enviada."
"user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao)) .format(username, p.numero_proposicao))
msg_error = _('Proposição ainda não foi enviada.') msg_error = _('Proposição ainda não foi enviada.')
elif p.data_recebimento: elif p.data_recebimento:
self.logger.error("user=" + username + ". Proposição (numero={}) já foi recebida, não é " self.logger.warning("User={}. Proposição (numero={}) já foi recebida, "
"possível retorná-la.".format(p.numero_proposicao)) "não é possível retorná-la.".format(username, p.numero_proposicao))
msg_error = _('Proposição já foi recebida, não é ' msg_error = _('Proposição já foi recebida, não é possível retorná-la.')
'possível retorná-la.')
else: else:
p.data_envio = None p.data_envio = None
p.save() p.save()
@ -871,27 +870,24 @@ class ProposicaoCrud(Crud):
ta.privacidade = STATUS_TA_PRIVATE ta.privacidade = STATUS_TA_PRIVATE
ta.editing_locked = False ta.editing_locked = False
ta.save() ta.save()
self.logger.info( self.logger.info("User={}. Proposição (numero={}) Retornada com sucesso."
"user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao)) .format(username, p.numero_proposicao))
messages.success(request, _( messages.success(request, _('Proposição Retornada com sucesso.'))
'Proposição Retornada com sucesso.'))
if msg_error: if msg_error:
messages.error(request, msg_error) messages.error(request, msg_error)
# retornar redirecionando para limpar a variavel action # retornar redirecionando para limpar a variavel action
return redirect(reverse('sapl.materia:proposicao_detail', return redirect(reverse('sapl.materia:proposicao_detail', kwargs={'pk': kwargs['pk']}))
kwargs={'pk': kwargs['pk']}))
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
username = request.user.username username = request.user.username
try: try:
self.logger.debug( self.logger.debug("User={}. Tentando obter objeto Proposicao com pk={}".format(username, kwargs['pk']))
"user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk']))
p = Proposicao.objects.get(id=kwargs['pk']) p = Proposicao.objects.get(id=kwargs['pk'])
except Exception as e: except Exception as e:
self.logger.error( self.logger.warning("User={}. Erro ao obter proposicao com pk={}. Retornando 404. {}"
"user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e)) .format(username, kwargs['pk'], str(e)))
raise Http404() raise Http404()
if not self.has_permission(): if not self.has_permission():
@ -901,47 +897,38 @@ class ProposicaoCrud(Crud):
if not p.data_envio and not p.data_devolucao: if not p.data_envio and not p.data_devolucao:
raise Http404() raise Http404()
if p.data_devolucao and not request.user.has_perm( if p.data_devolucao and not request.user.has_perm('materia.detail_proposicao_devolvida'):
'materia.detail_proposicao_devolvida'):
raise Http404() raise Http404()
if p.data_envio and not p.data_recebimento\ if p.data_envio and not p.data_recebimento \
and not request.user.has_perm( and not request.user.has_perm('materia.detail_proposicao_enviada'):
'materia.detail_proposicao_enviada'):
raise Http404() raise Http404()
if p.data_envio and p.data_recebimento\ if p.data_envio and p.data_recebimento \
and not request.user.has_perm( and not request.user.has_perm('materia.detail_proposicao_incorporada'):
'materia.detail_proposicao_incorporada'):
raise Http404() raise Http404()
return super(PermissionRequiredMixin, self).dispatch( return super(PermissionRequiredMixin, self).dispatch(request, *args, **kwargs)
request, *args, **kwargs)
class DeleteView(BaseLocalMixin, Crud.DeleteView): class DeleteView(BaseLocalMixin, Crud.DeleteView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def _action_is_valid(self, request, *args, **kwargs): def _action_is_valid(self, request, *args, **kwargs):
proposicao = Proposicao.objects.filter( proposicao = Proposicao.objects.filter(id=kwargs['pk']).values_list('data_envio', 'data_recebimento')
id=kwargs['pk']).values_list(
'data_envio', 'data_recebimento')
username = request.user.username username = request.user.username
if proposicao: if proposicao:
if proposicao[0][0] and proposicao[0][1]: if proposicao[0][0] and proposicao[0][1]:
self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada e recebida." self.logger.warning("User={}. Proposição (id={}) já foi enviada e recebida."
"Não pode mais ser excluida.".format(kwargs['pk'])) "Não pode mais ser excluida.".format(username, kwargs['pk']))
msg = _('Proposição já foi enviada e recebida.' msg = _('Proposição já foi enviada e recebida. Não pode mais ser excluida.')
'Não pode mais ser excluida.')
elif proposicao[0][0] and not proposicao[0][1]: elif proposicao[0][0] and not proposicao[0][1]:
self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada mas ainda não recebida " self.logger.warning("""\
"pelo protocolo. Use a opção Recuperar Proposição " User={}. Proposição (id={}) foi enviada, mas ainda não recebida pelo protocolo. \
"para depois excluí-la.".format(kwargs['pk'])) Use a opção Recuperar Proposição para depois excluí-la.""".format(username, kwargs['pk']))
msg = _('Proposição já foi enviada mas ainda não recebida ' msg = _("Proposição já foi enviada mas ainda não recebida pelo protocolo. "
'pelo protocolo. Use a opção Recuperar Proposição ' "Use a opção Recuperar Proposição para depois excluí-la.")
'para depois excluí-la.')
if proposicao[0][0] or proposicao[0][1]: if proposicao[0][0] or proposicao[0][1]:
messages.error(request, msg) messages.error(request, msg)
@ -949,20 +936,18 @@ class ProposicaoCrud(Crud):
return True return True
class UpdateView(BaseLocalMixin, Crud.UpdateView): class UpdateView(BaseLocalMixin, Crud.UpdateView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
form_class = ProposicaoForm form_class = ProposicaoForm
def form_valid(self, form): def form_valid(self, form):
tz = timezone.get_current_timezone() tz = timezone.get_current_timezone()
objeto_antigo = Proposicao.objects.get( objeto_antigo = Proposicao.objects.get(pk=self.kwargs['pk'])
pk=self.kwargs['pk']
)
dict_objeto_antigo = objeto_antigo.__dict__ dict_objeto_antigo = objeto_antigo.__dict__
tipo_texto = self.request.POST.get('tipo_texto', '') tipo_texto = self.request.POST.get('tipo_texto', '')
if tipo_texto=='D' and objeto_antigo.texto_articulado.exists() or tipo_texto=='T' and not objeto_antigo.texto_articulado.exists(): if tipo_texto == 'D' and objeto_antigo.texto_articulado.exists()\
or tipo_texto == 'T' and not objeto_antigo.texto_articulado.exists():
self.object.user = self.request.user self.object.user = self.request.user
self.object.ip = get_client_ip(self.request) self.object.ip = get_client_ip(self.request)
self.object.ultima_edicao = tz.localize(datetime.now()) self.object.ultima_edicao = tz.localize(datetime.now())
@ -972,7 +957,10 @@ class ProposicaoCrud(Crud):
dict_objeto_novo = self.object.__dict__ dict_objeto_novo = self.object.__dict__
atributos = [ atributos = [
'tipo_id', 'descricao', 'observacao', 'texto_original', 'tipo_id',
'descricao',
'observacao',
'texto_original',
'materia_de_vinculo_id' 'materia_de_vinculo_id'
] ]
@ -987,27 +975,22 @@ class ProposicaoCrud(Crud):
return super().form_valid(form) return super().form_valid(form)
def _action_is_valid(self, request, *args, **kwargs): def _action_is_valid(self, request, *args, **kwargs):
proposicao = Proposicao.objects.filter(id=kwargs['pk']).values_list('data_envio', 'data_recebimento')
proposicao = Proposicao.objects.filter(
id=kwargs['pk']).values_list(
'data_envio', 'data_recebimento')
username = request.user.username username = request.user.username
if proposicao: if proposicao:
msg = '' msg = ''
if proposicao[0][0] and proposicao[0][1]: if proposicao[0][0] and proposicao[0][1]:
self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada e recebida.' self.logger.warning('User={}. Proposição (id={}) já foi enviada e recebida. '
'Não pode mais ser editada'.format(kwargs['pk'])) 'Não pode mais ser editada'.format(username, kwargs['pk']))
msg = _('Proposição já foi enviada e recebida.' msg = _('Proposição já foi enviada e recebida. Não pode mais ser editada')
'Não pode mais ser editada')
elif proposicao[0][0] and not proposicao[0][1]: elif proposicao[0][0] and not proposicao[0][1]:
self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada mas ainda não recebida ' self.logger.warning("""\
'pelo protocolo. Use a opção Recuperar Proposição ' User={}. Proposição (id={}) foi enviada, mas ainda não recebida pelo protocolo. \
'para voltar para edição.'.format(kwargs['pk'])) Use a opção Recuperar Proposição para voltar para edição.""".format(username, kwargs['pk']))
msg = _('Proposição já foi enviada mas ainda não recebida ' msg = _("Proposição já foi enviada, mas ainda não recebida pelo protocolo. "
'pelo protocolo. Use a opção Recuperar Proposição ' "Use a opção Recuperar Proposição para voltar para edição.")
'para voltar para edição.')
if proposicao[0][0] or proposicao[0][1]: if proposicao[0][0] or proposicao[0][1]:
messages.error(request, msg) messages.error(request, msg)
@ -1015,22 +998,17 @@ class ProposicaoCrud(Crud):
return True return True
def get_success_url(self): def get_success_url(self):
tipo_texto = self.request.POST.get('tipo_texto', '') tipo_texto = self.request.POST.get('tipo_texto', '')
username = self.request.user.username username = self.request.user.username
if tipo_texto == 'T': if tipo_texto == 'T':
messages.info(self.request, messages.info(self.request, _("""\
_('Sempre que uma Proposição é inclusa ou ' Sempre que uma Proposição é inclusa ou alterada e a opção "Texto Articulado " for marcada, \
'alterada e a opção "Texto Articulado " for ' você será redirecionado para a edição do Texto Eletrônico."""))
'marcada, você será redirecionado para a ' self.logger.debug("""\
'edição do Texto Eletrônico.')) User={}. Sempre que uma Proposição é inclusa ou alterada e a opção "Texto Articulado" for marcada, \
self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou ' você será redirecionado para a edição do Texto Eletrônico.""".format(username))
'alterada e a opção "Texto Articulado " for ' return reverse('sapl.materia:proposicao_ta', kwargs={'pk': self.object.pk})
'marcada, você será redirecionado para a '
'edição do Texto Eletrônico.')
return reverse('sapl.materia:proposicao_ta',
kwargs={'pk': self.object.pk})
else: else:
return Crud.UpdateView.get_success_url(self) return Crud.UpdateView.get_success_url(self)
@ -1061,43 +1039,38 @@ class ProposicaoCrud(Crud):
username = self.request.user.username username = self.request.user.username
if tipo_texto == 'T': if tipo_texto == 'T':
messages.info(self.request, messages.info(self.request, _("""\
_('Sempre que uma Proposição é inclusa ou ' Sempre que uma Proposição é inclusa ou alterada e a opção "Texto Articulado" for marcada, \
'alterada e a opção "Texto Articulado " for ' você será redirecionado para o Texto Eletrônico. \
'marcada, você será redirecionado para o ' Use a opção "Editar Texto" para construir seu texto."""))
'Texto Eletrônico. Use a opção "Editar Texto" ' self.logger.debug("""\
'para construir seu texto.')) User={}. Sempre que uma Proposição é inclusa ou alterada e a opção "Texto Articulado" for marcada, \
self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou ' você será redirecionado para o Texto Eletrônico. \
'alterada e a opção "Texto Articulado " for ' Use a opção "Editar Texto" para construir seu texto.""".format(username))
'marcada, você será redirecionado para o ' return reverse('sapl.materia:proposicao_ta', kwargs={'pk': self.object.pk})
'Texto Eletrônico. Use a opção "Editar Texto" '
'para construir seu texto.')
return reverse('sapl.materia:proposicao_ta',
kwargs={'pk': self.object.pk})
else: else:
return Crud.CreateView.get_success_url(self) return Crud.CreateView.get_success_url(self)
class ListView(Crud.ListView): class ListView(Crud.ListView):
ordering = ['-data_envio', 'descricao'] ordering = [
'-data_envio',
'descricao'
]
def get_rows(self, object_list): def get_rows(self, object_list):
for obj in object_list: for obj in object_list:
if obj.data_recebimento is None: if obj.data_recebimento is None:
obj.data_recebimento = 'Não recebida'\ obj.data_recebimento = 'Não recebida' if obj.data_envio else 'Não enviada'
if obj.data_envio else 'Não enviada'
else: else:
obj.data_recebimento = timezone.localtime( obj.data_recebimento = timezone.localtime(obj.data_recebimento)
obj.data_recebimento) obj.data_recebimento = formats.date_format(obj.data_recebimento, "DATETIME_FORMAT")
obj.data_recebimento = formats.date_format(
obj.data_recebimento, "DATETIME_FORMAT")
if obj.data_envio is None: if obj.data_envio is None:
obj.data_envio = 'Em elaboração...' obj.data_envio = 'Em elaboração...'
else: else:
obj.data_envio = timezone.localtime(obj.data_envio) obj.data_envio = timezone.localtime(obj.data_envio)
obj.data_envio = formats.date_format( obj.data_envio = formats.date_format(obj.data_envio, "DATETIME_FORMAT")
obj.data_envio, "DATETIME_FORMAT")
return [self._as_row(obj) for obj in object_list] return [self._as_row(obj) for obj in object_list]
@ -1415,7 +1388,6 @@ class TramitacaoCrud(MasterDetailCrud):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['user'] = self.request.user
return context return context
@ -2757,11 +2729,11 @@ def create_zip_docacessorios(materia):
def get_zip_docacessorios(request, pk): def get_zip_docacessorios(request, pk):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
username = request.user.username username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username
materia = get_object_or_404(MateriaLegislativa, pk=pk) materia = get_object_or_404(MateriaLegislativa, pk=pk)
try: try:
external_name, zipfilename = create_zip_docacessorios(materia) external_name, zipfilename = create_zip_docacessorios(materia)
logger.info("user= {}. Gerou o zip compilado de documento acessorios") logger.info("user= {}. Gerou o zip compilado de documento acessorios".format(username))
except FileNotFoundError: except FileNotFoundError:
logger.error("user= {}.Não há arquivos cadastrados".format(username)) logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg=_('Não há arquivos cadastrados nesses documentos acessórios.') msg=_('Não há arquivos cadastrados nesses documentos acessórios.')
@ -2822,10 +2794,10 @@ def create_pdf_docacessorios(materia):
def get_pdf_docacessorios(request, pk): def get_pdf_docacessorios(request, pk):
materia = get_object_or_404(MateriaLegislativa, pk=pk) materia = get_object_or_404(MateriaLegislativa, pk=pk)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
username = request.user.username username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username
try: try:
external_name, pdffilename = create_pdf_docacessorios(materia) external_name, pdffilename = create_pdf_docacessorios(materia)
logger.info("user= {}. Gerou o pdf compilado de documento acessorios") logger.info("user= {}. Gerou o pdf compilado de documento acessorios".format(username))
except FileNotFoundError: except FileNotFoundError:
logger.error("user= {}.Não há arquivos cadastrados".format(username)) logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg=_('Não há arquivos cadastrados nesses documentos acessórios.') msg=_('Não há arquivos cadastrados nesses documentos acessórios.')
@ -2853,3 +2825,16 @@ def get_pdf_docacessorios(request, pk):
% external_name) % external_name)
return response return response
def configEtiquetaMateriaLegislativaCrud(request):
config = ConfigEtiquetaMateriaLegislativa.objects.last()
if request.method == "POST":
form = ConfigEtiquetaMateriaLegislativaForms(request.POST, instance=config)
if form.is_valid():
config = form.save(commit=False)
config.published_date = timezone.now()
config.save()
return redirect('materia/config_etiqueta_materia.html', {'form': form})
else:
form = ConfigEtiquetaMateriaLegislativaForms(instance=config)
return render(request, 'materia/config_etiqueta_materia.html', {'form': form})

2
sapl/norma/forms.py

@ -163,7 +163,7 @@ class NormaJuridicaForm(FileFieldCheckMixin, ModelForm):
numero=cleaned_data['numero'], numero=cleaned_data['numero'],
tipo=cleaned_data['tipo']).exists() tipo=cleaned_data['tipo']).exists()
if norma: if norma:
self.logger.error("Já existe uma norma de mesmo Tipo ({}), Ano ({}) " self.logger.warning("Já existe uma norma de mesmo Tipo ({}), Ano ({}) "
"e Número ({}) no sistema." "e Número ({}) no sistema."
.format(cleaned_data['tipo'], cleaned_data['ano'], cleaned_data['numero'])) .format(cleaned_data['tipo'], cleaned_data['ano'], cleaned_data['numero']))
raise ValidationError("Já existe uma norma de mesmo Tipo, Ano " raise ValidationError("Já existe uma norma de mesmo Tipo, Ano "

8
sapl/norma/views.py

@ -258,7 +258,7 @@ class NormaCrud(Crud):
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
norma = NormaJuridica.objects.get(id=self.kwargs['pk']) norma = NormaJuridica.objects.select_related("materia").get(id=self.kwargs['pk'])
if norma.materia: if norma.materia:
initial['tipo_materia'] = norma.materia.tipo initial['tipo_materia'] = norma.materia.tipo
initial['ano_materia'] = norma.materia.ano initial['ano_materia'] = norma.materia.ano
@ -267,9 +267,7 @@ class NormaCrud(Crud):
return initial return initial
def form_valid(self, form): def form_valid(self, form):
norma_antiga = NormaJuridica.objects.get( norma_antiga = NormaJuridica.objects.get(pk=self.kwargs['pk'])
pk=self.kwargs['pk']
)
# Feito desta forma para que sejam materializados os assuntos # Feito desta forma para que sejam materializados os assuntos
# antigos # antigos
@ -329,7 +327,7 @@ def recuperar_norma(request):
response = JsonResponse({'ementa': norma.ementa, response = JsonResponse({'ementa': norma.ementa,
'id': norma.id}) 'id': norma.id})
except ObjectDoesNotExist: except ObjectDoesNotExist:
logger.error('user=' + username + '. NormaJuridica buscada (tipo={}, ano={}, numero={}) não existe. ' logger.warning('user=' + username + '. NormaJuridica buscada (tipo={}, ano={}, numero={}) não existe. '
'Definida com ementa vazia e id 0.'.format(tipo, ano, numero)) 'Definida com ementa vazia e id 0.'.format(tipo, ano, numero))
response = JsonResponse({'ementa': '', 'id': 0}) response = JsonResponse({'ementa': '', 'id': 0})

11
sapl/parlamentares/forms.py

@ -216,6 +216,17 @@ class ParlamentarForm(FileFieldCheckMixin, ModelForm):
'biografia': forms.Textarea( 'biografia': forms.Textarea(
attrs={'id': 'texto-rico'})} attrs={'id': 'texto-rico'})}
def save(self, commit=True):
parlamentar = super().save()
autor = parlamentar.autor.first()
usuario = autor.user if autor else None
if autor and usuario:
usuario.is_active = parlamentar.ativo
usuario.save()
return parlamentar
class ParlamentarFilterSet(django_filters.FilterSet): class ParlamentarFilterSet(django_filters.FilterSet):
nome_parlamentar = django_filters.CharFilter( nome_parlamentar = django_filters.CharFilter(

3
sapl/parlamentares/views.py

@ -585,8 +585,7 @@ class ParlamentarCrud(Crud):
". Tentando obter id da legislatura.") ". Tentando obter id da legislatura.")
return int(self.request.GET['pk']) return int(self.request.GET['pk'])
except: except:
self.logger.error( self.logger.warning("User=" + username + ". Legislatura não possui ID. Buscando em todas as entradas.")
"user=" + username + ". Legislatura não possui ID. Buscando em todas as entradas.")
legislaturas = Legislatura.objects.all() legislaturas = Legislatura.objects.all()
for l in legislaturas: for l in legislaturas:
if l.atual(): if l.atual():

21
sapl/protocoloadm/migrations/0033_auto_20200708_1312.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2020-07-08 16:12
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0032_auto_20200416_1538'),
]
operations = [
migrations.AlterField(
model_name='protocolo',
name='autor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='base.Autor'),
),
]

61
sapl/protocoloadm/models.py

@ -53,43 +53,55 @@ def texto_upload_path(instance, filename):
@reversion.register() @reversion.register()
class Protocolo(models.Model): class Protocolo(models.Model):
numero = models.PositiveIntegerField( numero = models.PositiveIntegerField(
blank=False, null=False, verbose_name=_('Número de Protocolo')) blank=False,
ano = models.PositiveSmallIntegerField(blank=False, null=False,
verbose_name=_('Número de Protocolo'))
ano = models.PositiveSmallIntegerField(
blank=False,
null=False, null=False,
choices=RANGE_ANOS, choices=RANGE_ANOS,
verbose_name=_('Ano do Protocolo')) verbose_name=_('Ano do Protocolo'))
data = models.DateField(null=True, blank=True, data = models.DateField(
null=True,
blank=True,
verbose_name=_('Data do Protocolo'), verbose_name=_('Data do Protocolo'),
help_text=_('Informado manualmente')) help_text=_('Informado manualmente'))
hora = models.TimeField(null=True, blank=True, hora = models.TimeField(
null=True,
blank=True,
verbose_name=_('Hora do Protocolo'), verbose_name=_('Hora do Protocolo'),
help_text=_('Informado manualmente')) help_text=_('Informado manualmente'))
timestamp_data_hora_manual = models.DateTimeField(default=timezone.now) timestamp_data_hora_manual = models.DateTimeField(default=timezone.now)
user_data_hora_manual = models.CharField( user_data_hora_manual = models.CharField(
max_length=256, blank=True, max_length=256,
blank=True,
verbose_name=_('IP'), verbose_name=_('IP'),
help_text=_('Usuário que está realizando Protocolo e informando ' help_text=_('Usuário que está realizando Protocolo e informando data e hora manualmente.'))
'data e hora manualmente.'))
ip_data_hora_manual = models.CharField( ip_data_hora_manual = models.CharField(
max_length=256, blank=True, max_length=256,
blank=True,
verbose_name=_('IP'), verbose_name=_('IP'),
help_text=_('Endereço IP da estação de trabalho ' help_text=_('Endereço IP da estação de trabalho do usuário que está realizando Protocolo e '
'do usuário que está realizando Protocolo e informando ' 'informando data e hora manualmente.'))
'data e hora manualmente.')) # Não foi utilizado auto_now_add=True em timestamp porque ele usa datetime.now que não é timezone aware.
# Não foi utilizado auto_now_add=True em timestamp porque
# ele usa datetime.now que não é timezone aware.
timestamp = models.DateTimeField( timestamp = models.DateTimeField(
default=timezone.now, null=True, blank=True) null=True,
blank=True,
default=timezone.now)
tipo_protocolo = models.PositiveIntegerField( tipo_protocolo = models.PositiveIntegerField(
blank=True, null=True, verbose_name=_('Tipo de Protocolo')) blank=True,
null=True,
verbose_name=_('Tipo de Protocolo'))
tipo_processo = models.PositiveIntegerField() tipo_processo = models.PositiveIntegerField()
interessado = models.CharField( interessado = models.CharField(
max_length=200, blank=True, verbose_name=_('Interessado')) max_length=200,
autor = models.ForeignKey(Autor, blank=True,
verbose_name=_('Interessado'))
autor = models.ForeignKey(
Autor,
blank=True, blank=True,
null=True, null=True,
on_delete=models.PROTECT) on_delete=models.SET_NULL)
assunto_ementa = models.TextField(blank=True) assunto_ementa = models.TextField(blank=True)
tipo_documento = models.ForeignKey( tipo_documento = models.ForeignKey(
TipoDocumentoAdministrativo, TipoDocumentoAdministrativo,
@ -104,14 +116,17 @@ class Protocolo(models.Model):
on_delete=models.PROTECT, on_delete=models.PROTECT,
verbose_name=_('Tipo de Matéria')) verbose_name=_('Tipo de Matéria'))
numero_paginas = models.PositiveIntegerField( numero_paginas = models.PositiveIntegerField(
blank=True, null=True, verbose_name=_('Número de Páginas')) blank=True,
observacao = models.TextField( null=True,
blank=True, verbose_name=_('Observação')) verbose_name=_('Número de Páginas'))
observacao = models.TextField(blank=True, verbose_name=_('Observação'))
anulado = models.BooleanField(default=False) anulado = models.BooleanField(default=False)
user_anulacao = models.CharField(max_length=20, blank=True) user_anulacao = models.CharField(max_length=20, blank=True)
ip_anulacao = models.CharField(max_length=15, blank=True) ip_anulacao = models.CharField(max_length=15, blank=True)
justificativa_anulacao = models.CharField( justificativa_anulacao = models.CharField(
max_length=260, blank=True, verbose_name=_('Motivo')) max_length=260,
blank=True,
verbose_name=_('Motivo'))
timestamp_anulacao = models.DateTimeField(blank=True, null=True) timestamp_anulacao = models.DateTimeField(blank=True, null=True)
class Meta: class Meta:

4
sapl/protocoloadm/views.py

@ -1368,9 +1368,9 @@ class TramitacaoAdmCrud(MasterDetailCrud):
if tramitacao.pk != ultima_tramitacao.pk: if tramitacao.pk != ultima_tramitacao.pk:
username = request.user.username username = request.user.username
self.logger.error("user=" + username + ". Não é possível deletar a tramitação de pk={}. " self.logger.warning("User={}. Não é possível deletar a tramitação de pk={}. "
"Somente a última tramitação (pk={}) pode ser deletada!." "Somente a última tramitação (pk={}) pode ser deletada!."
.format(tramitacao.pk, ultima_tramitacao.pk)) .format(username, 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)

8
sapl/relatorios/urls.py

@ -6,7 +6,7 @@ from .views import (relatorio_capa_processo,
relatorio_etiqueta_protocolo, relatorio_materia, relatorio_etiqueta_protocolo, relatorio_materia,
relatorio_ordem_dia, relatorio_pauta_sessao, relatorio_ordem_dia, relatorio_pauta_sessao,
relatorio_protocolo, relatorio_sessao_plenaria, relatorio_protocolo, relatorio_sessao_plenaria,
resumo_ata_pdf, relatorio_sessao_plenaria_pdf) resumo_ata_pdf, relatorio_sessao_plenaria_pdf, etiqueta_materia_legislativa)
app_name = AppConfig.name app_name = AppConfig.name
@ -21,8 +21,8 @@ urlpatterns = [
name='relatorio_documento_administrativo'), name='relatorio_documento_administrativo'),
url(r'^relatorios/espelho$', relatorio_espelho, url(r'^relatorios/espelho$', relatorio_espelho,
name='relatorio_espelho'), name='relatorio_espelho'),
url(r'^relatorios/(?P<pk>\d+)/sessao-plenaria$', #url(r'^relatorios/(?P<pk>\d+)/sessao-plenaria$',
relatorio_sessao_plenaria, name='relatorio_sessao_plenaria'), # relatorio_sessao_plenaria, name='relatorio_sessao_plenaria'),
url(r'^relatorios/protocolo$', url(r'^relatorios/protocolo$',
relatorio_protocolo, name='relatorio_protocolo'), relatorio_protocolo, name='relatorio_protocolo'),
url(r'^relatorios/(?P<nro>\d+)/(?P<ano>\d+)/etiqueta-protocolo$', url(r'^relatorios/(?P<nro>\d+)/(?P<ano>\d+)/etiqueta-protocolo$',
@ -33,4 +33,6 @@ urlpatterns = [
resumo_ata_pdf, name='resumo_ata_pdf'), resumo_ata_pdf, name='resumo_ata_pdf'),
url(r'^relatorios/(?P<pk>\d+)/sessao-plenaria-pdf$', url(r'^relatorios/(?P<pk>\d+)/sessao-plenaria-pdf$',
relatorio_sessao_plenaria_pdf, name='relatorio_sessao_plenaria_pdf'), relatorio_sessao_plenaria_pdf, name='relatorio_sessao_plenaria_pdf'),
url(r'^relatorios/(?P<pk>\d+)/etiqueta-materia-legislativa$',
etiqueta_materia_legislativa, name='etiqueta_materia_legislativa'),
] ]

59
sapl/relatorios/views.py

@ -3,6 +3,7 @@ import html
import logging import logging
import re import re
import tempfile import tempfile
import unidecode
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
@ -15,7 +16,7 @@ from sapl.settings import MEDIA_URL
from sapl.base.models import Autor, CasaLegislativa 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, ConfigEtiquetaMateriaLegislativa)
from sapl.parlamentares.models import CargoMesa, Filiacao, Parlamentar from sapl.parlamentares.models import CargoMesa, Filiacao, Parlamentar
from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo, from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
TramitacaoAdministrativo) TramitacaoAdministrativo)
@ -26,7 +27,7 @@ from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
SessaoPlenariaPresenca, OcorrenciaSessao, SessaoPlenariaPresenca, OcorrenciaSessao,
RegistroVotacao, VotoParlamentar, OradorOrdemDia, TipoExpediente, ResumoOrdenacao) RegistroVotacao, VotoParlamentar, OradorOrdemDia, TipoExpediente, ResumoOrdenacao)
from sapl.settings import STATIC_ROOT from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data, create_barcode
from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora, from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora,
get_presenca_sessao, get_expedientes, get_presenca_sessao, get_expedientes,
@ -601,6 +602,7 @@ def get_sessao_plenaria(sessao, casa):
str(materia.ano)), str(materia.ano)),
"des_numeracao": ' ', "des_numeracao": ' ',
"des_turno": get_turno(materia)[0], "des_turno": get_turno(materia)[0],
"situacao": materia.materiaemtramitacao_set.first().tramitacao.status,
"txt_ementa": str(materia.ementa), "txt_ementa": str(materia.ementa),
"materia_observacao": materia.observacao, "materia_observacao": materia.observacao,
"ordem_observacao": expediente_materia.observacao, "ordem_observacao": expediente_materia.observacao,
@ -705,7 +707,8 @@ def get_sessao_plenaria(sessao, casa):
"txt_ementa": html.unescape(materia.ementa), "txt_ementa": html.unescape(materia.ementa),
"materia_observacao": materia.observacao, "materia_observacao": materia.observacao,
"ordem_observacao": html.unescape(votacao.observacao), "ordem_observacao": html.unescape(votacao.observacao),
"nom_autor": '' "nom_autor": '',
"situacao": materia.materiaemtramitacao_set.first().tramitacao.status
}) })
autoria = materia.autoria_set.all() autoria = materia.autoria_set.all()
@ -1005,6 +1008,8 @@ def relatorio_etiqueta_protocolo(request, nro, ano):
protocolo = Protocolo.objects.filter(numero=nro, ano=ano) protocolo = Protocolo.objects.filter(numero=nro, ano=ano)
m = MateriaLegislativa.objects.filter(numero_protocolo=nro,ano=ano)
protocolo_data = get_etiqueta_protocolos(protocolo) protocolo_data = get_etiqueta_protocolos(protocolo)
pdf = pdf_etiqueta_protocolo_gerar.principal(imagem, pdf = pdf_etiqueta_protocolo_gerar.principal(imagem,
@ -1502,3 +1507,51 @@ def relatorio_sessao_plenaria_pdf(request, pk):
response.write(pdf_file) response.write(pdf_file)
return response return response
def gera_etiqueta_ml(materia_legislativa, base_url):
confg = ConfigEtiquetaMateriaLegislativa.objects.first()
ml_info = unidecode.unidecode("{}/{}-{}".format(materia_legislativa.numero,
materia_legislativa.ano,
materia_legislativa.tipo.sigla))
base64_data = create_barcode(ml_info, 100, 500)
barcode = 'data:image/png;base64,{0}'.format(base64_data)
max_ementa_size = 240
ementa = materia_legislativa.ementa
ementa = ementa if len(ementa) < max_ementa_size else ementa[:max_ementa_size]+"..."
context = {
'numero': materia_legislativa.numero,
'ano': materia_legislativa.ano,
'tipo': materia_legislativa.tipo,
'data_apresentacao':materia_legislativa.data_apresentacao,
'autores': materia_legislativa.autores.all(),
'ementa':ementa,
'largura': confg.largura,
'altura':confg.largura,
'barcode': barcode
}
main_template = render_to_string('relatorios/etiqueta_materia_legislativa.html', context)
html = HTML(base_url=base_url, string=main_template)
main_doc = html.render(stylesheets=[CSS(string="@page {{size: {}cm {}cm;}}".format(confg.largura,confg.altura))])
pdf_file = main_doc.write_pdf()
return pdf_file
def etiqueta_materia_legislativa(request, pk):
base_url = request.build_absolute_uri()
materia_legislativa = MateriaLegislativa.objects.get(pk=pk)
pdf_file = gera_etiqueta_ml(materia_legislativa, base_url)
response = HttpResponse(content_type='application/pdf;')
response['Content-Disposition'] = 'inline; filename=etiqueta.pdf'
response['Content-Transfer-Encoding'] = 'binary'
response.write(pdf_file)
return response

1
sapl/rules/map_rules.py

@ -258,6 +258,7 @@ rules_group_geral = {
(materia.Parecer, __base__, __perms_publicas__), (materia.Parecer, __base__, __perms_publicas__),
(materia.StatusTramitacao, __base__, __perms_publicas__), (materia.StatusTramitacao, __base__, __perms_publicas__),
(materia.UnidadeTramitacao, __base__, __perms_publicas__), (materia.UnidadeTramitacao, __base__, __perms_publicas__),
(materia.ConfigEtiquetaMateriaLegislativa, __base__, set()),
(norma.AssuntoNorma, __base__, __perms_publicas__), (norma.AssuntoNorma, __base__, __perms_publicas__),

158
sapl/sessao/views.py

@ -29,7 +29,7 @@ from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
PermissionRequiredForAppCrudMixin, make_pagination) PermissionRequiredForAppCrudMixin, make_pagination)
from sapl.materia.forms import filtra_tramitacao_status from sapl.materia.forms import filtra_tramitacao_status
from sapl.materia.models import (Autoria, TipoMateriaLegislativa, from sapl.materia.models import (Autoria, TipoMateriaLegislativa,
Tramitacao) Tramitacao, MateriaEmTramitacao)
from sapl.materia.views import MateriaLegislativaPesquisaView from sapl.materia.views import MateriaLegislativaPesquisaView
from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato,
Parlamentar, SessaoLegislativa) Parlamentar, SessaoLegislativa)
@ -228,19 +228,23 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
if t[0] == tramitacao.turno: if t[0] == tramitacao.turno:
turno = t[1] turno = t[1]
break break
situacao = MateriaEmTramitacao.objects.select_related("materia", "tramitacao")\
.filter(materia=materia).first().tramitacao.status
title_materia = """<a id=id%s href=%s>%s</a> </br> title_materia = """<a id=id%s href=%s>%s</a> </br>
<b>Processo:</b> %s </br> <b>Processo:</b> %s </br>
<b>Autor:</b> %s </br> <b>Autor:</b> %s </br>
<b>Protocolo:</b> %s </br> <b>Protocolo:</b> %s </br>
<b>Turno:</b> %s </br> <b>Turno:</b> %s </br>
<b>Situação:</b> %s </br>
""" % (obj.materia.id, """ % (obj.materia.id,
url_materia, url_materia,
row[1][0], row[1][0],
numeracao if numeracao else '', numeracao if numeracao else '',
autor if autor else '', autor if autor else '',
num_protocolo if num_protocolo else '', num_protocolo if num_protocolo else '',
turno) turno,
situacao if situacao else '')
# Na linha abaixo, o segundo argumento é None para não colocar # Na linha abaixo, o segundo argumento é None para não colocar
# url em toda a string de title_materia # url em toda a string de title_materia
@ -706,6 +710,8 @@ class OradorCrud(MasterDetailCrud):
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
form_class = OradorForm form_class = OradorForm
template_name = 'sessao/oradores_create.html'
def get_initial(self): def get_initial(self):
return {'id_sessao': self.kwargs['pk']} return {'id_sessao': self.kwargs['pk']}
@ -718,6 +724,8 @@ class OradorCrud(MasterDetailCrud):
if tipo_sessao.nome == "Solene": if tipo_sessao.nome == "Solene":
context.update( context.update(
{'subnav_template_name': 'sessao/subnav-solene.yaml'}) {'subnav_template_name': 'sessao/subnav-solene.yaml'})
ultimo_orador = Orador.objects.filter(sessao_plenaria=kwargs['root_pk']).order_by("-numero_ordem").first()
context["ultima_ordem"] = ultimo_orador.numero_ordem if ultimo_orador else 0
return context return context
def get_success_url(self): def get_success_url(self):
@ -775,6 +783,7 @@ class OradorExpedienteCrud(OradorCrud):
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
form_class = OradorExpedienteForm form_class = OradorExpedienteForm
template_name = 'sessao/oradores_create.html'
def get_initial(self): def get_initial(self):
return {'id_sessao': self.kwargs['pk']} return {'id_sessao': self.kwargs['pk']}
@ -787,6 +796,8 @@ class OradorExpedienteCrud(OradorCrud):
if tipo_sessao.nome == "Solene": if tipo_sessao.nome == "Solene":
context.update( context.update(
{'subnav_template_name': 'sessao/subnav-solene.yaml'}) {'subnav_template_name': 'sessao/subnav-solene.yaml'})
ultimo_orador = OradorExpediente.objects.filter(sessao_plenaria=kwargs['root_pk']).order_by("-numero_ordem").first()
context["ultima_ordem"] = ultimo_orador.numero_ordem if ultimo_orador else 0
return context return context
def get_success_url(self): def get_success_url(self):
@ -850,9 +861,9 @@ class OradorExpedienteCrud(OradorCrud):
class OradorOrdemDiaCrud(OradorCrud): class OradorOrdemDiaCrud(OradorCrud):
model = OradorOrdemDia model = OradorOrdemDia
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
form_class = OradorOrdemDiaForm form_class = OradorOrdemDiaForm
template_name = 'sessao/oradores_create.html'
def get_initial(self): def get_initial(self):
return {'id_sessao': self.kwargs['pk']} return {'id_sessao': self.kwargs['pk']}
@ -861,6 +872,12 @@ class OradorOrdemDiaCrud(OradorCrud):
return reverse('sapl.sessao:oradorordemdia_list', return reverse('sapl.sessao:oradorordemdia_list',
kwargs={'pk': self.kwargs['pk']}) kwargs={'pk': self.kwargs['pk']})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
ultimo_orador = OradorOrdemDia.objects.filter(sessao_plenaria=kwargs['root_pk']).order_by("-numero_ordem").first()
context["ultima_ordem"] = ultimo_orador.numero_ordem if ultimo_orador else 0
return context
class UpdateView(MasterDetailCrud.UpdateView): class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorOrdemDiaForm form_class = OradorOrdemDiaForm
@ -1689,28 +1706,14 @@ def get_expedientes(sessao_plenaria):
def get_materias_expediente(sessao_plenaria): def get_materias_expediente(sessao_plenaria):
materias = ExpedienteMateria.objects.filter(
sessao_plenaria_id=sessao_plenaria.id)
materias_expediente = [] materias_expediente = []
for m in materias: for m in ExpedienteMateria.objects.select_related("materia").filter(sessao_plenaria_id=sessao_plenaria.id):
ementa = m.materia.ementa
titulo = m.materia
numero = m.numero_ordem
tramitacao = '' tramitacao = ''
tramitacoes = Tramitacao.objects.filter( for aux_tramitacao in Tramitacao.objects.filter(materia=m.materia).order_by('-pk'):
materia=m.materia).order_by('-pk')
for aux_tramitacao in tramitacoes:
if aux_tramitacao.turno: if aux_tramitacao.turno:
tramitacao = aux_tramitacao tramitacao = aux_tramitacao
break break
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
rv = m.registrovotacao_set.first() rv = m.registrovotacao_set.first()
rp = m.retiradapauta_set.filter(materia=m.materia).first() rp = m.retiradapauta_set.filter(materia=m.materia).first()
if rv: if rv:
@ -1720,31 +1723,26 @@ def get_materias_expediente(sessao_plenaria):
resultado = rp.tipo_de_retirada.descricao resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao resultado_observacao = rp.observacao
else: else:
if m.tipo_votacao == 4: resultado = _('Matéria lida') if m.tipo_votacao == 4 else _('Matéria não votada')
resultado = _('Matéria lida')
else:
resultado = _('Matéria não votada')
resultado_observacao = _(' ') resultado_observacao = _(' ')
autoria = Autoria.objects.filter(materia_id=m.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa, materias_expediente.append({
'titulo': titulo, 'ementa': m.materia.ementa,
'numero': numero, 'titulo': m.materia,
'turno': turno, 'numero': m.numero_ordem,
'turno': get_turno(tramitacao.turno) if tramitacao else None,
'situacao': m.materia.materiaemtramitacao_set.first().tramitacao.status,
'resultado': resultado, 'resultado': resultado,
'resultado_observacao': resultado_observacao, 'resultado_observacao': resultado_observacao,
'autor': autor, 'autor': [str(x.autor) for x in Autoria.objects.select_related("autor").filter(materia_id=m.materia_id)],
'numero_protocolo': m.materia.numero_protocolo, 'numero_protocolo': m.materia.numero_protocolo,
'numero_processo': m.materia.numeracao_set.last(), 'numero_processo': m.materia.numeracao_set.last(),
'observacao_materia': m.materia.observacao, 'observacao_materia': m.materia.observacao,
'observacao': m.observacao 'observacao': m.observacao
} })
materias_expediente.append(mat)
context = {'materia_expediente': materias_expediente} return {'materia_expediente': materias_expediente}
return context
def get_oradores_expediente(sessao_plenaria): def get_oradores_expediente(sessao_plenaria):
@ -1812,26 +1810,14 @@ def get_assinaturas(sessao_plenaria):
def get_materias_ordem_do_dia(sessao_plenaria): def get_materias_ordem_do_dia(sessao_plenaria):
ordem = OrdemDia.objects.filter(sessao_plenaria_id=sessao_plenaria.id)
materias_ordem = [] materias_ordem = []
for o in ordem: for o in OrdemDia.objects.filter(sessao_plenaria_id=sessao_plenaria.id):
ementa = o.materia.ementa
ementa_observacao = o.observacao
titulo = o.materia
numero = o.numero_ordem
tramitacao = '' tramitacao = ''
tramitacoes = Tramitacao.objects.filter( for aux_tramitacao in Tramitacao.objects.filter(materia=o.materia).order_by('-pk'):
materia=o.materia).order_by('-pk')
for aux_tramitacao in tramitacoes:
if aux_tramitacao.turno: if aux_tramitacao.turno:
tramitacao = aux_tramitacao tramitacao = aux_tramitacao
break break
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
# Verificar resultado # Verificar resultado
rv = o.registrovotacao_set.filter(materia=o.materia).first() rv = o.registrovotacao_set.filter(materia=o.materia).first()
rp = o.retiradapauta_set.filter(materia=o.materia).first() rp = o.retiradapauta_set.filter(materia=o.materia).first()
@ -1842,43 +1828,35 @@ def get_materias_ordem_do_dia(sessao_plenaria):
resultado = rp.tipo_de_retirada.descricao resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao resultado_observacao = rp.observacao
else: else:
if o.tipo_votacao == 4: resultado = _('Matéria lida') if o.tipo_votacao == 4 else _('Matéria não votada')
resultado = _('Matéria lida')
else:
resultado = _('Matéria não votada')
resultado_observacao = _(' ') resultado_observacao = _(' ')
voto_sim = ""
voto_nao = ""
voto_abstencoes = ""
voto_nominal = [] voto_nominal = []
if o.tipo_votacao == 2: if o.tipo_votacao == 2:
votos = VotoParlamentar.objects.filter(ordem=o.id) for voto in VotoParlamentar.objects.filter(ordem=o.id):
for voto in votos: voto_nominal.append((voto.parlamentar.nome_completo, voto.voto))
aux_voto = (voto.parlamentar.nome_completo, voto.voto)
voto_nominal.append(aux_voto)
try:
voto = RegistroVotacao.objects.filter(ordem=o.id).last() voto = RegistroVotacao.objects.filter(ordem=o.id).last()
if voto:
voto_sim = voto.numero_votos_sim voto_sim = voto.numero_votos_sim
voto_nao = voto.numero_votos_nao voto_nao = voto.numero_votos_nao
voto_abstencoes = voto.numero_abstencoes voto_abstencoes = voto.numero_abstencoes
except AttributeError: else:
voto_sim = " Não Informado" voto_sim = " Não Informado"
voto_nao = " Não Informado" voto_nao = " Não Informado"
voto_abstencoes = " Não Informado" voto_abstencoes = " Não Informado"
autoria = Autoria.objects.filter(
materia_id=o.materia_id) materias_ordem.append({
autor = [str(x.autor) for x in autoria] 'ementa': o.materia.ementa,
mat = {'ementa': ementa, 'ementa_observacao': o.observacao,
'ementa_observacao': ementa_observacao, 'titulo': o.materia,
'titulo': titulo, 'numero': o.numero_ordem,
'numero': numero, 'turno': get_turno(tramitacao.turno) if tramitacao else None,
'turno': turno, 'situacao': o.materia.materiaemtramitacao_set.first().tramitacao.status,
'resultado': resultado, 'resultado': resultado,
'resultado_observacao': resultado_observacao, 'resultado_observacao': resultado_observacao,
'autor': autor, 'autor': [str(x.autor) for x in Autoria.objects.select_related("autor").filter(materia_id=o.materia_id)],
'numero_protocolo': o.materia.numero_protocolo, 'numero_protocolo': o.materia.numero_protocolo,
'numero_processo': o.materia.numeracao_set.last(), 'numero_processo': o.materia.numeracao_set.last(),
'tipo_votacao': o.TIPO_VOTACAO_CHOICES[o.tipo_votacao], 'tipo_votacao': o.TIPO_VOTACAO_CHOICES[o.tipo_votacao],
@ -1887,11 +1865,9 @@ def get_materias_ordem_do_dia(sessao_plenaria):
'voto_abstencoes': voto_abstencoes, 'voto_abstencoes': voto_abstencoes,
'voto_nominal': voto_nominal, 'voto_nominal': voto_nominal,
'observacao': o.observacao 'observacao': o.observacao
} })
materias_ordem.append(mat)
context = {'materias_ordem': materias_ordem} return {'materias_ordem': materias_ordem}
return context
def get_oradores_ordemdia(sessao_plenaria): def get_oradores_ordemdia(sessao_plenaria):
@ -1959,13 +1935,9 @@ class ResumoView(DetailView):
context = self.get_context_data(object=self.object) context = self.get_context_data(object=self.object)
# Votos de Votação Nominal de Matérias Expediente # Votos de Votação Nominal de Matérias Expediente
materias_expediente_votacao_nominal = ExpedienteMateria.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia')
votacoes = [] votacoes = []
for mevn in materias_expediente_votacao_nominal: for mevn in ExpedienteMateria.objects.filter(sessao_plenaria_id=self.object.id, tipo_votacao=2)\
.order_by('-materia'):
votos_materia = [] votos_materia = []
titulo_materia = mevn.materia titulo_materia = mevn.materia
registro = RegistroVotacao.objects.filter(expediente=mevn) registro = RegistroVotacao.objects.filter(expediente=mevn)
@ -1973,11 +1945,10 @@ class ResumoView(DetailView):
for vp in VotoParlamentar.objects.filter(votacao=registro).order_by('parlamentar'): for vp in VotoParlamentar.objects.filter(votacao=registro).order_by('parlamentar'):
votos_materia.append(vp) votos_materia.append(vp)
dados_votacao = { votacoes.append({
'titulo': titulo_materia, 'titulo': titulo_materia,
'votos': votos_materia 'votos': votos_materia
} })
votacoes.append(dados_votacao)
context.update({'votos_nominais_materia_expediente': votacoes}) context.update({'votos_nominais_materia_expediente': votacoes})
@ -2011,12 +1982,8 @@ class ResumoView(DetailView):
# ===================================================================== # =====================================================================
# Matérias Ordem do Dia # Matérias Ordem do Dia
# Votos de Votação Nominal de Matérias Ordem do Dia # Votos de Votação Nominal de Matérias Ordem do Dia
materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia')
votacoes_od = [] votacoes_od = []
for modvn in materias_ordem_dia_votacao_nominal: for modvn in OrdemDia.objects.filter(sessao_plenaria_id=self.object.id, tipo_votacao=2).order_by('-materia'):
votos_materia_od = [] votos_materia_od = []
t_materia = modvn.materia t_materia = modvn.materia
registro_od = RegistroVotacao.objects.filter(ordem=modvn) registro_od = RegistroVotacao.objects.filter(ordem=modvn)
@ -2024,11 +1991,10 @@ class ResumoView(DetailView):
for vp_od in VotoParlamentar.objects.filter(votacao=registro_od).order_by('parlamentar'): for vp_od in VotoParlamentar.objects.filter(votacao=registro_od).order_by('parlamentar'):
votos_materia_od.append(vp_od) votos_materia_od.append(vp_od)
dados_votacao_od = { votacoes_od.append({
'titulo': t_materia, 'titulo': t_materia,
'votos': votos_materia_od 'votos': votos_materia_od
} })
votacoes_od.append(dados_votacao_od)
context.update({'votos_nominais_materia_ordem_dia': votacoes_od}) context.update({'votos_nominais_materia_ordem_dia': votacoes_od})
@ -2803,8 +2769,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
parlamentar=parlamentar) parlamentar=parlamentar)
except ObjectDoesNotExist: except ObjectDoesNotExist:
username = self.request.user.username username = self.request.user.username
self.logger.error('user=' + username + '. Objeto voto_parlamentar do ' + self.logger.warning('User={}. Objeto voto_parlamentar do parlamentar de id={} não existe.'
'parlamentar de id={} não existe.'.format(parlamentar.pk)) .format(username, parlamentar.pk))
yield [parlamentar, None] yield [parlamentar, None]
else: else:
yield [parlamentar, voto.voto] yield [parlamentar, voto.voto]
@ -4400,8 +4366,8 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView)
parlamentar=parlamentar) parlamentar=parlamentar)
except ObjectDoesNotExist: except ObjectDoesNotExist:
username = self.request.user.username username = self.request.user.username
self.logger.error('user=' + username + '. Objeto voto_parlamentar do ' + self.logger.warning('User={}. Objeto voto_parlamentar do parlamentar de id={} não existe.'
'parlamentar de id={} não existe.'.format(parlamentar.pk)) .format(username, parlamentar.pk))
yield [parlamentar, None] yield [parlamentar, None]
else: else:
yield [parlamentar, voto.voto] yield [parlamentar, voto.voto]

2
sapl/settings.py

@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next=' LOGIN_URL = '/login/?next='
SAPL_VERSION = '3.1.161-RC2' SAPL_VERSION = '3.1.161-RC3'
if DEBUG: if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

3
sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.LICENSE.txt.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.map

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.map.gz

Binary file not shown.

3
sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js

File diff suppressed because one or more lines are too long

4
sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.LICENSE.txt → sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.LICENSE.txt

@ -60,7 +60,7 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*! /*!
* jQuery JavaScript Library v3.5.0 * jQuery JavaScript Library v3.5.1
* https://jquery.com/ * https://jquery.com/
* *
* Includes Sizzle.js * Includes Sizzle.js
@ -70,7 +70,7 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Released under the MIT license * Released under the MIT license
* https://jquery.org/license * https://jquery.org/license
* *
* Date: 2020-04-10T15:07Z * Date: 2020-05-04T22:49Z
*/ */
/*! /*!

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.LICENSE.txt.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.map

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.map.gz

Binary file not shown.

4
sapl/static/sapl/frontend/js/parlamentar.35e37659.js → sapl/static/sapl/frontend/js/parlamentar.307451cf.js

@ -1,2 +1,2 @@
(function(e){function a(a){for(var r,s,l=a[0],o=a[1],u=a[2],c=0,f=[];c<l.length;c++)s=l[c],Object.prototype.hasOwnProperty.call(n,s)&&n[s]&&f.push(n[s][0]),n[s]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(e[r]=o[r]);p&&p(a);while(f.length)f.shift()();return i.push.apply(i,u||[]),t()}function t(){for(var e,a=0;a<i.length;a++){for(var t=i[a],r=!0,l=1;l<t.length;l++){var o=t[l];0!==n[o]&&(r=!1)}r&&(i.splice(a--,1),e=s(s.s=t[0]))}return e}var r={},n={parlamentar:0},i=[];function s(a){if(r[a])return r[a].exports;var t=r[a]={i:a,l:!1,exports:{}};return e[a].call(t.exports,t,t.exports,s),t.l=!0,t.exports}s.m=e,s.c=r,s.d=function(e,a,t){s.o(e,a)||Object.defineProperty(e,a,{enumerable:!0,get:t})},s.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.t=function(e,a){if(1&a&&(e=s(e)),8&a)return e;if(4&a&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(s.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&a&&"string"!=typeof e)for(var r in e)s.d(t,r,function(a){return e[a]}.bind(null,r));return t},s.n=function(e){var a=e&&e.__esModule?function(){return e["default"]}:function(){return e};return s.d(a,"a",a),a},s.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},s.p="/static/sapl/frontend/";var l=window["webpackJsonp"]=window["webpackJsonp"]||[],o=l.push.bind(l);l.push=a,l=l.slice();for(var u=0;u<l.length;u++)a(l[u]);var p=o;i.push([3,"chunk-vendors"]),t()})({3:function(e,a,t){e.exports=t("71e4")},"49c2":function(e,a,t){},"71e4":function(e,a,t){"use strict";t.r(a),function(e){t("4de4"),t("e260"),t("e6cf"),t("cca6"),t("a79d"),t("49c2");var a=t("a026"),r=t("44d4"),n=t("bc3a"),i=t.n(n);i.a.defaults.xsrfCookieName="csrftoken",i.a.defaults.xsrfHeaderName="X-CSRFToken",a["a"].use(r["a"]);new a["a"]({delimiters:["[[","]]"],el:"#app2",data:function(){return{nome_pesquisa:"",is_pesquisa:!1,legislatura_selecionada:"",legislaturas:[],parlamentares:[],visible_parlamentares:[],size_parlamentares:0,filter_ativo:"",filter_titular:""}},watch:{nome_pesquisa:function(e){this.debouncepesquisaParlamentar()}},created:function(){this.debouncepesquisaParlamentar=e.debounce(this.pesquisaParlamentar,500)},methods:{getParlamentares:function(e){var a=this;this.legislatura_selecionada&&i.a.get("/api/parlamentares/parlamentar/"+this.legislatura_selecionada+"/parlamentares_by_legislatura/").then((function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length})).catch((function(e){}))},pesquisaParlamentar:function(e){var a=this;i.a.get("/api/parlamentares/parlamentar/search_parlamentares/",{params:{nome_parlamentar:this.nome_pesquisa}}).then((function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length})).catch((function(e){}))},checkTitularAtivo:function(e){this.visible_parlamentares=this.parlamentares,this.filter_ativo&&(this.visible_parlamentares=this.visible_parlamentares.filter((function(e){return e.ativo}))),this.filter_titular&&(this.visible_parlamentares=this.visible_parlamentares.filter((function(e){return"Sim"===e.titular}))),this.size_parlamentares=this.visible_parlamentares.length},pesquisaChange:function(e){this.is_pesquisa=!this.is_pesquisa,this.filter_ativo=!1,this.is_pesquisa?this.parlamentares=[]:this.getParlamentares()}},mounted:function(){var e=this;i.a.get("/api/parlamentares/legislatura/?get_all=true").then((function(a){e.legislaturas=a.data,e.legislatura_selecionada=a.data[0].id})).then((function(a){e.getParlamentares()})).catch((function(e){}))}})}.call(this,t("2ef0"))}}); (function(e){function a(a){for(var r,s,l=a[0],o=a[1],u=a[2],c=0,f=[];c<l.length;c++)s=l[c],Object.prototype.hasOwnProperty.call(n,s)&&n[s]&&f.push(n[s][0]),n[s]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(e[r]=o[r]);p&&p(a);while(f.length)f.shift()();return i.push.apply(i,u||[]),t()}function t(){for(var e,a=0;a<i.length;a++){for(var t=i[a],r=!0,l=1;l<t.length;l++){var o=t[l];0!==n[o]&&(r=!1)}r&&(i.splice(a--,1),e=s(s.s=t[0]))}return e}var r={},n={parlamentar:0},i=[];function s(a){if(r[a])return r[a].exports;var t=r[a]={i:a,l:!1,exports:{}};return e[a].call(t.exports,t,t.exports,s),t.l=!0,t.exports}s.m=e,s.c=r,s.d=function(e,a,t){s.o(e,a)||Object.defineProperty(e,a,{enumerable:!0,get:t})},s.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.t=function(e,a){if(1&a&&(e=s(e)),8&a)return e;if(4&a&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(s.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&a&&"string"!=typeof e)for(var r in e)s.d(t,r,function(a){return e[a]}.bind(null,r));return t},s.n=function(e){var a=e&&e.__esModule?function(){return e["default"]}:function(){return e};return s.d(a,"a",a),a},s.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},s.p="/static/sapl/frontend/";var l=window["webpackJsonp"]=window["webpackJsonp"]||[],o=l.push.bind(l);l.push=a,l=l.slice();for(var u=0;u<l.length;u++)a(l[u]);var p=o;i.push([3,"chunk-vendors"]),t()})({3:function(e,a,t){e.exports=t("71e4")},"49c2":function(e,a,t){},"71e4":function(e,a,t){"use strict";t.r(a),function(e){t("4de4"),t("e260"),t("e6cf"),t("cca6"),t("a79d"),t("49c2");var a=t("a026"),r=t("44d4"),n=t("bc3a"),i=t.n(n);i.a.defaults.xsrfCookieName="csrftoken",i.a.defaults.xsrfHeaderName="X-CSRFToken",a["a"].use(r["a"]);new a["a"]({delimiters:["[[","]]"],el:"#app2",data:function(){return{nome_pesquisa:"",is_pesquisa:!1,legislatura_selecionada:"",legislaturas:[],parlamentares:[],visible_parlamentares:[],size_parlamentares:0,filter_ativo:!0,filter_titular:""}},watch:{nome_pesquisa:function(e){this.debouncepesquisaParlamentar()}},created:function(){this.debouncepesquisaParlamentar=e.debounce(this.pesquisaParlamentar,500)},methods:{getParlamentares:function(e){var a=this;this.legislatura_selecionada&&i.a.get("/api/parlamentares/parlamentar/"+this.legislatura_selecionada+"/parlamentares_by_legislatura/").then((function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length,a.checkTitularAtivo()})).catch((function(e){}))},pesquisaParlamentar:function(e){var a=this;i.a.get("/api/parlamentares/parlamentar/search_parlamentares/",{params:{nome_parlamentar:this.nome_pesquisa}}).then((function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length})).catch((function(e){}))},checkTitularAtivo:function(e){this.visible_parlamentares=this.parlamentares,this.filter_ativo&&(this.visible_parlamentares=this.visible_parlamentares.filter((function(e){return e.ativo}))),this.filter_titular&&(this.visible_parlamentares=this.visible_parlamentares.filter((function(e){return"Sim"===e.titular}))),this.size_parlamentares=this.visible_parlamentares.length},pesquisaChange:function(e){this.is_pesquisa=!this.is_pesquisa,this.filter_ativo=!1,this.is_pesquisa?this.parlamentares=[]:this.getParlamentares()}},mounted:function(){var e=this;i.a.get("/api/parlamentares/legislatura/?get_all=true").then((function(a){e.legislaturas=a.data,e.legislatura_selecionada=a.data[0].id})).then((function(a){e.getParlamentares()})).catch((function(e){}))}})}.call(this,t("2ef0"))}});
//# sourceMappingURL=parlamentar.35e37659.js.map //# sourceMappingURL=parlamentar.307451cf.js.map

BIN
sapl/static/sapl/frontend/js/parlamentar.307451cf.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/parlamentar.307451cf.js.map

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/parlamentar.307451cf.js.map.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/parlamentar.35e37659.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/parlamentar.35e37659.js.map

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/parlamentar.35e37659.js.map.gz

Binary file not shown.

2
sapl/templates/base.html

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

14
sapl/templates/base/autor_detail.html

@ -0,0 +1,14 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags staticfiles %}
{% block sub_actions %}
<div class="actions btn-group btn-group-sm" role="group">
<a href="{% url 'sapl.base:pesquisar_autor' %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Pesquisar {{ verbose_name }} {% endblocktrans %}
</a>
<a href="{{ view.create_url }}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
</div>
{% endblock sub_actions %}

51
sapl/templates/base/autor_filter.html

@ -0,0 +1,51 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags staticfiles %}
{% block base_content %}
{% if not show_results %}
{% crispy filter.form %}
{% else %}
<div class="actions btn-group float-right btn-group-sm" role="group">
<a href="{% url 'sapl.base:pesquisar_autor' %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
{% if not request.user.is_anonymous %}
<a href="{% url 'sapl.base:autor_create' %}"class="btn btn-outline-primary">Cadastrar Autor</a>
{% endif %}
</div>
<br>
{% if numero_res > 0 %}
{% if numero_res == 1 %}
<p>Foi encontrado {{ numero_res }} resultado</p>
{% else %}
<p>Foram encontrados {{ numero_res }} resultados</p>
{% endif %}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Tipo do Autor</th>
<th>Nome do Autor</th>
<th>Usuário</th>
</tr>
</thead>
<tbody>
{% for autor in page_obj %}
<tr>
<td>{{ autor.tipo }}</td>
<td>
<a href="{% url 'sapl.base:autor_detail' autor.pk %}">
{% if autor.nome %} {{ autor.nome }} {% else %} - {% endif %}
</a>
</td>
<td>{% if autor.user %} {{ autor.user }} {% else %} - {% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<font size="4"><p align="center">{{ NO_ENTRIES_MSG }}</p></font>
{% endif %}
{% endif %}
<br/>
{% include 'paginacao.html'%}
<br /><br /><br />
{% endblock base_content %}

19
sapl/templates/materia/config_etiqueta_materia.html

@ -0,0 +1,19 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block base_content %}
<h1>Configuração Etiqueta Materia Legislativa</h1>
<form action="." method="post">
{% csrf_token %}
{{ form|crispy }}
<div class="row">
<div class="col-md-12">
<div class="form-group row justify-content-between">
<a href="{% url 'sapl.base:sistema' %}" class="btn btn-dark">Cancelar</a>
<input type="submit" name="salvar" value="Salvar" class="btn btn-primary float-right" id="submit-id-salvar" onclick="this.form.submit();this.disabled=true;">
</div>
</div>
</div>
</form>
{% endblock base_content %}

6
sapl/templates/materia/layouts.yaml

@ -157,3 +157,9 @@ MateriaLegislativaDetail:
- ementa - ementa
- indexacao - indexacao
- observacao - observacao
ConfigEtiquetaMateriaLegislativa:
{% trans 'Configurações de Etiqueta' %}:
- largura
- altura
- mostrar_em_arquivo

6
sapl/templates/materia/materialegislativa_detail.html

@ -10,6 +10,12 @@
{% endif %} {% endif %}
{% endblock sub_actions %} {% endblock sub_actions %}
{% block editions %}
{{ block.super }}
<a href="{% url 'sapl.relatorios:etiqueta_materia_legislativa' object.pk %}" class="btn btn-outline-primary">{% trans 'Etiqueta' %}</a>
{% endblock editions %}
{% block detail_content %} {% block detail_content %}
{{ block.super }} {{ block.super }}
{% if object.registrovotacao_set.exists %} {% if object.registrovotacao_set.exists %}

2
sapl/templates/materia/materialegislativa_filter.html

@ -1,6 +1,7 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n %} {% load i18n %}
{% load crispy_forms_tags common_tags%} {% load crispy_forms_tags common_tags%}
{% load webpack_static from webpack_loader %}
{% block actions %} {% block actions %}
@ -47,6 +48,7 @@
<tr> <tr>
<td> <td>
<strong><a href="{% url 'sapl.materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a> <strong><a href="{% url 'sapl.materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a>
<a href="{% url 'sapl.relatorios:etiqueta_materia_legislativa' m.pk %}"><img src="{% webpack_static 'img/etiqueta.png' %}" alt="Etiqueta Individual"></a>
</br> </br>
<strong>Ementa:</strong>&nbsp;{{ m.ementa|dont_break_out }} <strong>Ementa:</strong>&nbsp;{{ m.ementa|dont_break_out }}
</br> </br>

38
sapl/templates/materia/materialegislativa_form.html

@ -1,23 +1,20 @@
{% extends "crud/form.html" %} {% extends "crud/form.html" %}
{% load i18n %} {% load i18n %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load common_tags %} {% load common_tags %}
{% block extra_js %} {% block extra_js %}
<script language="Javascript">
<script language="Javascript">
function recuperar_numero_ano() { function recuperar_numero_ano() {
var tipo = $("#id_tipo").val() var tipo = $("#id_tipo").val()
var ano = $("#id_ano").val() var ano = $("#id_ano").val()
if (tipo) { if (tipo){
$.get("/materia/recuperar-materia",{tipo: tipo, ano: ano}, $.get("/materia/recuperar-materia", { tipo: tipo, ano: ano },
function(data, status) { function (data, status) {
$("#id_numero").val(data.numero); $("#id_numero").val(data.numero);
$("#id_ano").val(data.ano); $("#id_ano").val(data.ano);
console.log(data) console.log(data);
}); });
} }
} }
@ -55,27 +52,29 @@
+'Compreendo e quero continuar</button>' +'Compreendo e quero continuar</button>'
+'</div></div>'; +'</div></div>';
function verifica_ano(){ function verifica_ano() {
let ano = $("select#id_ano.select").val(); let ano = $("select#id_ano.select").val();
let data_apresentacao = $("input#id_data_apresentacao.dateinput").val(); let data_apresentacao = $("input#id_data_apresentacao.dateinput").val();
let ano_apresentacao = data_apresentacao.substr(data_apresentacao.length - 4); let ano_apresentacao = data_apresentacao.substr(data_apresentacao.length - 4);
if(ano && ano_apresentacao && ano_apresentacao != ano){ if (ano && ano_apresentacao && ano_apresentacao != ano){
$('#fundo_modal').fadeIn(); $('#fundo_modal').fadeIn();
} }
} }
$(document).ready(function() { $(document).ready( function() {
$("#id_tipo_autor").change(function() { $("#id_tipo_autor, #id_data_apresentacao").change( function() {
var tipo_selecionado = $("#id_tipo_autor").val(); var tipo_selecionado = $("#id_tipo_autor").val();
var autor_selecionado = $("#id_autor").val(); var autor_selecionado = $("#id_autor").val();
$("#id_autor option").remove() $("#id_autor option").remove()
if (tipo_selecionado !== undefined && tipo_selecionado !== null) {
if (tipo_selecionado !== undefined && tipo_selecionado !== null){
var json_data = { var json_data = {
tipo : tipo_selecionado, tipo : tipo_selecionado,
data_relativa : $("#id_data_apresentacao").val() data_relativa : $("#id_data_apresentacao").val()
} }
$.getJSON("/api/autor/possiveis", json_data, function(data){ $.getJSON("/api/autor/possiveis", json_data, function(data) {
if (data) { if (data) {
var results = data.sort(compare); var results = data.sort(compare);
if (results.length > 1) { if (results.length > 1) {
@ -96,16 +95,15 @@
$("body").append(meu_modal); $("body").append(meu_modal);
$("#fundo_modal, #close_model_btn").click(function(){ $("#fundo_modal").hide(); }); $("#fundo_modal, #close_model_btn").click( function() { $("#fundo_modal").hide(); });
$("#meu_modal").click(function(e){ e.stopPropagation(); }); $("#meu_modal").click( function(e) { e.stopPropagation(); });
$("select#id_ano.select.form-control").change(function(){ $("select#id_ano.select.form-control").change( function() {
verifica_ano(); verifica_ano();
}); });
$("input#id_data_apresentacao.dateinput.form-control").change(function(){ $("input#id_data_apresentacao.dateinput.form-control").change( function() {
verifica_ano(); verifica_ano();
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}

2
sapl/templates/materia/tramitacao_detail.html

@ -3,7 +3,7 @@
{% block detail_content %} {% block detail_content %}
{{ block.super }} {{ block.super }}
{% if user.is_superuser %} {% if 'materia.detail_tramitacao' in request.user.get_all_permissions %}
<div class="row"> <div class="row">
{% if tramitacao.user %} {% if tramitacao.user %}
<div class="col-sm-4"> <div class="col-sm-4">

10
sapl/templates/menu_tabelas_auxiliares.yaml

@ -8,8 +8,11 @@
- title: {% trans 'Configurações da Aplicação' %} - title: {% trans 'Configurações da Aplicação' %}
url: sapl.base:appconfig_list url: sapl.base:appconfig_list
css_class: btn btn-link css_class: btn btn-link
- title: {% trans 'Autor' %} - title: {% trans 'Pesquisar Autor' %}
url: sapl.base:autor_list url: sapl.base:pesquisar_autor
css_class: btn btn-link
- title: {% trans 'Adicionar Autor' %}
url: sapl.base:autor_create
css_class: btn btn-link css_class: btn btn-link
- title: {% trans 'Tipo de Autor' %} - title: {% trans 'Tipo de Autor' %}
url: sapl.base:tipoautor_list url: sapl.base:tipoautor_list
@ -116,6 +119,9 @@
- title: {% trans 'Assunto Matéria' %} - title: {% trans 'Assunto Matéria' %}
url: sapl.materia:assuntomateria_list url: sapl.materia:assuntomateria_list
css_class: btn btn-link css_class: btn btn-link
- title: {% trans 'Configuração Etiqueta Materia Legislativa' %}
url: sapl.materia:configEtiquetaMateriaLegislativaCrud
css_class: btn btn-link
- title: {% trans 'Módulo Normas Jurídicas' %} - title: {% trans 'Módulo Normas Jurídicas' %}
css_class: head_title css_class: head_title
children: children:

104
sapl/templates/norma/normajuridica_form.html

@ -10,20 +10,23 @@
var tipo_materia = $("#id_tipo_materia").val(); var tipo_materia = $("#id_tipo_materia").val();
var numero_materia = $("#id_numero_materia").val(); var numero_materia = $("#id_numero_materia").val();
var ano_materia = $("#id_ano_materia").val(); var ano_materia = $("#id_ano_materia").val();
var tipo = $('#id_tipo').val();
var ano = $('#id_ano').val();
var numero = $('#id_numero').val();
var ementa = $('#id_ementa').val();
if (tipo_materia && numero_materia && ano_materia) { if (tipo_materia && numero_materia && ano_materia) {
$.get("/sessao/recuperar-materia", $.get("/sessao/recuperar-materia", {
{tipo_materia: tipo_materia, tipo_materia: tipo_materia,
numero_materia: numero_materia, numero_materia: numero_materia,
ano_materia: ano_materia}, ano_materia: ano_materia
function(data, status) { }, (data, status) => {
$("#id_fundo_confirmacao_mudanca_ementa_indexacao").fadeIn();
$("#id_sim_mudanca_ementa_indexacao").click(() => {
$("#id_ementa").val(data.ementa); $("#id_ementa").val(data.ementa);
$("#id_indexacao").val(data.indexacao); $("#id_indexacao").val(data.indexacao);
} $("#id_fundo_confirmacao_mudanca_ementa_indexacao").hide();
); });
$("#id_nao_mudanca_ementa_indexacao").click(() => {
$("#id_fundo_confirmacao_mudanca_ementa_indexacao").hide();
});
});
} }
} }
var fields = ["#id_tipo_materia", "#id_numero_materia", "#id_ano_materia"] var fields = ["#id_tipo_materia", "#id_numero_materia", "#id_ano_materia"]
@ -36,9 +39,8 @@
var ano = $("#id_ano").val(); var ano = $("#id_ano").val();
if (tipo) { if (tipo) {
$.get("/norma/recuperar-numero-norma",{tipo: tipo, $.get("/norma/recuperar-numero-norma", { tipo: tipo, ano: ano },
ano: ano}, (data, status) => {
function(data, status) {
$("#id_numero").val(data.numero); $("#id_numero").val(data.numero);
$("#id_ano").val(data.ano); $("#id_ano").val(data.ano);
}); });
@ -58,29 +60,57 @@
} }
}); });
var modal_estilos = 'display: block;' var modal_estilos = `
+'width: 85%; max-width: 600px;' display: block;
+'background: #fff; padding: 15px;' width: 85%;
+'border-radius: 5px;' max-width: 600px;
+'-webkit-box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);' background: #fff;
+'-moz-box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);' padding: 15px;
+'box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);' border-radius: 5px;
+'position: fixed;' -webkit-box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);
+'top: 50%; left: 50%;' -moz-box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);
+'transform: translate(-50%,-50%);' box-shadow: 0px 6px 14px -2px rgba(0,0,0,0.75);
+'z-index: 99999999; text-align: center'; position: fixed;
top: 50%;
var fundo_modal_estilos = 'top: 0; right: 0;' left: 50%;
+'bottom: 0; left: 0; position: fixed;' transform: translate(-50%,-50%);
+'background-color: rgba(0, 0, 0, 0.6); z-index: 99999999;' z-index: 99999999;
+'display: none;'; text-align: center;
`;
var meu_modal = '<div id="fundo_modal" style="'+fundo_modal_estilos+'">'
+'<div id="meu_modal" style="'+modal_estilos+'">' var fundo_modal_estilos = `
+'<h2>Atenção! Ano de apresentação e ano da norma são diferentes.</h2><br />' top: 0;
+'<button id="close_model_btn" type="button" class="btn btn-warning" data-dismiss="modal">' right: 0;
+'Compreendo e quero continuar</button>' bottom: 0;
+'</div></div>'; left: 0;
position: fixed;
background-color: rgba(0, 0, 0, 0.6);
z-index: 99999999;
display: none;
`;
var meu_modal = `
<div id="fundo_modal" style="${fundo_modal_estilos}">
<div id="meu_modal" style="${modal_estilos}">
<h2>Atenção! Ano de apresentação e ano da norma são diferentes.</h2><br />
<button id="close_model_btn" type="button" class="btn btn-warning" data-dismiss="modal">
Compreendo e quero continuar
</button>
</div>
</div>
`;
const confirmacao_mudanca_ementa_indexacao = `
<div id="id_fundo_confirmacao_mudanca_ementa_indexacao" style="${fundo_modal_estilos}">
<div id="id_confirmacao_mudanca_ementa_indexacao" style="${modal_estilos}">
<h3>Houve à mudança de Matéria vinculada a norma.</h3>
<h3>Deseja atualizar a Ementa e a Indexação com a nova Matéria?</h3><br/>
<button type="submit" id="id_sim_mudanca_ementa_indexacao" class="btn btn-primary">Sim</button>
<button type="button" id="id_nao_mudanca_ementa_indexacao" class="btn btn-secondary" data-dismiss="modal">Não</button>
</div>
</div>
`;
function verifica_ano(){ function verifica_ano(){
let ano = $("select#id_ano.select").val(); let ano = $("select#id_ano.select").val();
@ -93,7 +123,7 @@
} }
$(document).ready(function() { $(document).ready(function() {
$("body").append(meu_modal); $("body").append(meu_modal, confirmacao_mudanca_ementa_indexacao);
$("#fundo_modal, #close_model_btn").click(function(){ $("#fundo_modal").hide(); }); $("#fundo_modal, #close_model_btn").click(function(){ $("#fundo_modal").hide(); });
$("#meu_modal").click(function(e){ e.stopPropagation(); }); $("#meu_modal").click(function(e){ e.stopPropagation(); });

3
sapl/templates/relatorios/blocos_sessao_plenaria/materias_expediente.html

@ -18,6 +18,9 @@
<dt><b>{{materia.num_ordem}} -</b> {{materia.id_materia}}</dt> <dt><b>{{materia.num_ordem}} -</b> {{materia.id_materia}}</dt>
<dt style="text-align: left;"><b>Turno:</b> {{materia.des_turno}}</dt> <dt style="text-align: left;"><b>Turno:</b> {{materia.des_turno}}</dt>
<dt style="text-align: left;"><b>{{materia.num_autores}}: </b>{{materia.nom_autor}}</dt> <dt style="text-align: left;"><b>{{materia.num_autores}}: </b>{{materia.nom_autor}}</dt>
{% if materia.situacao %}
<dt style="text-align: left;"><b>Situação: </b>{{materia.situacao}}</dt>
{% endif %}
</dl> </dl>
</td> </td>
<td style="width:60%"><div style="margin:10px">{{materia.txt_ementa}}<br>{{materia.ordem_observacao}}</div></td> <td style="width:60%"><div style="margin:10px">{{materia.txt_ementa}}<br>{{materia.ordem_observacao}}</div></td>

3
sapl/templates/relatorios/blocos_sessao_plenaria/materias_ordemdia.html

@ -16,6 +16,9 @@
<dt><b>{{materia.num_ordem}} -</b> {{materia.id_materia}}</dt> <dt><b>{{materia.num_ordem}} -</b> {{materia.id_materia}}</dt>
<dt style="text-align: left;"><b>Turno:</b> {{materia.des_turno}}</dt> <dt style="text-align: left;"><b>Turno:</b> {{materia.des_turno}}</dt>
<dt style="text-align: left;"><b>{{materia.num_autores}}: </b>{{materia.nom_autor}}</dt> <dt style="text-align: left;"><b>{{materia.num_autores}}: </b>{{materia.nom_autor}}</dt>
{% if materia.situacao %}
<dt style="text-align: left;"><b>Situação: </b>{{materia.situacao}}</dt>
{% endif %}
</dl> </dl>
</td> </td>
<td style="width:60%">{{materia.txt_ementa}} <br>{{materia.ordem_observacao}}</td> <td style="width:60%">{{materia.txt_ementa}} <br>{{materia.ordem_observacao}}</td>

40
sapl/templates/relatorios/etiqueta_materia_legislativa.html

@ -0,0 +1,40 @@
{% load i18n %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% load static %}
<head>
<style>
@page{
margin: 0cm
}
div {page-break-inside: avoid;}
p {
font-size:4pt;
margin: 5px;
font-family: Georgia, Times, "Times New Roman";
}
img {
position: absolute;
bottom:0px;
left: 0px;
padding:10px;
height: 20px;
width: 90%;
}
</style>
</head>
<body>
<div>
<p><strong>Materia Legislativa - {{numero}}/{{ano}}</strong></p>
<p>Tipo: {{tipo.sigla}} - {{tipo.descricao}}</p>
<p>Data: {{data_apresentacao}}</p>
<p>Ementa: {{ementa}}</p>
<img src="{{barcode}}">
</div>
</body>

4
sapl/templates/relatorios/relatorio_pauta_sessao.html

@ -19,7 +19,7 @@
<thead><tr><th>Matéria</th><th>Ementa</th></tr></thead> <thead><tr><th>Matéria</th><th>Ementa</th></tr></thead>
{% for m in materia_expediente %} {% for m in materia_expediente %}
<tr> <tr>
<td style="width:20%;"> <td style="width:30%; font-size: x-small;">
{{ m.numero }} - {{ m.titulo }}<br /> {{ m.numero }} - {{ m.titulo }}<br />
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }} <b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td> </td>
@ -38,7 +38,7 @@
<thead><tr><th>Matéria</th><th>Ementa</th></tr></thead> <thead><tr><th>Matéria</th><th>Ementa</th></tr></thead>
{% for m in materias_ordem %} {% for m in materias_ordem %}
<tr> <tr>
<td style="width:20%;"> <td style="width:30%; font-size: x-small;">
{{m.numero}} - <b">{{m.titulo}}</b><br /> {{m.numero}} - <b">{{m.titulo}}</b><br />
<b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }} <b>Autor{{ m.autor|length|pluralize:"es" }}</b>: {{ m.autor|join:', ' }}
</td> </td>

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

@ -15,6 +15,9 @@
{% if m.turno %} {% if m.turno %}
Turno: {{m.turno}}, Turno: {{m.turno}},
{% endif %} {% endif %}
{% if m.situacao %}
Situação: {{m.situacao}},
{% endif %}
{% if m.tipo_votacao %} {% if m.tipo_votacao %}
Tipo: {{m.tipo_votacao}}, Tipo: {{m.tipo_votacao}},
Sim: {{ m.voto_sim }}, Sim: {{ m.voto_sim }},

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

@ -15,6 +15,9 @@
{% if m.turno %} {% if m.turno %}
Turno: {{m.turno}}, Turno: {{m.turno}},
{% endif %} {% endif %}
{% if m.situacao %}
Situação: {{m.situacao}},
{% endif %}
{% if m.tipo_votacao %} {% if m.tipo_votacao %}
Tipo: {{m.tipo_votacao}}, Tipo: {{m.tipo_votacao}},
Sim: {{ m.voto_sim }}, Sim: {{ m.voto_sim }},

5
sapl/templates/sessao/blocos_resumo/materias_expediente.html

@ -34,6 +34,11 @@
<br /> <br />
<b>Processo:</b> {{ m.numero_processo }} <b>Processo:</b> {{ m.numero_processo }}
{% endif %} {% endif %}
{% if m.situacao %}
<br />
<b>Situação:</b> {{ m.situacao }}
{% endif %}
</td> </td>
<td> <td>
{{m.ementa|dont_break_out}}<br/> {{m.ementa|dont_break_out}}<br/>

5
sapl/templates/sessao/blocos_resumo/materias_ordem_dia.html

@ -35,6 +35,11 @@
<br /> <br />
<b>Processo:</b> {{ m.numero_processo }} <b>Processo:</b> {{ m.numero_processo }}
{% endif %} {% endif %}
{% if m.situacao %}
<br />
<b>Situação:</b> {{ m.situacao }}
{% endif %}
</td> </td>
<td>{{m.ementa|dont_break_out}}</b><br/>{{m.observacao|dont_break_out}}</td> <td>{{m.ementa|dont_break_out}}</b><br/>{{m.observacao|dont_break_out}}</td>
<td><b>{{m.resultado}}</b><br/>{{m.resultado_observacao}}</td> <td><b>{{m.resultado}}</b><br/>{{m.resultado_observacao}}</td>

17
sapl/templates/sessao/oradores_create.html

@ -0,0 +1,17 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% block extra_js %}
<script type="text/javascript" >
$(document).ready(function(){
if("{{ultima_ordem}}" != "None"){
$("#id_numero_ordem").val({{ultima_ordem}}+1);
}
else{
$("#id_numero_ordem").val(1);
}
});
</script>
{% endblock extra_js %}

2
sapl/webpack-stats.json

@ -1 +1 @@
{"status":"done","publicPath":"/static/sapl/frontend/","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.42151acc.css","publicPath":"/static/sapl/frontend/css/chunk-vendors.42151acc.css","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.42151acc.css"},{"name":"js/chunk-vendors.f89f6c45.js","publicPath":"/static/sapl/frontend/js/chunk-vendors.f89f6c45.js","path":"../sapl/sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js"},{"name":"css/chunk-vendors.42151acc.css.map","publicPath":"/static/sapl/frontend/css/chunk-vendors.42151acc.css.map","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.42151acc.css.map"},{"name":"js/chunk-vendors.f89f6c45.js.map","publicPath":"/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.map","path":"../sapl/sapl/static/sapl/frontend/js/chunk-vendors.f89f6c45.js.map"}],"compilacao":[{"name":"css/compilacao.eff62463.css","publicPath":"/static/sapl/frontend/css/compilacao.eff62463.css","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.eff62463.css"},{"name":"js/compilacao.d421699a.js","publicPath":"/static/sapl/frontend/js/compilacao.d421699a.js","path":"../sapl/sapl/static/sapl/frontend/js/compilacao.d421699a.js"},{"name":"css/compilacao.eff62463.css.map","publicPath":"/static/sapl/frontend/css/compilacao.eff62463.css.map","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.eff62463.css.map"},{"name":"js/compilacao.d421699a.js.map","publicPath":"/static/sapl/frontend/js/compilacao.d421699a.js.map","path":"../sapl/sapl/static/sapl/frontend/js/compilacao.d421699a.js.map"}],"global":[{"name":"css/global.278b5d61.css","publicPath":"/static/sapl/frontend/css/global.278b5d61.css","path":"../sapl/sapl/static/sapl/frontend/css/global.278b5d61.css"},{"name":"js/global.49490c4a.js","publicPath":"/static/sapl/frontend/js/global.49490c4a.js","path":"../sapl/sapl/static/sapl/frontend/js/global.49490c4a.js"},{"name":"css/global.278b5d61.css.map","publicPath":"/static/sapl/frontend/css/global.278b5d61.css.map","path":"../sapl/sapl/static/sapl/frontend/css/global.278b5d61.css.map"},{"name":"js/global.49490c4a.js.map","publicPath":"/static/sapl/frontend/js/global.49490c4a.js.map","path":"../sapl/sapl/static/sapl/frontend/js/global.49490c4a.js.map"}],"painel":[{"name":"css/painel.5d957a9b.css","publicPath":"/static/sapl/frontend/css/painel.5d957a9b.css","path":"../sapl/sapl/static/sapl/frontend/css/painel.5d957a9b.css"},{"name":"js/painel.33e8b8a5.js","publicPath":"/static/sapl/frontend/js/painel.33e8b8a5.js","path":"../sapl/sapl/static/sapl/frontend/js/painel.33e8b8a5.js"},{"name":"css/painel.5d957a9b.css.map","publicPath":"/static/sapl/frontend/css/painel.5d957a9b.css.map","path":"../sapl/sapl/static/sapl/frontend/css/painel.5d957a9b.css.map"},{"name":"js/painel.33e8b8a5.js.map","publicPath":"/static/sapl/frontend/js/painel.33e8b8a5.js.map","path":"../sapl/sapl/static/sapl/frontend/js/painel.33e8b8a5.js.map"}],"parlamentar":[{"name":"css/parlamentar.0e433876.css","publicPath":"/static/sapl/frontend/css/parlamentar.0e433876.css","path":"../sapl/sapl/static/sapl/frontend/css/parlamentar.0e433876.css"},{"name":"js/parlamentar.35e37659.js","publicPath":"/static/sapl/frontend/js/parlamentar.35e37659.js","path":"../sapl/sapl/static/sapl/frontend/js/parlamentar.35e37659.js"},{"name":"css/parlamentar.0e433876.css.map","publicPath":"/static/sapl/frontend/css/parlamentar.0e433876.css.map","path":"../sapl/sapl/static/sapl/frontend/css/parlamentar.0e433876.css.map"},{"name":"js/parlamentar.35e37659.js.map","publicPath":"/static/sapl/frontend/js/parlamentar.35e37659.js.map","path":"../sapl/sapl/static/sapl/frontend/js/parlamentar.35e37659.js.map"}]}} {"status":"done","publicPath":"/static/sapl/frontend/","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.42151acc.css","publicPath":"/static/sapl/frontend/css/chunk-vendors.42151acc.css","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.42151acc.css"},{"name":"js/chunk-vendors.f8cff174.js","publicPath":"/static/sapl/frontend/js/chunk-vendors.f8cff174.js","path":"../sapl/sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js"},{"name":"css/chunk-vendors.42151acc.css.map","publicPath":"/static/sapl/frontend/css/chunk-vendors.42151acc.css.map","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.42151acc.css.map"},{"name":"js/chunk-vendors.f8cff174.js.map","publicPath":"/static/sapl/frontend/js/chunk-vendors.f8cff174.js.map","path":"../sapl/sapl/static/sapl/frontend/js/chunk-vendors.f8cff174.js.map"}],"compilacao":[{"name":"css/compilacao.eff62463.css","publicPath":"/static/sapl/frontend/css/compilacao.eff62463.css","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.eff62463.css"},{"name":"js/compilacao.d421699a.js","publicPath":"/static/sapl/frontend/js/compilacao.d421699a.js","path":"../sapl/sapl/static/sapl/frontend/js/compilacao.d421699a.js"},{"name":"css/compilacao.eff62463.css.map","publicPath":"/static/sapl/frontend/css/compilacao.eff62463.css.map","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.eff62463.css.map"},{"name":"js/compilacao.d421699a.js.map","publicPath":"/static/sapl/frontend/js/compilacao.d421699a.js.map","path":"../sapl/sapl/static/sapl/frontend/js/compilacao.d421699a.js.map"}],"global":[{"name":"css/global.278b5d61.css","publicPath":"/static/sapl/frontend/css/global.278b5d61.css","path":"../sapl/sapl/static/sapl/frontend/css/global.278b5d61.css"},{"name":"js/global.49490c4a.js","publicPath":"/static/sapl/frontend/js/global.49490c4a.js","path":"../sapl/sapl/static/sapl/frontend/js/global.49490c4a.js"},{"name":"css/global.278b5d61.css.map","publicPath":"/static/sapl/frontend/css/global.278b5d61.css.map","path":"../sapl/sapl/static/sapl/frontend/css/global.278b5d61.css.map"},{"name":"js/global.49490c4a.js.map","publicPath":"/static/sapl/frontend/js/global.49490c4a.js.map","path":"../sapl/sapl/static/sapl/frontend/js/global.49490c4a.js.map"}],"painel":[{"name":"css/painel.5d957a9b.css","publicPath":"/static/sapl/frontend/css/painel.5d957a9b.css","path":"../sapl/sapl/static/sapl/frontend/css/painel.5d957a9b.css"},{"name":"js/painel.33e8b8a5.js","publicPath":"/static/sapl/frontend/js/painel.33e8b8a5.js","path":"../sapl/sapl/static/sapl/frontend/js/painel.33e8b8a5.js"},{"name":"css/painel.5d957a9b.css.map","publicPath":"/static/sapl/frontend/css/painel.5d957a9b.css.map","path":"../sapl/sapl/static/sapl/frontend/css/painel.5d957a9b.css.map"},{"name":"js/painel.33e8b8a5.js.map","publicPath":"/static/sapl/frontend/js/painel.33e8b8a5.js.map","path":"../sapl/sapl/static/sapl/frontend/js/painel.33e8b8a5.js.map"}],"parlamentar":[{"name":"css/parlamentar.0e433876.css","publicPath":"/static/sapl/frontend/css/parlamentar.0e433876.css","path":"../sapl/sapl/static/sapl/frontend/css/parlamentar.0e433876.css"},{"name":"js/parlamentar.307451cf.js","publicPath":"/static/sapl/frontend/js/parlamentar.307451cf.js","path":"../sapl/sapl/static/sapl/frontend/js/parlamentar.307451cf.js"},{"name":"css/parlamentar.0e433876.css.map","publicPath":"/static/sapl/frontend/css/parlamentar.0e433876.css.map","path":"../sapl/sapl/static/sapl/frontend/css/parlamentar.0e433876.css.map"},{"name":"js/parlamentar.307451cf.js.map","publicPath":"/static/sapl/frontend/js/parlamentar.307451cf.js.map","path":"../sapl/sapl/static/sapl/frontend/js/parlamentar.307451cf.js.map"}]}}

35
scripts/gerar_hash_proposicoes.py

@ -0,0 +1,35 @@
# Gerar hash de proposições para recebimento sem recibo
from sapl.materia.models import Proposicao
from sapl.utils import gerar_hash_arquivo, SEPARADOR_HASH_PROPOSICAO
from datetime import datetime
def gerar_hash(proposicao):
if proposicao.texto_original:
try:
proposicao.hash_code = gerar_hash_arquivo(
proposicao.texto_original.path, str(proposicao.pk))
except IOError:
raise Exception("Existem proposicoes com arquivos inexistentes.")
elif proposicao.texto_articulado.exists():
ta = proposicao.texto_articulado.first()
proposicao.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(proposicao.pk)
print(proposicao.hash_code)
proposicao.save()
def gerar_hash_proposicoes():
di = datetime.now()
print(di)
props = Proposicao.objects.filter(hash_code='', data_recebimento__isnull=True).exclude(data_envio__isnull=True)
print("Total de proposicoes: %s" % props.count())
for prop in props:
try:
print(".",end="")
gerar_hash(prop)
except Exception as e:
print('Erro para proposicao', prop)
print(e)
elapsed = datetime.now() - di
print("\n {}s".format(elapsed.seconds))

2
setup.py

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

Loading…
Cancel
Save