Browse Source

Merge pull request #6 from interlegis/master

08/08/2017
pull/1374/head
Rogério Frá 7 years ago
committed by GitHub
parent
commit
29bb3e0171
  1. 5
      Dockerfile
  2. 0
      bug.txt
  3. 2
      docker-compose.yml
  4. 8
      docs/instalacao31.rst
  5. 1
      envfile
  6. 104
      sapl/api/forms.py
  7. 8
      sapl/api/urls.py
  8. 52
      sapl/api/views.py
  9. 14
      sapl/base/forms.py
  10. 20
      sapl/base/migrations/0005_auto_20170802_1428.py
  11. 21
      sapl/base/migrations/0006_auto_20170802_1908.py
  12. 19
      sapl/base/migrations/0007_auto_20170808_0850.py
  13. 8
      sapl/base/models.py
  14. 5
      sapl/base/urls.py
  15. 21
      sapl/base/views.py
  16. 3
      sapl/compilacao/compilacao_data_tables.sql
  17. 3
      sapl/crispy_layout_mixin.py
  18. 26
      sapl/legacy/migracao_documentos.py
  19. 92
      sapl/legacy/migration.py
  20. 8
      sapl/legacy/scripts/fix_tables.sql
  21. 92
      sapl/materia/forms.py
  22. 19
      sapl/materia/migrations/0010_auto_20170808_0850.py
  23. 2
      sapl/materia/models.py
  24. 90
      sapl/materia/views.py
  25. 12
      sapl/painel/views.py
  26. 34
      sapl/protocoloadm/forms.py
  27. 41
      sapl/protocoloadm/views.py
  28. 27
      sapl/sessao/views.py
  29. 7
      sapl/settings.py
  30. 15
      sapl/static/js/app.js
  31. 5
      sapl/templates/base/autor_form.html
  32. 2
      sapl/templates/crud/detail.html
  33. 47
      sapl/templates/materia/autoria_form.html
  34. 8
      sapl/templates/materia/layouts.yaml
  35. 22
      sapl/templates/materia/materialegislativa_filter.html
  36. 2
      sapl/templates/navbar.yaml
  37. 41
      sapl/templates/painel/index.html
  38. 2
      sapl/templates/protocoloadm/MateriaTemplate.html
  39. 2
      sapl/templates/protocoloadm/protocolo_list.html
  40. 8
      sapl/templates/search/search.html
  41. 6
      sapl/templates/sessao/mesa.html
  42. 20
      sapl/templates/sessao/pauta_sessao_detail.html
  43. 2
      sapl/templates/sistema.html
  44. 35
      scrap-js.js

5
Dockerfile

@ -4,7 +4,7 @@ ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig
python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev nodejs py3-lxml \ python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev nodejs py3-lxml \
py3-magic postgresql-client poppler-utils vim py3-magic postgresql-client poppler-utils vim
RUN apk add --no-cache python3 nginx && \ RUN apk add --no-cache python3 nginx tzdata && \
python3 -m ensurepip && \ python3 -m ensurepip && \
rm -r /usr/lib/python*/ensurepip && \ rm -r /usr/lib/python*/ensurepip && \
pip3 install --upgrade pip setuptools && \ pip3 install --upgrade pip setuptools && \
@ -30,6 +30,9 @@ RUN pip install -r /var/interlegis/sapl/requirements/dev-requirements.txt --upgr
COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env
# Configura timezone para BRT
# RUN cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime && echo "America/Sao_Paulo" > /etc/timezone
# manage.py bower install bug: https://github.com/nvbn/django-bower/issues/51 # manage.py bower install bug: https://github.com/nvbn/django-bower/issues/51
# compilescss - Precompile all occurrences of your SASS/SCSS files for the whole project into css files # compilescss - Precompile all occurrences of your SASS/SCSS files for the whole project into css files

0
bug.txt

2
docker-compose.yml

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

8
docs/instalacao31.rst

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

1
envfile

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

104
sapl/api/forms.py

@ -1,11 +1,15 @@
from django.db.models import Q from django.db.models import Q, F
from django.forms.fields import CharField, MultiValueField from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import MultiWidget, TextInput from django.forms.widgets import MultiWidget, TextInput
from django_filters.filters import MethodFilter, ModelChoiceFilter from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django_filters.filters import MethodFilter, ModelChoiceFilter, DateFilter
from rest_framework import serializers
from rest_framework.compat import django_filters from rest_framework.compat import django_filters
from rest_framework.filters import FilterSet from rest_framework.filters import FilterSet
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.parlamentares.models import Legislatura
from sapl.utils import generic_relations_for_model from sapl.utils import generic_relations_for_model
@ -38,11 +42,13 @@ class SaplGenericRelationSearchFilterSet(FilterSet):
item.related_query_name(), item.related_query_name(),
field[0]) field[0])
) )
if len(field) == 3 and field[2](qtext) is not None: # if len(field) == 3 and field[2](qtext) is not
# None:
q_fs = q_fs | Q(**{'%s__%s%s' % ( q_fs = q_fs | Q(**{'%s__%s%s' % (
item.related_query_name(), item.related_query_name(),
field[0], field[0],
field[1]): qtext if len(field) == 2 else field[2](qtext)}) field[1]): qtext if len(field) == 2
else field[2](qtext)})
q = q & q_fs q = q & q_fs
@ -115,3 +121,93 @@ class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
v = '1' if v == 'True' else '0' v = '1' if v == 'True' else '0'
params[key] = v params[key] = v
return queryset.filter(**params).distinct('nome').order_by('nome') return queryset.filter(**params).distinct('nome').order_by('nome')
class AutoresPossiveisFilterSet(FilterSet):
data_relativa = DateFilter(method='filter_data_relativa')
tipo = MethodFilter()
class Meta:
model = Autor
fields = ['data_relativa', 'tipo', ]
def filter_data_relativa(self, queryset, name, value):
return queryset
def filter_tipo(self, queryset, value):
try:
tipo = TipoAutor.objects.get(pk=value)
except:
raise serializers.ValidationError(_('Tipo de Autor inexistente.'))
qs = queryset.filter(tipo=tipo)
return qs
@property
def qs(self):
qs = super().qs
data_relativa = self.form.cleaned_data['data_relativa'] \
if 'data_relativa' in self.form.cleaned_data else None
tipo = self.form.cleaned_data['tipo'] \
if 'tipo' in self.form.cleaned_data else None
if not tipo and not data_relativa:
return qs
if tipo:
# não precisa de try except, já foi validado em filter_tipo
tipo = TipoAutor.objects.get(pk=tipo)
if not tipo.content_type:
return qs
filter_for_model = 'filter_%s' % tipo.content_type.model
if not hasattr(self, filter_for_model):
return qs
return getattr(self, filter_for_model)(qs, data_relativa)
def filter_parlamentar(self, queryset, data_relativa):
# não leva em conta afastamentos
if not data_relativa:
data_relativa = timezone.now()
legislatura_relativa = Legislatura.objects.filter(
data_inicio__lte=data_relativa,
data_fim__gte=data_relativa).first()
params = {
'parlamentar_set__mandato__data_inicio_mandato__lte':
data_relativa,
'parlamentar_set__mandato__data_fim_mandato__gte': data_relativa
}
if legislatura_relativa.atual():
params['parlamentar_set__ativo'] = True
qs = queryset.filter(**params).distinct()
return qs
def filter_frente(self, queryset, data_relativa):
# implementar regras específicas para frente
return queryset
def filter_comissao(self, queryset, data_relativa):
# implementar regras específicas para comissao
return queryset
def filter_orgao(self, queryset, data_relativa):
# implementar regras específicas para orgao
return queryset
def filter_bancada(self, queryset, data_relativa):
# implementar regras específicas para bancada
return queryset
def filter_bloco(self, queryset, data_relativa):
# implementar regras específicas para bloco
return queryset

8
sapl/api/urls.py

@ -3,7 +3,8 @@ from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from sapl.api.views import (AutorListView, MateriaLegislativaViewSet, from sapl.api.views import (AutorListView, MateriaLegislativaViewSet,
ModelChoiceView, SessaoPlenariaViewSet) ModelChoiceView, SessaoPlenariaViewSet,
AutoresPossiveisListView, AutoresProvaveisListView)
from .apps import AppConfig from .apps import AppConfig
@ -17,6 +18,11 @@ urlpatterns_router = router.urls
urlpatterns_api = [ urlpatterns_api = [
url(r'^autor/provaveis',
AutoresProvaveisListView.as_view(), name='autores_provaveis_list'),
url(r'^autor/possiveis',
AutoresPossiveisListView.as_view(), name='autores_possiveis_list'),
url(r'^autor', AutorListView.as_view(), name='autor_list'), url(r'^autor', AutorListView.as_view(), name='autor_list'),
url(r'^model/(?P<content_type>\d+)/(?P<pk>\d*)$', url(r'^model/(?P<content_type>\d+)/(?P<pk>\d*)$',

52
sapl/api/views.py

@ -9,7 +9,8 @@ from rest_framework.permissions import (AllowAny, IsAuthenticated,
IsAuthenticatedOrReadOnly) IsAuthenticatedOrReadOnly)
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from sapl.api.forms import AutorChoiceFilterSet, AutorSearchForFieldFilterSet from sapl.api.forms import AutorChoiceFilterSet, AutorSearchForFieldFilterSet,\
AutoresPossiveisFilterSet
from sapl.api.serializers import (AutorChoiceSerializer, AutorSerializer, from sapl.api.serializers import (AutorChoiceSerializer, AutorSerializer,
ChoiceSerializer, ChoiceSerializer,
MateriaLegislativaSerializer, MateriaLegislativaSerializer,
@ -57,14 +58,6 @@ class AutorListView(ListAPIView):
de Autores feita pelo django-filter de Autores feita pelo django-filter
-> processo usado nas pesquisas, o mais usado. -> processo usado nas pesquisas, o mais usado.
= 2 -> para (value, text) usados geralmente
em combobox, radiobox, checkbox, etc com pesquisa básica
de Autores mas feito para Possíveis Autores armazenados
segundo o ContentType associado ao Tipo de Autor via
relacionamento genérico.
Busca feita sem django-filter processada no get_queryset
-> processo no cadastro de autores para seleção e busca
dos possíveis autores
= 3 -> Devolve instancias da classe Autor filtradas pelo = 3 -> Devolve instancias da classe Autor filtradas pelo
django-filter django-filter
@ -78,7 +71,7 @@ class AutorListView(ListAPIView):
o django-filter é desativado e a busca é feita o django-filter é desativado e a busca é feita
no model do ContentType associado ao tipo. no model do ContentType associado ao tipo.
- q_0 / q_1 - q_0 faz o código ignorar "q"... - q_0 / q_1 - q_0 é opcional e quando usado, faz o código ignorar "q"...
q_0 -> campos lookup a serem filtrados em qualquer Model q_0 -> campos lookup a serem filtrados em qualquer Model
que implemente SaplGenericRelation que implemente SaplGenericRelation
@ -132,10 +125,8 @@ class AutorListView(ListAPIView):
""" """
TR_AUTOR_CHOICE_SERIALIZER = 1 TR_AUTOR_CHOICE_SERIALIZER = 1
TR_CHOICE_SERIALIZER = 2
TR_AUTOR_SERIALIZER = 3 TR_AUTOR_SERIALIZER = 3
# FIXME aplicar permissão correta de usuário
permission_classes = (IsAuthenticatedOrReadOnly,) permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all() queryset = Autor.objects.all()
model = Autor model = Autor
@ -152,7 +143,6 @@ class AutorListView(ListAPIView):
assert tr in ( assert tr in (
AutorListView.TR_AUTOR_CHOICE_SERIALIZER, AutorListView.TR_AUTOR_CHOICE_SERIALIZER,
AutorListView.TR_CHOICE_SERIALIZER,
AutorListView.TR_AUTOR_SERIALIZER), sapl_logger.info( AutorListView.TR_AUTOR_SERIALIZER), sapl_logger.info(
_("Tipo do Resultado a ser fornecido não existe!")) _("Tipo do Resultado a ser fornecido não existe!"))
except: except:
@ -161,16 +151,8 @@ class AutorListView(ListAPIView):
return tr return tr
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
"""
desativa o django-filter se a busca for por possiveis autores
parametro tr = TR_CHOICE_SERIALIZER
"""
if self.tr == AutorListView.TR_CHOICE_SERIALIZER:
self.filter_class = None
self.filter_backends = []
self.serializer_class = ChoiceSerializer
elif self.tr == AutorListView.TR_AUTOR_SERIALIZER: if self.tr == AutorListView.TR_AUTOR_SERIALIZER:
self.serializer_class = AutorSerializer self.serializer_class = AutorSerializer
self.permission_classes = (IsAuthenticated,) self.permission_classes = (IsAuthenticated,)
@ -179,12 +161,20 @@ class AutorListView(ListAPIView):
return ListAPIView.get(self, request, *args, **kwargs) return ListAPIView.get(self, request, *args, **kwargs)
class AutoresProvaveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
filter_class = None
filter_backends = []
serializer_class = ChoiceSerializer
def get_queryset(self): def get_queryset(self):
queryset = ListAPIView.get_queryset(self) queryset = ListAPIView.get_queryset(self)
if self.filter_backends:
return queryset
params = {'content_type__isnull': False} params = {'content_type__isnull': False}
tipo = '' tipo = ''
@ -252,6 +242,18 @@ class AutorListView(ListAPIView):
return r return r
class AutoresPossiveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
pagination_class = None
filter_class = AutoresPossiveisFilterSet
serializer_class = AutorChoiceSerializer
class MateriaLegislativaViewSet(ListModelMixin, class MateriaLegislativaViewSet(ListModelMixin,
RetrieveModelMixin, RetrieveModelMixin,
GenericViewSet): GenericViewSet):

14
sapl/base/forms.py

@ -1,4 +1,3 @@
import django_filters
from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton from crispy_forms.bootstrap import FieldWithButtons, InlineRadios, StrictButton
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Div, Field, Fieldset, Layout, Row from crispy_forms.layout import HTML, Button, Div, Field, Fieldset, Layout, Row
@ -13,8 +12,9 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models, transaction from django.db import models, transaction
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
@ -28,6 +28,7 @@ from sapl.utils import (RANGE_ANOS, ChoiceWithoutValidationField,
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
ACTION_CREATE_USERS_AUTOR_CHOICE = [ ACTION_CREATE_USERS_AUTOR_CHOICE = [
('C', _('Criar novo Usuário')), ('C', _('Criar novo Usuário')),
('A', _('Associar um usuário existente')), ('A', _('Associar um usuário existente')),
@ -336,8 +337,11 @@ class AutorForm(ModelForm):
_('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))
if qs_autor.filter(object_id=cd['autor_related']).exists(): qs_autor_selected = qs_autor.filter(
autor = qs_autor.filter(object_id=cd['autor_related']).first() object_id=cd['autor_related'],
content_type_id=cd['tipo'].content_type_id)
if qs_autor_selected.exists():
autor = qs_autor_selected.first()
raise ValidationError( raise ValidationError(
_('Já existe um autor Cadastrado para %s' _('Já existe um autor Cadastrado para %s'
) % autor.autor_related) ) % autor.autor_related)
@ -714,6 +718,7 @@ class ConfiguracoesAppForm(ModelForm):
class RecuperarSenhaForm(PasswordResetForm): class RecuperarSenhaForm(PasswordResetForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
row1 = to_row( row1 = to_row(
[('email', 12)]) [('email', 12)])
@ -740,6 +745,7 @@ class RecuperarSenhaForm(PasswordResetForm):
class NovaSenhaForm(SetPasswordForm): class NovaSenhaForm(SetPasswordForm):
def __init__(self, user, *args, **kwargs): def __init__(self, user, *args, **kwargs):
self.user = user self.user = user
super(NovaSenhaForm, self).__init__(user, *args, **kwargs) super(NovaSenhaForm, self).__init__(user, *args, **kwargs)

20
sapl/base/migrations/0005_auto_20170802_1428.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2017-08-02 14:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0004_auto_20170714_1838'),
]
operations = [
migrations.AlterField(
model_name='casalegislativa',
name='codigo',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Codigo'),
),
]

21
sapl/base/migrations/0006_auto_20170802_1908.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.11 on 2017-08-02 22:08
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0005_auto_20170802_1428'),
]
operations = [
migrations.AlterField(
model_name='casalegislativa',
name='codigo',
field=models.CharField(blank=True, default='', max_length=100, verbose_name='Codigo'),
preserve_default=False,
),
]

19
sapl/base/migrations/0007_auto_20170808_0850.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2017-08-08 08:50
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('base', '0006_auto_20170802_1908'),
]
operations = [
migrations.AlterModelOptions(
name='autor',
options={'ordering': ('nome',), 'verbose_name': 'Autor', 'verbose_name_plural': 'Autores'},
),
]

8
sapl/base/models.py

@ -1,11 +1,12 @@
import reversion
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import reversion
from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model from sapl.utils import UF, YES_NO_CHOICES, get_settings_auth_user_model
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')), TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo'))) ('R', _('Restritivo')))
@ -18,7 +19,9 @@ class CasaLegislativa(models.Model):
# TODO ajustar todos os max_length !!!! # TODO ajustar todos os max_length !!!!
# cod_casa => id (pk) # cod_casa => id (pk)
codigo = models.CharField(max_length=100, verbose_name=_('Codigo')) codigo = models.CharField(max_length=100,
blank=True,
verbose_name=_('Codigo'))
nome = models.CharField(max_length=100, verbose_name=_('Nome')) nome = models.CharField(max_length=100, verbose_name=_('Nome'))
sigla = models.CharField(max_length=100, verbose_name=_('Sigla')) sigla = models.CharField(max_length=100, verbose_name=_('Sigla'))
endereco = models.CharField(max_length=100, verbose_name=_('Endereço')) endereco = models.CharField(max_length=100, verbose_name=_('Endereço'))
@ -219,6 +222,7 @@ class Autor(models.Model):
verbose_name = _('Autor') verbose_name = _('Autor')
verbose_name_plural = _('Autores') verbose_name_plural = _('Autores')
unique_together = (('content_type', 'object_id'), ) unique_together = (('content_type', 'object_id'), )
ordering = ('nome',)
def __str__(self): def __str__(self):

5
sapl/base/urls.py

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

21
sapl/base/views.py

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

3
sapl/compilacao/compilacao_data_tables.sql

@ -258,9 +258,6 @@ INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id,
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (126, 1, false, 4, -1, false); INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (126, 1, false, 4, -1, false);
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 1, -1, false); INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 1, -1, false);
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 1, -1, false);
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 2, -1, true);
INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 2, -1, true); INSERT INTO compilacao_tipodispositivorelationship (filho_permitido_id, pai_id, filho_de_insercao_automatica, perfil_id, quantidade_permitida, permitir_variacao) VALUES (122, 119, false, 2, -1, true);

3
sapl/crispy_layout_mixin.py

@ -67,6 +67,9 @@ def get_field_display(obj, fieldname):
ou mesmo uma método no model. ou mesmo uma método no model.
""" """
value = getattr(obj, fieldname) value = getattr(obj, fieldname)
try:
verbose_name = value.model._meta.verbose_name
except AttributeError:
verbose_name = '' verbose_name = ''
else: else:

26
sapl/legacy/migracao_documentos.py

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

92
sapl/legacy/migration.py

@ -327,6 +327,9 @@ def obj_desnecessario(obj):
if (f.one_to_many or f.one_to_one) and f.auto_created] if (f.one_to_many or f.one_to_one) and f.auto_created]
sem_referencia = not any(rr.related_model.objects.filter( sem_referencia = not any(rr.related_model.objects.filter(
**{rr.field.name: obj}).exists() for rr in relacoes) **{rr.field.name: obj}).exists() for rr in relacoes)
if type(obj).__name__ == 'Parlamentar' and sem_referencia and \
obj.autor.all():
sem_referencia = False
return sem_referencia return sem_referencia
@ -655,12 +658,32 @@ def adjust_acompanhamentomateria(new, old):
def adjust_documentoadministrativo(new, old): def adjust_documentoadministrativo(new, old):
if new.numero_protocolo: if new.numero_protocolo:
try:
protocolo = Protocolo.objects.get(numero=new.numero_protocolo, protocolo = Protocolo.objects.get(numero=new.numero_protocolo,
ano=new.ano) ano=new.ano)
new.protocolo = protocolo new.protocolo = protocolo
except Exception:
try:
protocolo = Protocolo.objects.get(numero=new.numero_protocolo,
ano=new.ano+1)
new.protocolo = protocolo
except Exception:
protocolo = mommy.make(Protocolo, numero=new.numero_protocolo,
ano=new.ano)
with reversion.create_revision():
problema = 'Protocolo Vinculado [numero_protocolo=%s, '\
'ano=%s] não existe' % (new.numero_protocolo,
new.ano)
descricao = 'O protocolo inexistente foi criado'
warn(problema + ' => ' + descricao)
save_relation(obj=protocolo, problema=problema,
descricao=descricao, eh_stub=True)
reversion.set_comment('Protocolo não existia.')
def adjust_mandato(new, old): def adjust_mandato(new, old):
if old.dat_fim_mandato:
new.data_fim_mandato = old.dat_fim_mandato
if not new.data_fim_mandato: if not new.data_fim_mandato:
legislatura = Legislatura.objects.latest('data_fim') legislatura = Legislatura.objects.latest('data_fim')
new.data_fim_mandato = legislatura.data_fim new.data_fim_mandato = legislatura.data_fim
@ -727,8 +750,8 @@ def adjust_proposicao_antes_salvar(new, old):
def adjust_proposicao_depois_salvar(new, old): def adjust_proposicao_depois_salvar(new, old):
if not hasattr(old.dat_envio, 'year') or old.dat_envio.year == 1800: if not hasattr(old.dat_envio, 'year') or old.dat_envio.year == 1800:
msg = "O valor do campo data_envio (DateField) da model Proposicao" msg = "O valor do campo data_envio (DateField) da model Proposicao"\
"era inválido" " era inválido"
descricao = 'A data 1111-11-11 foi colocada no lugar' descricao = 'A data 1111-11-11 foi colocada no lugar'
problema = 'O valor da data era nulo ou inválido' problema = 'O valor da data era nulo ou inválido'
warn(msg + ' => ' + descricao) warn(msg + ' => ' + descricao)
@ -745,17 +768,22 @@ def adjust_normarelacionada(new, old):
new.tipo_vinculo = tipo[0] new.tipo_vinculo = tipo[0]
def adjust_protocolo(new, old): def adjust_protocolo_antes_salvar(new, old):
if new.numero is None and not primeira_vez: data_ajuste = date(2014, 11, 13)
p = ProtocoloLegado.objects.filter(
ano_protocolo=new.ano).aggregate(Max('num_protocolo')) if old.num_protocolo is None and data_ajuste >= old.dat_protocolo:
numero_maximo = p['num_protocolo__max'] new.numero = old.pk
new.numero = 1 if numero_maximo is None else numero_maximo + 1
primeira_vez.append(True)
if new.numero is None and primeira_vez: def adjust_protocolo_depois_salvar(new, old):
p = Protocolo.objects.filter( if old.num_protocolo is None:
ano=new.ano).aggregate(Max('numero')) with reversion.create_revision():
new.numero = p['numero__max'] + 1 problema = 'Número do protocolo de PK %s é nulo' % new.pk
descricao = 'Número do protocolo alterado para %s!' % new.numero
warn(problema + ' => ' + descricao)
save_relation(obj=new, problema=problema,
descricao=descricao, eh_stub=False)
reversion.set_comment('Número de protocolo teve que ser alterado')
def adjust_registrovotacao_antes_salvar(new, old): def adjust_registrovotacao_antes_salvar(new, old):
@ -835,21 +863,23 @@ def adjust_normajuridica_depois_salvar(new, old):
new.assuntos.add(AssuntoNorma.objects.get(pk=pk_assunto)) new.assuntos.add(AssuntoNorma.objects.get(pk=pk_assunto))
def adjust_protocolo_depois_salvar(new, old):
if old.num_protocolo is None:
with reversion.create_revision():
problema = 'Número do protocolo de PK %s é nulo' % new.pk
descricao = 'Número do protocolo alterado para %s!' % new.numero
warn(problema + ' => ' + descricao)
save_relation(obj=new, problema=problema,
descricao=descricao, eh_stub=False)
reversion.set_comment('Numero de protocolo teve que ser alterado')
def adjust_autor(new, old): def adjust_autor(new, old):
if old.cod_parlamentar: if old.cod_parlamentar:
try:
new.autor_related = Parlamentar.objects.get(pk=old.cod_parlamentar) new.autor_related = Parlamentar.objects.get(pk=old.cod_parlamentar)
except Exception:
with reversion.create_revision():
msg = 'Um parlamentar relacionado de PK [%s] não existia' \
% old.cod_parlamentar
reversion.set_comment('Stub criado pela migração')
value = make_stub(Parlamentar, old.cod_parlamentar)
descricao = 'stub criado para entrada orfã!'
warn(msg + ' => ' + descricao)
save_relation(value, [], msg, descricao,
eh_stub=True)
new.autor_related = value
new.nome = new.autor_related.nome_parlamentar new.nome = new.autor_related.nome_parlamentar
elif old.cod_comissao: elif old.cod_comissao:
new.autor_related = Comissao.objects.get(pk=old.cod_comissao) new.autor_related = Comissao.objects.get(pk=old.cod_comissao)
new.nome = new.autor_related.nome new.nome = new.autor_related.nome
@ -857,22 +887,14 @@ def adjust_autor(new, old):
if old.col_username: if old.col_username:
if not get_user_model().objects.filter( if not get_user_model().objects.filter(
username=old.col_username).exists(): username=old.col_username).exists():
user = get_user_model()( user = get_user_model()(username=old.col_username)
username=old.col_username, password=12345) user.set_password(12345)
with reversion.create_revision(): with reversion.create_revision():
user.save() user.save()
reversion.set_comment('Objeto criado pela migração') reversion.set_comment('Objeto criado pela migração')
grupo_autor = Group.objects.get(name="Autor") grupo_autor = Group.objects.get(name="Autor")
user.groups.add(grupo_autor) user.groups.add(grupo_autor)
if old.cod_parlamentar:
grupo_parlamentar = Group.objects.get(name="Parlamentar")
user.groups.add(grupo_parlamentar)
new.user = user
else:
new.user = get_user_model().objects.filter(
username=old.col_username)[0]
def adjust_comissao(new, old): def adjust_comissao(new, old):
@ -897,7 +919,7 @@ AJUSTE_ANTES_SALVAR = {
Parlamentar: adjust_parlamentar, Parlamentar: adjust_parlamentar,
Participacao: adjust_participacao, Participacao: adjust_participacao,
Proposicao: adjust_proposicao_antes_salvar, Proposicao: adjust_proposicao_antes_salvar,
Protocolo: adjust_protocolo, Protocolo: adjust_protocolo_antes_salvar,
RegistroVotacao: adjust_registrovotacao_antes_salvar, RegistroVotacao: adjust_registrovotacao_antes_salvar,
TipoAfastamento: adjust_tipoafastamento, TipoAfastamento: adjust_tipoafastamento,
TipoProposicao: adjust_tipoproposicao, TipoProposicao: adjust_tipoproposicao,

8
sapl/legacy/scripts/fix_tables.sql

@ -1,20 +1,24 @@
-- Apaga as restrições somente para essa sessão -- Apaga as restrições somente para essa sessão
SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES,',''); SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES,','ALLOW_INVALID_DATES');
-- Exclui procedures caso já existam -- Exclui procedures caso já existam
DROP PROCEDURE IF EXISTS verifica_campos_proposicao; DROP PROCEDURE IF EXISTS verifica_campos_proposicao;
DROP PROCEDURE IF EXISTS verifica_campos_tipo_materia_legislativa; DROP PROCEDURE IF EXISTS verifica_campos_tipo_materia_legislativa;
DROP PROCEDURE IF EXISTS verifica_campos_sessao_plenaria_presenca; DROP PROCEDURE IF EXISTS verifica_campos_sessao_plenaria_presenca;
DROP PROCEDURE IF EXISTS cria_lexml_registro_provedor_e_publicador; DROP PROCEDURE IF EXISTS cria_lexml_registro_provedor_e_publicador;
DROP PROCEDURE IF EXISTS muda_vinculo_norma_juridica_ind_excluido;
-- Procedure para criar campo num_proposicao em proposicao -- Procedure para criar campo num_proposicao em proposicao
CREATE PROCEDURE verifica_campos_proposicao() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='proposicao' AND column_name='num_proposicao') THEN ALTER TABLE proposicao ADD COLUMN num_proposicao INT(11) NULL after txt_justif_devolucao; END IF; END; CREATE PROCEDURE verifica_campos_proposicao() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='proposicao' AND column_name='num_proposicao') THEN UPDATE proposicao SET dat_envio = '1800-01-01' WHERE CAST(dat_envio AS CHAR(20)) = '0000-00-00 00:00:00'; ALTER TABLE proposicao ADD COLUMN num_proposicao INT(11) NULL after txt_justif_devolucao; END IF; END;
-- Procedure para criar campo iind_num_automatica em tipo_materia_legislativa -- Procedure para criar campo iind_num_automatica em tipo_materia_legislativa
CREATE PROCEDURE verifica_campos_tipo_materia_legislativa() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_materia_legislativa' AND column_name='ind_num_automatica') THEN ALTER TABLE tipo_materia_legislativa ADD COLUMN ind_num_automatica BOOLEAN NULL DEFAULT FALSE after des_tipo_materia; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_materia_legislativa' AND column_name='quorum_minimo_votacao') THEN ALTER TABLE tipo_materia_legislativa ADD COLUMN quorum_minimo_votacao INT(11) NULL after ind_num_automatica; END IF; END; CREATE PROCEDURE verifica_campos_tipo_materia_legislativa() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_materia_legislativa' AND column_name='ind_num_automatica') THEN ALTER TABLE tipo_materia_legislativa ADD COLUMN ind_num_automatica BOOLEAN NULL DEFAULT FALSE after des_tipo_materia; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='tipo_materia_legislativa' AND column_name='quorum_minimo_votacao') THEN ALTER TABLE tipo_materia_legislativa ADD COLUMN quorum_minimo_votacao INT(11) NULL after ind_num_automatica; END IF; END;
-- Procedure para criar campos cod_presenca_sessao (sendo a nova PK da tabela) e dat_sessao em sessao_plenaria_presenca -- Procedure para criar campos cod_presenca_sessao (sendo a nova PK da tabela) e dat_sessao em sessao_plenaria_presenca
CREATE PROCEDURE verifica_campos_sessao_plenaria_presenca() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='cod_presenca_sessao') THEN ALTER TABLE sessao_plenaria_presenca DROP PRIMARY KEY, ADD cod_presenca_sessao INT AUTO_INCREMENT PRIMARY KEY FIRST; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='dat_sessao') THEN ALTER TABLE sessao_plenaria_presenca ADD COLUMN dat_sessao DATE NULL after cod_parlamentar; END IF; END; CREATE PROCEDURE verifica_campos_sessao_plenaria_presenca() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='cod_presenca_sessao') THEN ALTER TABLE sessao_plenaria_presenca DROP PRIMARY KEY, ADD cod_presenca_sessao INT AUTO_INCREMENT PRIMARY KEY FIRST; END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='sessao_plenaria_presenca' AND column_name='dat_sessao') THEN ALTER TABLE sessao_plenaria_presenca ADD COLUMN dat_sessao DATE NULL after cod_parlamentar; END IF; END;
-- Procedure para criar tabela lexml_registro_provedor e lexml_registro_publicador -- Procedure para criar tabela lexml_registro_provedor e lexml_registro_publicador
CREATE PROCEDURE cria_lexml_registro_provedor_e_publicador() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_publicador') THEN CREATE TABLE lexml_registro_publicador (cod_publicador INT AUTO_INCREMENT NOT NULL, id_publicador INT, nom_publicador VARCHAR(255), adm_email VARCHAR(50), sigla VARCHAR(255), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, PRIMARY KEY (cod_publicador)); END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_provedor') THEN CREATE TABLE lexml_registro_provedor (cod_provedor INT AUTO_INCREMENT NOT NULL, id_provedor INT, nom_provedor VARCHAR(255), sgl_provedor VARCHAR(15), adm_email VARCHAR(50), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, xml_provedor LONGTEXT, PRIMARY KEY (cod_provedor)); END IF; END; CREATE PROCEDURE cria_lexml_registro_provedor_e_publicador() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_publicador') THEN CREATE TABLE lexml_registro_publicador (cod_publicador INT AUTO_INCREMENT NOT NULL, id_publicador INT, nom_publicador VARCHAR(255), adm_email VARCHAR(50), sigla VARCHAR(255), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, PRIMARY KEY (cod_publicador)); END IF; IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='lexml_registro_provedor') THEN CREATE TABLE lexml_registro_provedor (cod_provedor INT AUTO_INCREMENT NOT NULL, id_provedor INT, nom_provedor VARCHAR(255), sgl_provedor VARCHAR(15), adm_email VARCHAR(50), nom_responsavel VARCHAR(255), tipo VARCHAR(50), id_responsavel INT, xml_provedor LONGTEXT, PRIMARY KEY (cod_provedor)); END IF; END;
-- Procedure para mudar valor do campo ind_excluido da tabela vinculo_norma_juridica de 0 para string vazia ''
CREATE PROCEDURE muda_vinculo_norma_juridica_ind_excluido() BEGIN UPDATE vinculo_norma_juridica SET ind_excluido = '' WHERE trim(ind_excluido) = '0'; END;
-- Executa as procedures criadas acima -- Executa as procedures criadas acima
CALL verifica_campos_proposicao; CALL verifica_campos_proposicao;
CALL verifica_campos_tipo_materia_legislativa; CALL verifica_campos_tipo_materia_legislativa;
CALL verifica_campos_sessao_plenaria_presenca; CALL verifica_campos_sessao_plenaria_presenca;
CALL cria_lexml_registro_provedor_e_publicador; CALL cria_lexml_registro_provedor_e_publicador;
CALL muda_vinculo_norma_juridica_ind_excluido;

92
sapl/materia/forms.py

@ -13,17 +13,21 @@ from django.core.files.base import File
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models, transaction from django.db import models, transaction
from django.db.models import Max from django.db.models import Max
from django.forms import ModelForm, widgets from django.forms import ModelForm, ModelChoiceField, widgets
from django.forms.fields import BooleanField
from django.forms.forms import Form from django.forms.forms import Form
from django.forms.widgets import Select from django.forms.widgets import Select, HiddenInput
from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_filters.filterset import STRICTNESS
import django_filters import django_filters
from sapl.base.models import Autor from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.compilacao.forms import error_messages
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PRIVATE) STATUS_TA_PRIVATE)
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
@ -586,6 +590,45 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
form_actions(save_label='Pesquisar')) form_actions(save_label='Pesquisar'))
) )
@property
def qs(self):
if not hasattr(self, '_qs'):
valid = self.is_bound and self.form.is_valid()
if self.is_bound and not valid:
if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR:
raise forms.ValidationError(self.form.errors)
elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS:
self._qs = self.queryset.none()
return self._qs
# else STRICTNESS.IGNORE... ignoring
# start with all the results and filter from there
qs = self.queryset.all()
for name, filter_ in six.iteritems(self.filters):
value = None
if valid:
value = self.form.cleaned_data[name]
else:
raw_value = self.form[name].value()
try:
value = self.form.fields[name].clean(raw_value)
except forms.ValidationError:
if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR:
raise
elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS:
self._qs = self.queryset.none()
return self._qs
# else STRICTNESS.IGNORE... ignoring
if value is not None: # valid & clean data
qs = qs._next_is_sticky()
qs = filter_.filter(qs, value)
self._qs = qs
return self._qs
def pega_ultima_tramitacao(): def pega_ultima_tramitacao():
ultimas_tramitacoes = Tramitacao.objects.values( ultimas_tramitacoes = Tramitacao.objects.values(
@ -648,24 +691,45 @@ class DespachoInicialForm(ModelForm):
class AutoriaForm(ModelForm): class AutoriaForm(ModelForm):
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=False,
queryset=TipoAutor.objects.all(),
empty_label=_('Selecione'),)
data_relativa = forms.DateField(
widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
super(AutoriaForm, self).__init__(*args, **kwargs)
row1 = to_row([('tipo_autor', 4),
('autor', 4),
('primeiro_autor', 4)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(_('Autoria'),
row1, 'data_relativa', form_actions(save_label='Salvar')))
if not kwargs['instance']:
self.fields['autor'].choices = []
class Meta: class Meta:
model = Autoria model = Autoria
fields = ['autor', 'primeiro_autor'] fields = ['tipo_autor', 'autor', 'primeiro_autor', 'data_relativa']
def clean(self): def clean(self):
super(AutoriaForm, self).clean() cd = super(AutoriaForm, self).clean()
if self.errors: autorias = Autoria.objects.filter(
return self.errors materia=self.instance.materia, autor=cd['autor'])
pk = self.instance.pk
if Autoria.objects.filter( if ((not pk and autorias.exists())
materia=self.instance.materia, or (pk and autorias.exclude(pk=pk).exists())):
autor=self.cleaned_data['autor'], raise ValidationError(_('Esse Autor já foi cadastrado.'))
).exists():
msg = _('Esse Autor já foi cadastrado.')
raise ValidationError(msg)
return self.cleaned_data return cd
class AcessorioEmLoteFilterSet(django_filters.FilterSet): class AcessorioEmLoteFilterSet(django_filters.FilterSet):

19
sapl/materia/migrations/0010_auto_20170808_0850.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2017-08-08 08:50
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('materia', '0009_auto_20170712_0951'),
]
operations = [
migrations.AlterUniqueTogether(
name='autoria',
unique_together=set([('autor', 'materia')]),
),
]

2
sapl/materia/models.py

@ -299,6 +299,8 @@ class Autoria(models.Model):
class Meta: class Meta:
verbose_name = _('Autoria') verbose_name = _('Autoria')
verbose_name_plural = _('Autorias') verbose_name_plural = _('Autorias')
unique_together = (('autor', 'materia'), )
ordering = ('-primeiro_autor', 'autor__nome')
def __str__(self): def __str__(self):
return _('%(autor)s - %(materia)s') % { return _('%(autor)s - %(materia)s') % {

90
sapl/materia/views.py

@ -2,23 +2,6 @@ from datetime import datetime, date
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
from .email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, MateriaAssuntoForm,
MateriaLegislativaFilterSet, MateriaSimplificadaForm,
PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm,
RelatoriaForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaAssunto,
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao)
from .signals import tramitacao_signal
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML from crispy_forms.layout import HTML
from django import forms from django import forms
@ -39,7 +22,7 @@ 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_filters.views import FilterView from django_filters.views import FilterView
import sapl
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.comissoes.models import Comissao, Participacao from sapl.comissoes.models import Comissao, Participacao
@ -62,7 +45,25 @@ from sapl.protocoloadm.models import Protocolo
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url, autor_modal, gerar_hash_arquivo, get_base_url,
montar_row_autor) montar_row_autor)
import sapl
from .email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, MateriaAssuntoForm,
MateriaLegislativaFilterSet, MateriaSimplificadaForm,
PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm,
RelatoriaForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaAssunto,
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao)
from .signals import tramitacao_signal
AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia') AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia')
@ -958,6 +959,12 @@ class TramitacaoCrud(MasterDetailCrud):
def form_valid(self, form): def form_valid(self, form):
self.object = form.save() self.object = form.save()
if form.instance.status.indicador == 'F':
form.instance.materia.em_tramitacao = False
else:
form.instance.materia.em_tramitacao = True
form.instance.materia.save()
try: try:
tramitacao_signal.send(sender=Tramitacao, tramitacao_signal.send(sender=Tramitacao,
post=self.object, post=self.object,
@ -981,6 +988,12 @@ class TramitacaoCrud(MasterDetailCrud):
def form_valid(self, form): def form_valid(self, form):
self.object = form.save() self.object = form.save()
if form.instance.status.indicador == 'F':
form.instance.materia.em_tramitacao = False
else:
form.instance.materia.em_tramitacao = True
form.instance.materia.save()
try: try:
tramitacao_signal.send(sender=Tramitacao, tramitacao_signal.send(sender=Tramitacao,
post=self.object, post=self.object,
@ -1077,28 +1090,31 @@ class AutoriaCrud(MasterDetailCrud):
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
form_class = AutoriaForm form_class = AutoriaForm
def get_context_data(self, **kwargs): @property
context = super(CreateView, self).get_context_data(**kwargs) def layout_key(self):
autores_ativos = self.autores_ativos() return 'AutoriaCreate'
autores = [] def get_initial(self):
for a in autores_ativos: initial = super().get_initial()
autores.append([a.id, a.__str__()]) materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
initial['data_relativa'] = materia.data_apresentacao
initial['autor'] = []
return initial
context['form'].fields['autor'].choices = autores class UpdateView(MasterDetailCrud.UpdateView):
return context form_class = AutoriaForm
@property
def layout_key(self):
return 'AutoriaUpdate'
def autores_ativos(self): def get_initial(self):
lista_parlamentares = Parlamentar.objects.filter(ativo=True).values_list('id', flat=True) initial = super().get_initial()
model_parlamentar = ContentType.objects.get_for_model(Parlamentar) initial.update({
autor_parlamentar = Autor.objects.filter(content_type=model_parlamentar, object_id__in=lista_parlamentares) 'data_relativa': self.object.materia.data_apresentacao,
'tipo_autor': self.object.autor.tipo.id,
lista_comissoes = Comissao.objects.filter(Q(data_extincao__isnull=True)|Q(data_extincao__gt=date.today())).values_list('id', flat=True) })
model_comissao = ContentType.objects.get_for_model(Comissao) return initial
autor_comissoes = Autor.objects.filter(content_type=model_comissao, object_id__in=lista_comissoes)
autores_outros = Autor.objects.exclude(content_type__in=[model_parlamentar, model_comissao])
q = autor_parlamentar | autor_comissoes | autores_outros
return q
class DespachoInicialCrud(MasterDetailCrud): class DespachoInicialCrud(MasterDetailCrud):

12
sapl/painel/views.py

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

34
sapl/protocoloadm/forms.py

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

41
sapl/protocoloadm/views.py

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

27
sapl/sessao/views.py

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

7
sapl/settings.py

@ -22,6 +22,7 @@ from unipath import Path
from .temp_suppress_crispy_form_warnings import \ from .temp_suppress_crispy_form_warnings import \
SUPRESS_CRISPY_FORM_WARNINGS_LOGGING SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
BASE_DIR = Path(__file__).ancestor(1) BASE_DIR = Path(__file__).ancestor(1)
PROJECT_DIR = Path(__file__).ancestor(2) PROJECT_DIR = Path(__file__).ancestor(2)
@ -101,7 +102,7 @@ if SOLR_URL:
HAYSTACK_CONNECTIONS = { HAYSTACK_CONNECTIONS = {
'default': { 'default': {
'ENGINE': SEARCH_BACKEND, 'ENGINE': SEARCH_BACKEND,
SEARCH_URL[0] : SEARCH_URL[1] SEARCH_URL[0]: SEARCH_URL[1]
}, },
} }
@ -200,12 +201,12 @@ MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
# https://docs.djangoproject.com/en/1.8/topics/i18n/ # https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'pt-br' LANGUAGE_CODE = 'pt-br'
LANGUAGES = ( LANGUAGES = (
('pt-br','Português'), ('pt-br', 'Português'),
) )
TIME_ZONE = 'America/Sao_Paulo' TIME_ZONE = 'America/Sao_Paulo'
USE_I18N = True USE_I18N = True
USE_L10N = False USE_L10N = True
USE_TZ = False USE_TZ = False
# DATE_FORMAT = 'N j, Y' # DATE_FORMAT = 'N j, Y'
DATE_FORMAT = 'd/m/Y' DATE_FORMAT = 'd/m/Y'

15
sapl/static/js/app.js

@ -58,7 +58,7 @@ function autorModal() {
autoOpen: false, autoOpen: false,
modal: true, modal: true,
width: 500, width: 500,
height: 300, height: 340,
show: { show: {
effect: "blind", effect: "blind",
duration: 500}, duration: 500},
@ -90,11 +90,11 @@ function autorModal() {
$("#pesquisar").click(function() { $("#pesquisar").click(function() {
var name_in_query = $("#q").val() var name_in_query = $("#q").val()
var q_0 = "q_0=parlamentar_set__ativo,parlamentar_set__nome_parlamentar__icontains" //var q_0 = "q_0=nome__icontains"
var q_1 = "q_1=True," + name_in_query //var q_1 = name_in_query
query = q_0 + "&" + q_1 //query = q_1
$.get("/api/autor?" + query, function(data, status) { $.get("/api/autor?q=" + name_in_query, function(data, status) {
$("#div-resultado").children().remove(); $("#div-resultado").children().remove();
if (data.pagination.total_entries == 0) { if (data.pagination.total_entries == 0) {
$("#selecionar").attr("hidden", "hidden"); $("#selecionar").attr("hidden", "hidden");
@ -111,11 +111,12 @@ function autorModal() {
select.append($("<option>").attr('value', item.value).text(item.text)); select.append($("<option>").attr('value', item.value).text(item.text));
}); });
$("#div-resultado").append("<br/>").append(select); $("#div-resultado").append("<br/>").append(select);
$("#selecionar").removeAttr("hidden", "hidden"); $("#selecionar").removeAttr("hidden", "hidden");
if (data.pagination.total_pages > 1)
$("#div-resultado").prepend('<span><br/>Mostrando 10 primeiros autores relativos a sua busca.<br/></span>');
$("#selecionar").click(function() { $("#selecionar").click(function() {
res = $("#resultados option:selected"); res = $("#resultados option:selected");
id = res.val(); id = res.val();

5
sapl/templates/base/autor_form.html

@ -28,12 +28,11 @@ $(document).ready(function(){
var update_search = function(pk, atualizar=true) { var update_search = function(pk, atualizar=true) {
var q = $('#id_q').val(); var q = $('#id_q').val();
var url = '{% url 'sapl.api:autor_list'%}' var url = '{% url 'sapl.api:autores_provaveis_list'%}'
var formData = { var formData = {
'q' : q, 'q' : q,
'tipo' : pk, 'tipo' : pk
'tr' : '2' // tipo_resultado = 2 - api fornecerá possíveis Autores
} }
$.get(url, formData).done(function(data) { $.get(url, formData).done(function(data) {
active('pesquisa'); active('pesquisa');

2
sapl/templates/crud/detail.html

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

47
sapl/templates/materia/autoria_form.html

@ -0,0 +1,47 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% block extra_js %}
<script language="Javascript">
function compare(a, b) {
if (a.text < b.text)
return -1;
if (a.text > b.text)
return 1;
return 0;
}
$(document).ready(function() {
$("#id_tipo_autor").change(function() {
var tipo_selecionado = $("#id_tipo_autor").val();
var autor_selecionado = $("#id_autor").val();
$("#id_autor option").remove()
if (tipo_selecionado !== undefined && tipo_selecionado !== null) {
var json_data = {
tipo : tipo_selecionado,
data_relativa : $("#id_data_relativa").val()
}
$.getJSON("/api/autor/possiveis", json_data, function(data){
if (data) {
var results = data.sort(compare);
if (results.length > 1) {
$("#id_autor").append("<option>-----</option>");
}
$.each(results, function(idx, obj) {
$("#id_autor")
.append($("<option></option>")
.attr("value", obj.value)
.text(obj.text));
});
$("#id_autor").val(autor_selecionado);
}
});
}
});
$("#id_tipo_autor").trigger('change');
});
</script>
{% endblock %}

8
sapl/templates/materia/layouts.yaml

@ -61,6 +61,14 @@ Autoria:
{% trans 'Autoria' %}: {% trans 'Autoria' %}:
- autor primeiro_autor - autor primeiro_autor
AutoriaCreate:
{% trans 'Autoria' %}:
- tipo_autor autor primeiro_autor
AutoriaUpdate:
{% trans 'Autoria' %}:
- tipo_autor autor primeiro_autor
DocumentoAcessorio: DocumentoAcessorio:
{% trans 'Documento Acessório' %}: {% trans 'Documento Acessório' %}:
- tipo nome data - tipo nome data

22
sapl/templates/materia/materialegislativa_filter.html

@ -62,8 +62,10 @@
{% if m.autoria_set.all %} {% if m.autoria_set.all %}
<strong>Autor:</strong> <strong>Autor:</strong>
{% for a in m.autoria_set.all %} {% for a in m.autoria_set.all %}
{% if a.primeiro_autor %} {% if not forloop.first %}
&nbsp;{{a.autor.nome}} </br> {{a.autor}}
{% else %}
&nbsp;{{a.autor}}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</br> </br>
@ -76,17 +78,19 @@
<strong>Data Fim Prazo (Tramitação):</strong>&nbsp;{{m.tramitacao_set.last.data_fim_prazo|default_if_none:""}}</br> <strong>Data Fim Prazo (Tramitação):</strong>&nbsp;{{m.tramitacao_set.last.data_fim_prazo|default_if_none:""}}</br>
{% endif %} {% endif %}
{% if m.registrovotacao_set.exists %} {% if m.registrovotacao_set.exists %}
<strong>Data da última Votação:</strong> <strong>Data Votação:</strong>
{% if m.registrovotacao_set.last.ordem %} {% for rv in m.registrovotacao_set.all %}
<a href="{% url 'sapl.sessao:ordemdia_list' m.registrovotacao_set.last.ordem.sessao_plenaria_id %}"> {% if rv.ordem %}
{{ m.registrovotacao_set.last.ordem.data_ordem }} <a href="{% url 'sapl.sessao:ordemdia_list' rv.ordem.sessao_plenaria_id %}">
{{ rv.ordem.data_ordem }}
</a> </a>
{% elif m.registrovotacao_set.last.expediente %} {% elif rv.expediente %}
<a href="{% url 'sapl.sessao:expedientemateria_list' m.registrovotacao_set.last.expediente.sessao_plenaria_id %}"> <a href="{% url 'sapl.sessao:expedientemateria_list' rv.expediente.sessao_plenaria_id %}">
{{ m.registrovotacao_set.last.expediente.data_ordem }} {{ rv.expediente.data_ordem }}
</a> </a>
{% endif %} {% endif %}
</br> </br>
{% endfor %}
{% endif %} {% endif %}
{% if m.tramitacao_set.last.data_tramitacao %} {% if m.tramitacao_set.last.data_tramitacao %}
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.last.data_tramitacao}}</br> <strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.last.data_tramitacao}}</br>

2
sapl/templates/navbar.yaml

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

41
sapl/templates/painel/index.html

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

2
sapl/templates/protocoloadm/MateriaTemplate.html

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

2
sapl/templates/protocoloadm/protocolo_list.html

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

8
sapl/templates/search/search.html

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

6
sapl/templates/sessao/mesa.html

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

20
sapl/templates/sessao/pauta_sessao_detail.html

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

2
sapl/templates/sistema.html

@ -3,7 +3,7 @@
{% block base_content %} {% block base_content %}
<h2>Configuração Gerais</h2> <h2>Configurações Gerais</h2>
<div class="row"> <div class="row">
<div class="col-md-6"><a href="{% url 'sapl.base:casalegislativa_list' %}" class="btn btn-link">Casa Legislativa</a></div> <div class="col-md-6"><a href="{% url 'sapl.base:casalegislativa_list' %}" class="btn btn-link">Casa Legislativa</a></div>
<div class="col-md-6"><a href="{% url 'sapl.base:autor_list' %}" class="btn btn-link">Autor</a></div> <div class="col-md-6"><a href="{% url 'sapl.base:autor_list' %}" class="btn btn-link">Autor</a></div>

35
scrap-js.js

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