Browse Source

Faz o rebase com o master

pull/339/head
Eduardo Calil 9 years ago
parent
commit
dd6e9e6934
  1. 10
      base/forms.py
  2. 14
      crispy_layout_mixin.py
  3. 4
      crud/tests/test_base.py
  4. 75
      legacy/migration.py
  5. 235
      materia/forms.py
  6. 3
      materia/test_materia_urls.py
  7. 5
      materia/urls.py
  8. 161
      materia/views.py
  9. 10
      parlamentares/forms.py
  10. 2
      parlamentares/models.py
  11. 6
      parlamentares/test_parlamentares_urls.py
  12. 5
      protocoloadm/forms.py
  13. 1
      protocoloadm/views.py
  14. 1
      requirements/requirements.txt
  15. 5
      sapl/settings.py
  16. 5
      sapl/utils.py
  17. 12
      static/js/app.js
  18. 48
      templates/materia/materialegislativa_filter.html
  19. 8
      templates/materia/pesquisa_materia.html
  20. 26
      templates/materia/pesquisa_materia_list.html
  21. 10
      templates/materia/proposicao/proposicao_list.html

10
base/forms.py

@ -4,19 +4,15 @@ from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
import crispy_layout_mixin import crispy_layout_mixin
import sapl
from crispy_layout_mixin import form_actions from crispy_layout_mixin import form_actions
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
from .models import CasaLegislativa from .models import CasaLegislativa
class ImageThumbnailFileInput(ClearableFileInput):
template_name = 'floppyforms/image_thumbnail.html'
class CasaLegislativaTabelaAuxForm(ModelForm): class CasaLegislativaTabelaAuxForm(ModelForm):
class Meta: class Meta:
@ -41,9 +37,9 @@ class CasaLegislativaTabelaAuxForm(ModelForm):
'cep': forms.TextInput(attrs={'class': 'cep'}), 'cep': forms.TextInput(attrs={'class': 'cep'}),
'telefone': forms.TextInput(attrs={'class': 'telefone'}), 'telefone': forms.TextInput(attrs={'class': 'telefone'}),
'fax': forms.TextInput(attrs={'class': 'telefone'}), 'fax': forms.TextInput(attrs={'class': 'telefone'}),
'logotipo': ImageThumbnailFileInput, 'logotipo': sapl.utils.ImageThumbnailFileInput,
'informacao_geral': forms.Textarea( 'informacao_geral': forms.Textarea(
attrs={'id': 'casa-informacoes'}) attrs={'id': 'texto-rico'})
} }
def clean_logotipo(self): def clean_logotipo(self):

14
crispy_layout_mixin.py

@ -5,6 +5,7 @@ import rtyaml
from crispy_forms.bootstrap import FormActions from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit
from django.utils import formats
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
@ -57,9 +58,18 @@ def get_field_display(obj, fieldname):
if value is None: if value is None:
display = '' display = ''
elif 'date' in str(type(value)): elif 'date' in str(type(value)):
display = value.strftime("%d/%m/%Y") # TODO: localize display = formats.date_format(value, "SHORT_DATE_FORMAT")
elif 'bool' in str(type(value)): elif 'bool' in str(type(value)):
display = 'Sim' if value else 'Não' display = _('Sim') if value else _('Não')
elif 'ImageFieldFile' in str(type(value)):
display = '<img src="{}" />'.format(value.url)
elif 'FieldFile' in str(type(value)):
if value:
display = '<a href="{}">{}</a>'.format(
value.url,
value.name.split('/')[-1:][0])
else:
display = ''
else: else:
display = str(value) display = str(value)
return verbose_name, display return verbose_name, display

4
crud/tests/test_base.py

@ -87,7 +87,7 @@ def test_layout_fieldnames(_layout, result):
assert view.list_field_names == result assert view.list_field_names == result
def test_layout_detail_fieldsets(monkeypatch): def test_layout_detail_fieldsets():
stub = mommy.make(Country, stub = mommy.make(Country,
name='Brazil', name='Brazil',
@ -183,7 +183,7 @@ def assert_on_detail_page(res, stub_name):
(9, 4, [(0, 4), (4, 8), (8, 9)], ['Anterior', '1', '2', '3', 'Próxima']), (9, 4, [(0, 4), (4, 8), (8, 9)], ['Anterior', '1', '2', '3', 'Próxima']),
]) ])
def test_flux_list_paginate_detail( def test_flux_list_paginate_detail(
app, monkeypatch, num_entries, page_size, ranges, page_list): app, num_entries, page_size, ranges, page_list):
entries_labels = [] entries_labels = []
for i in range(num_entries): for i in range(num_entries):

75
legacy/migration.py

@ -27,6 +27,7 @@ appconfs = [apps.get_app_config(n) for n in [
'protocoloadm', ]] 'protocoloadm', ]]
stubs_list = [] stubs_list = []
unique_constraints = []
name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs] name_sets = [set(m.__name__ for m in ac.get_models()) for ac in appconfs]
@ -93,7 +94,6 @@ def warn(msg):
def get_fk_related(field, value, label=None): def get_fk_related(field, value, label=None):
fields_dict = {} fields_dict = {}
if value is None and field.null is False: if value is None and field.null is False:
value = 0 value = 0
if value is not None: if value is not None:
@ -105,7 +105,7 @@ def get_fk_related(field, value, label=None):
field.name, value, field.name, value,
field.model.__name__, label or '---') field.model.__name__, label or '---')
if value == 0: if value == 0:
# se FK == 0, criamos um stub e colocamos o valor '???????? # se FK == 0, criamos um stub e colocamos o valor '????????'
# para qualquer CharField ou TextField que possa haver # para qualquer CharField ou TextField que possa haver
if not field.null: if not field.null:
all_fields = field.related_model._meta.get_fields() all_fields = field.related_model._meta.get_fields()
@ -149,6 +149,37 @@ def iter_sql_records(sql, db):
yield record yield record
def delete_constraints(model):
# pega nome da unique constraint dado o nome da tabela
table = model._meta.db_table
cursor = exec_sql("SELECT conname FROM pg_constraint WHERE conrelid = "
"(SELECT oid FROM pg_class WHERE relname LIKE "
"'%s') and contype = 'u';" % (table))
result = cursor.fetchone()
# se existir um resultado, unique constraint será deletado
if result:
warn('Excluindo unique constraint de nome %s' % result)
args = model._meta.unique_together[0]
args_list = list(args)
unique_constraints.append([table, result[0], args_list, model])
exec_sql("ALTER TABLE %s DROP CONSTRAINT %s;" %
(table, result[0]))
def recreate_constraints():
if unique_constraints:
for constraint in unique_constraints:
table, name, args, model = constraint
for i in range(len(args)):
if isinstance(model._meta.get_field(args[i]),
models.ForeignKey):
args[i] = args[i]+'_id'
args_string = ''
args_string += "(" + ', '.join(map(str, args)) + ")"
exec_sql("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE %s;" %
(table, name, args_string))
def save_with_id(new, id): def save_with_id(new, id):
sequence_name = '%s_id_seq' % type(new)._meta.db_table sequence_name = '%s_id_seq' % type(new)._meta.db_table
cursor = exec_sql('SELECT last_value from %s;' % sequence_name) cursor = exec_sql('SELECT last_value from %s;' % sequence_name)
@ -169,7 +200,6 @@ def make_stub(model, id):
class DataMigrator: class DataMigrator:
def __init__(self): def __init__(self):
self.field_renames, self.model_renames = get_renames() self.field_renames, self.model_renames = get_renames()
@ -179,6 +209,8 @@ class DataMigrator:
for field in new._meta.fields: for field in new._meta.fields:
old_field_name = renames.get(field.name) old_field_name = renames.get(field.name)
field_type = field.get_internal_type() field_type = field.get_internal_type()
msg = ("Campo %s (%s) da model %s " %
(field.name, field_type, field.model.__name__))
if old_field_name: if old_field_name:
old_value = getattr(old, old_field_name) old_value = getattr(old, old_field_name)
if isinstance(field, models.ForeignKey): if isinstance(field, models.ForeignKey):
@ -187,17 +219,29 @@ class DataMigrator:
old_type._meta.pk.name != 'id': old_type._meta.pk.name != 'id':
label = old.pk label = old.pk
else: else:
label = '-- WITHOUT PK --' label = '-- SEM PK --'
value = get_fk_related(field, old_value, label) value = get_fk_related(field, old_value, label)
else: else:
value = getattr(old, old_field_name) value = getattr(old, old_field_name)
if (field_type == 'DateField' and
field.null is False and value is None):
names = [old_fields.name for old_fields
in old._meta.get_fields()]
combined_names = "(" + ")|(".join(names) + ")"
matches = re.search('(ano_\w+)', combined_names)
if not matches:
warn(msg +
'=> colocando valor 0000-01-01 para DateField')
value = '0001-01-01'
else:
value = '%d-01-01' % getattr(old, matches.group(0))
warn(msg +
"=> colocando %s para DateField não nulável" %
(value))
if field_type == 'CharField' or field_type == 'TextField': if field_type == 'CharField' or field_type == 'TextField':
if value is None: if value is None:
warn( warn(msg + "=> colocando string vazia para valor %s" %
"Field %s (%s) from model %s" (value))
" => settig empty string '' for %s value" %
(field.name, field_type, field.model.__name__,
value))
value = '' value = ''
setattr(new, field.name, value) setattr(new, field.name, value)
@ -205,14 +249,16 @@ class DataMigrator:
# warning: model/app migration order is of utmost importance # warning: model/app migration order is of utmost importance
self.to_delete = [] self.to_delete = []
info('Starting %s migration...' % obj) info('Começando migração: %s...' % obj)
self._do_migrate(obj) self._do_migrate(obj)
# exclude logically deleted in legacy base # exclude logically deleted in legacy base
info('Deleting models with ind_excluido...') info('Deletando models com ind_excluido...')
for obj in self.to_delete: for obj in self.to_delete:
obj.delete() obj.delete()
info('Deleting unnecessary stubs...') info('Deletando stubs desnecessários...')
self.delete_stubs() self.delete_stubs()
info('Recriando unique constraints...')
recreate_constraints()
def _do_migrate(self, obj): def _do_migrate(self, obj):
if isinstance(obj, AppConfig): if isinstance(obj, AppConfig):
@ -229,7 +275,7 @@ class DataMigrator:
'Parameter must be a Model, AppConfig or a sequence of them') 'Parameter must be a Model, AppConfig or a sequence of them')
def migrate_model(self, model): def migrate_model(self, model):
print('Migrating %s...' % model.__name__) print('Migrando %s...' % model.__name__)
legacy_model_name = self.model_renames.get(model, model.__name__) legacy_model_name = self.model_renames.get(model, model.__name__)
legacy_model = legacy_app.get_model(legacy_model_name) legacy_model = legacy_app.get_model(legacy_model_name)
@ -238,6 +284,7 @@ class DataMigrator:
# Clear all model entries # Clear all model entries
# They may have been created in a previous migration attempt # They may have been created in a previous migration attempt
model.objects.all().delete() model.objects.all().delete()
delete_constraints(model)
# setup migration strategy for tables with or without a pk # setup migration strategy for tables with or without a pk
if legacy_pk_name == 'id': if legacy_pk_name == 'id':
@ -304,7 +351,7 @@ def adjust_parlamentar(new_parlamentar, old):
# but data includes null values # but data includes null values
# => transform None to False # => transform None to False
if value is None: if value is None:
warn('null converted to False') warn('nulo convertido para falso')
new_parlamentar.unidade_deliberativa = False new_parlamentar.unidade_deliberativa = False

235
materia/forms.py

@ -1,7 +1,10 @@
import django_filters
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Submit from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Submit
from django import forms from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.db.models import Max
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -10,14 +13,14 @@ import sapl
from crispy_layout_mixin import form_actions from crispy_layout_mixin import form_actions
from norma.models import LegislacaoCitada, TipoNormaJuridica from norma.models import LegislacaoCitada, TipoNormaJuridica
from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import RANGE_ANOS
from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria, from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaLegislativa, DespachoInicial, DocumentoAcessorio, MateriaLegislativa,
Numeracao, Proposicao, Relatoria, StatusTramitacao, Numeracao, Proposicao, Relatoria, TipoMateriaLegislativa,
TipoMateriaLegislativa, Tramitacao, UnidadeTramitacao) Tramitacao)
ORDENACAO_MATERIAIS = [(1, 'Crescente'), ANO_CHOICES = [('', '---------')] + RANGE_ANOS
(2, 'Decrescente')]
def em_tramitacao(): def em_tramitacao():
@ -140,13 +143,13 @@ class DocumentoAcessorioForm(ModelForm):
[('tipo', 4), ('nome', 4), ('data', 4)]) [('tipo', 4), ('nome', 4), ('data', 4)])
row2 = crispy_layout_mixin.to_row( row2 = crispy_layout_mixin.to_row(
[('autor', 0), [('autor', 0),
(Button('pesquisar', (Button('pesquisar',
'Pesquisar Autor', 'Pesquisar Autor',
css_class='btn btn-primary btn-sm'), 2), css_class='btn btn-primary btn-sm'), 2),
(Button('limpar', (Button('limpar',
'Limpar Autor', 'Limpar Autor',
css_class='btn btn-primary btn-sm'), 10)]) css_class='btn btn-primary btn-sm'), 10)])
row3 = crispy_layout_mixin.to_row( row3 = crispy_layout_mixin.to_row(
[('ementa', 12)]) [('ementa', 12)])
@ -192,7 +195,7 @@ class TramitacaoForm(ModelForm):
label='Tramitando', label='Tramitando',
choices=[(True, 'Sim'), (False, 'Não')], choices=[(True, 'Sim'), (False, 'Não')],
widget=forms.Select( widget=forms.Select(
attrs={'class': 'selector'})) attrs={'class': 'selector'}))
class Meta: class Meta:
model = Tramitacao model = Tramitacao
@ -455,75 +458,90 @@ class AutoriaForm(ModelForm):
*args, **kwargs) *args, **kwargs)
class MateriaLegislativaPesquisaForm(ModelForm): class RangeWidgetOverride(forms.MultiWidget):
autor = forms.CharField(widget=forms.HiddenInput(), required=False) def __init__(self, attrs=None):
widgets = (forms.DateInput(format='%d/%m/%Y',
attrs={'class': 'dateinput',
'placeholder': 'Inicial'}),
forms.DateInput(format='%d/%m/%Y',
attrs={'class': 'dateinput',
'placeholder': 'Final'}))
super(RangeWidgetOverride, self).__init__(widgets, attrs)
localizacao = forms.ModelChoiceField( def decompress(self, value):
label='Localização Atual', if value:
required=False, return [value.start, value.stop]
queryset=UnidadeTramitacao.objects.all(), return [None, None]
empty_label='Selecione',
)
situacao = forms.ModelChoiceField( def format_output(self, rendered_widgets):
label='Situação', return ''.join(rendered_widgets)
required=False,
queryset=StatusTramitacao.objects.all(),
empty_label='Selecione', class MateriaLegislativaFilterSet(django_filters.FilterSet):
)
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
em_tramitacao = forms.ChoiceField(required=False, ano = django_filters.ChoiceFilter(required=False,
label='Tramitando', label=u'Ano da Matéria',
choices=em_tramitacao(), choices=ANO_CHOICES)
widget=forms.Select(
attrs={'class': 'selector'})) autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput())
publicacao_inicial = forms.DateField(label=u'Data Publicação Inicial', ementa = django_filters.CharFilter(lookup_expr='icontains')
input_formats=['%d/%m/%Y'],
required=False,
widget=forms.DateInput(
format='%d/%m/%Y',
attrs={'class': 'dateinput'}))
publicacao_final = forms.DateField(label=u'Data Publicação Final',
input_formats=['%d/%m/%Y'],
required=False,
widget=forms.DateInput(
format='%d/%m/%Y',
attrs={'class': 'dateinput'}))
apresentacao_inicial = forms.DateField(label=u'Data Apresentação Inicial',
input_formats=['%d/%m/%Y'],
required=False,
widget=forms.DateInput(
format='%d/%m/%Y',
attrs={'class': 'dateinput'}))
apresentacao_final = forms.DateField(label=u'Data Apresentação Final',
input_formats=['%d/%m/%Y'],
required=False,
widget=forms.DateInput(
format='%d/%m/%Y',
attrs={'class': 'dateinput'}))
class Meta: class Meta:
model = MateriaLegislativa model = MateriaLegislativa
fields = ['tipo', fields = ['numero',
'numero',
'ano',
'numero_protocolo', 'numero_protocolo',
'apresentacao_inicial', 'ano',
'apresentacao_final', 'tipo',
'publicacao_inicial', 'data_apresentacao',
'publicacao_final', 'data_publicacao',
'autor', 'autoria__autor__tipo',
'autoria__partido',
'relatoria__parlamentar_id',
'local_origem_externa', 'local_origem_externa',
'localizacao', 'tramitacao__unidade_tramitacao_destino',
'tramitacao__status',
'em_tramitacao', 'em_tramitacao',
'situacao'] ]
order_by = (
('', 'Selecione'),
('dataC', 'Data, Tipo, Ano, Numero - Ordem Crescente'),
('dataD', 'Data, Tipo, Ano, Numero - Ordem Decrescente'),
('tipoC', 'Tipo, Ano, Numero, Data - Ordem Crescente'),
('tipoD', 'Tipo, Ano, Numero, Data - Ordem Decrescente')
)
order_by_mapping = {
'': [],
'dataC': ['data_apresentacao', 'tipo__sigla', 'ano', 'numero'],
'dataD': ['-data_apresentacao', '-tipo__sigla', '-ano', '-numero'],
'tipoC': ['tipo__sigla', 'ano', 'numero', 'data_apresentacao'],
'tipoD': ['-tipo__sigla', '-ano', '-numero', '-data_apresentacao'],
}
def get_order_by(self, order_value):
if order_value in self.order_by_mapping:
return self.order_by_mapping[order_value]
else:
return super(MateriaLegislativaFilterSet,
self).get_order_by(order_value)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['autoria__autor__tipo'].label = 'Tipo de Autor'
self.filters['autoria__partido'].label = 'Partido do Autor'
self.filters['relatoria__parlamentar_id'].label = 'Relatoria'
row1 = crispy_layout_mixin.to_row( row1 = crispy_layout_mixin.to_row(
[('tipo', 12)]) [('tipo', 12)])
@ -532,34 +550,73 @@ class MateriaLegislativaPesquisaForm(ModelForm):
('ano', 4), ('ano', 4),
('numero_protocolo', 4)]) ('numero_protocolo', 4)])
row3 = crispy_layout_mixin.to_row( row3 = crispy_layout_mixin.to_row(
[('apresentacao_inicial', 6), [('data_apresentacao', 6),
('apresentacao_final', 6)]) ('data_publicacao', 6)])
row4 = crispy_layout_mixin.to_row( row4 = crispy_layout_mixin.to_row(
[('publicacao_inicial', 6), [('autoria__autor', 0),
('publicacao_final', 6)]) (Button('pesquisar',
'Pesquisar Autor',
css_class='btn btn-primary btn-sm'), 2),
(Button('limpar',
'limpar Autor',
css_class='btn btn-primary btn-sm'), 10)])
row5 = crispy_layout_mixin.to_row( row5 = crispy_layout_mixin.to_row(
[('autor', 0), [('autoria__autor__tipo', 6),
(Button('pesquisar', ('autoria__partido', 6)])
'Pesquisar Autor',
css_class='btn btn-primary btn-sm'), 2),
(Button('limpar',
'limpar Autor',
css_class='btn btn-primary btn-sm'), 10)])
row6 = crispy_layout_mixin.to_row( row6 = crispy_layout_mixin.to_row(
[('local_origem_externa', 6), [('relatoria__parlamentar_id', 6),
('localizacao', 6)]) ('local_origem_externa', 6)])
row7 = crispy_layout_mixin.to_row( row7 = crispy_layout_mixin.to_row(
[('tramitacao__unidade_tramitacao_destino', 6),
('tramitacao__status', 6)])
row8 = crispy_layout_mixin.to_row(
[('em_tramitacao', 6), [('em_tramitacao', 6),
('situacao', 6)]) ('o', 6)])
row9 = crispy_layout_mixin.to_row(
[('ementa', 12)])
self.helper = FormHelper() self.form.helper = FormHelper()
self.helper.layout = Layout( self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa Básica'), Fieldset(_('Pesquisa Básica'),
row1, row2, row3, row4, row1, row2, row3,
HTML(sapl.utils.autor_label), HTML(sapl.utils.autor_label),
HTML(sapl.utils.autor_modal), HTML(sapl.utils.autor_modal),
row5, row6, row7, row4, row5, row6, row7, row8, row9,
form_actions(save_label='Pesquisar')) form_actions(save_label='Pesquisar'))
) )
super(MateriaLegislativaPesquisaForm, self).__init__(
*args, **kwargs)
def pega_ultima_tramitacao():
ultimas_tramitacoes = Tramitacao.objects.values(
'materia_id').annotate(data_encaminhamento=Max(
'data_encaminhamento'),
id=Max('id')).values_list('id')
lista = [item for sublist in ultimas_tramitacoes for item in sublist]
return lista
def filtra_tramitacao_status(status):
lista = pega_ultima_tramitacao()
return Tramitacao.objects.filter(
id__in=lista,
status=status).distinct().values_list('materia_id', flat=True)
def filtra_tramitacao_destino(destino):
lista = pega_ultima_tramitacao()
return Tramitacao.objects.filter(
id__in=lista,
unidade_tramitacao_destino=destino).distinct().values_list(
'materia_id', flat=True)
def filtra_tramitacao_destino_and_status(status, destino):
lista = pega_ultima_tramitacao()
return Tramitacao.objects.filter(
id__in=lista,
status=status,
unidade_tramitacao_destino=destino).distinct().values_list(
'materia_id', flat=True)

3
materia/test_materia_urls.py

@ -3,9 +3,6 @@ from django.core.urlresolvers import reverse
@pytest.mark.parametrize("test_input,kwargs,expected", [ @pytest.mark.parametrize("test_input,kwargs,expected", [
('materia:pesquisar_materia_list',
{},
'/materia/pesquisar-materia-list'),
('materia:relatoria_edit', ('materia:relatoria_edit',
{'pk': '11', 'id': '99'}, {'pk': '11', 'id': '99'},
'/materia/11/relatoria/99/edit'), '/materia/11/relatoria/99/edit'),

5
materia/urls.py

@ -11,8 +11,7 @@ from materia.views import (AcompanhamentoConfirmarView,
MateriaLegislativaCrud, MateriaLegislativaCrud,
MateriaLegislativaPesquisaView, MateriaTaView, MateriaLegislativaPesquisaView, MateriaTaView,
NumeracaoEditView, NumeracaoView, OrgaoCrud, NumeracaoEditView, NumeracaoView, OrgaoCrud,
OrigemCrud, PesquisaMateriaListView, OrigemCrud, ProposicaoEditView, ProposicaoListView,
ProposicaoEditView, ProposicaoListView,
ProposicaoTaView, ProposicaoView, ProposicaoTaView, ProposicaoView,
RegimeTramitacaoCrud, RelatoriaEditView, RegimeTramitacaoCrud, RelatoriaEditView,
RelatoriaView, StatusTramitacaoCrud, TipoAutorCrud, RelatoriaView, StatusTramitacaoCrud, TipoAutorCrud,
@ -93,8 +92,6 @@ urlpatterns = [
ProposicaoEditView.as_view(), name='editar_proposicao'), ProposicaoEditView.as_view(), name='editar_proposicao'),
url(r'^materia/pesquisar-materia$', url(r'^materia/pesquisar-materia$',
MateriaLegislativaPesquisaView.as_view(), name='pesquisar_materia'), MateriaLegislativaPesquisaView.as_view(), name='pesquisar_materia'),
url(r'^materia/pesquisar-materia-list$',
PesquisaMateriaListView.as_view(), name='pesquisar_materia_list'),
url(r'^materia/(?P<pk>\d+)/acompanhar-materia/$', url(r'^materia/(?P<pk>\d+)/acompanhar-materia/$',
AcompanhamentoMateriaView.as_view(), name='acompanhar_materia'), AcompanhamentoMateriaView.as_view(), name='acompanhar_materia'),
url(r'^materia/(?P<pk>\d+)/acompanhar-confirmar$', url(r'^materia/(?P<pk>\d+)/acompanhar-confirmar$',

161
materia/views.py

@ -12,6 +12,7 @@ from django.shortcuts import redirect
from django.template import Context, loader from django.template import Context, loader
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, FormView, ListView, TemplateView from django.views.generic import CreateView, FormView, ListView, TemplateView
from django_filters.views import FilterView
import crud.base import crud.base
from base.models import CasaLegislativa from base.models import CasaLegislativa
@ -25,8 +26,10 @@ from sapl.utils import get_base_url
from .forms import (AcompanhamentoMateriaForm, AutoriaForm, from .forms import (AcompanhamentoMateriaForm, AutoriaForm,
DespachoInicialForm, DocumentoAcessorioForm, DespachoInicialForm, DocumentoAcessorioForm,
LegislacaoCitadaForm, MateriaAnexadaForm, LegislacaoCitadaForm, MateriaAnexadaForm,
MateriaLegislativaPesquisaForm, NumeracaoForm, MateriaLegislativaFilterSet, NumeracaoForm, ProposicaoForm,
ProposicaoForm, RelatoriaForm, TramitacaoForm) RelatoriaForm, TramitacaoForm, filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria, from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
DespachoInicial, DocumentoAcessorio, MateriaLegislativa, DespachoInicial, DocumentoAcessorio, MateriaLegislativa,
Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao, Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao,
@ -219,7 +222,7 @@ class MateriaAnexadaEditView(FormView):
def get_success_url(self): def get_success_url(self):
pk = self.kwargs['pk'] pk = self.kwargs['pk']
return reverse('materia:materia_anexada', kwargs={'pk': pk}) return reverse('materia_anexada', kwargs={'pk': pk})
class DespachoInicialView(CreateView): class DespachoInicialView(CreateView):
@ -1186,118 +1189,78 @@ class ProposicaoListView(ListView):
return context return context
class MateriaLegislativaPesquisaView(FormView): class MateriaLegislativaPesquisaView(FilterView):
template_name = 'materia/pesquisa_materia.html' model = MateriaLegislativa
filterset_class = MateriaLegislativaFilterSet
def get_success_url(self): paginate_by = 10
return reverse('materia:pesquisar_materia')
def get(self, request, *args, **kwargs):
form = MateriaLegislativaPesquisaForm()
return self.render_to_response({'form': form})
def post(self, request, *args, **kwargs):
kwargs = {}
form = MateriaLegislativaPesquisaForm(request.POST)
if form.data['tipo']: def get_filterset_kwargs(self, filterset_class):
kwargs['tipo'] = form.data['tipo'] super(MateriaLegislativaPesquisaView,
self).get_filterset_kwargs(filterset_class)
if form.data['numero']: kwargs = {'data': self.request.GET or None}
kwargs['numero'] = form.data['numero']
if form.data['ano']: status_tramitacao = self.request.GET.get('tramitacao__status')
kwargs['ano'] = form.data['ano'] unidade_destino = self.request.GET.get(
'tramitacao__unidade_tramitacao_destino')
if form.data['numero_protocolo']: qs = self.get_queryset()
kwargs['numero_protocolo'] = form.data['numero_protocolo']
if (form.data['apresentacao_inicial'] and if status_tramitacao and unidade_destino:
form.data['apresentacao_final']): lista = filtra_tramitacao_destino_and_status(status_tramitacao,
kwargs['apresentacao_inicial'] = form.data['apresentacao_inicial'] unidade_destino)
kwargs['apresentacao_final'] = form.data['apresentacao_final'] qs = qs.filter(id__in=lista).distinct()
if (form.data['publicacao_inicial'] and elif status_tramitacao:
form.data['publicacao_final']): lista = filtra_tramitacao_status(status_tramitacao)
kwargs['publicacao_inicial'] = form.data['publicacao_inicial'] qs = qs.filter(id__in=lista).distinct()
kwargs['publicacao_final'] = form.data['publicacao_final']
if form.data['local_origem_externa']: elif unidade_destino:
kwargs['local_origem_externa'] = form.data['local_origem_externa'] lista = filtra_tramitacao_destino(unidade_destino)
qs = qs.filter(id__in=lista).distinct()
if form.data['autor']: kwargs.update({
kwargs['autor'] = form.data['autor'] 'queryset': qs,
})
return kwargs
if form.data['localizacao']: def get_context_data(self, **kwargs):
kwargs['localizacao'] = form.data['localizacao'] context = super(MateriaLegislativaPesquisaView,
self).get_context_data(**kwargs)
if form.data['em_tramitacao']: paginator = context['paginator']
kwargs['em_tramitacao'] = form.data['em_tramitacao'] page_obj = context['page_obj']
if form.data['situacao']: context['page_range'] = make_pagination(
kwargs['situacao'] = form.data['situacao'] page_obj.number, paginator.num_pages)
request.session['kwargs'] = kwargs return context
return redirect('materia:pesquisar_materia_list') def get(self, request, *args, **kwargs):
super(MateriaLegislativaPesquisaView, self).get(request)
# Se a pesquisa estiver quebrando com a paginação
# Olhe esta função abaixo
# Provavelmente você criou um novo campo no Form/FilterSet
# Então a ordem da URL está diferente
data = self.filterset.data
if (data and data.get('tipo') is not None):
url = "&"+str(self.request.environ['QUERY_STRING'])
if url.startswith("&page"):
ponto_comeco = url.find('tipo=') - 1
url = url[ponto_comeco:]
else:
url = ''
self.filterset.form.fields['o'].label = _('Ordenação')
class PesquisaMateriaListView(ListView): context = self.get_context_data(filter=self.filterset,
template_name = 'materia/pesquisa_materia_list.html' object_list=self.object_list,
context_object_name = 'materias' filter_url=url,
model = MateriaLegislativa numero_res=len(self.object_list)
paginate_by = 10 )
def get_queryset(self): return self.render_to_response(context)
kwargs = self.request.session['kwargs']
materias = MateriaLegislativa.objects.all().order_by(
'-numero', '-ano')
if 'apresentacao_inicial' in kwargs:
inicial = datetime.strptime(
kwargs['apresentacao_inicial'],
'%d/%m/%Y').strftime('%Y-%m-%d')
final = datetime.strptime(
kwargs['apresentacao_final'],
'%d/%m/%Y').strftime('%Y-%m-%d')
materias = materias.filter(
data_apresentacao__range=(inicial, final))
if 'publicacao_inicial' in kwargs:
inicial = datetime.strptime(
kwargs['publicacao_inicial'],
'%d/%m/%Y').strftime('%Y-%m-%d')
final = datetime.strptime(
kwargs['publicacao_final'],
'%d/%m/%Y').strftime('%Y-%m-%d')
materias = materias.filter(
data_publicacao__range=(inicial, final))
if 'tipo' in kwargs:
materias = materias.filter(tipo_id=kwargs['tipo'])
if 'numero' in kwargs:
materias = materias.filter(numero=kwargs['numero'])
if 'ano' in kwargs:
materias = materias.filter(ano=kwargs['ano'])
if 'numero_protocolo' in kwargs:
materias = materias.filter(numero=kwargs['numero_protocolo'])
if 'em_tramitacao' in kwargs:
materias = materias.filter(em_tramitacao=kwargs['em_tramitacao'])
if 'local_origem_externa' in kwargs:
materias = materias.filter(
local_origem_externa=kwargs['local_origem_externa'])
# autor
# localizao atual
# situacao
return materias
class ProposicaoView(CreateView): class ProposicaoView(CreateView):

10
parlamentares/forms.py

@ -4,24 +4,22 @@ from django import forms
from django.db import transaction from django.db import transaction
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
import crispy_layout_mixin import crispy_layout_mixin
import sapl
from crispy_layout_mixin import form_actions from crispy_layout_mixin import form_actions
from .models import Dependente, Filiacao, Legislatura, Mandato, Parlamentar from .models import Dependente, Filiacao, Legislatura, Mandato, Parlamentar
class ImageThumbnailFileInput(ClearableFileInput):
template_name = 'floppyforms/image_thumbnail.html'
class ParlamentarForm(ModelForm): class ParlamentarForm(ModelForm):
class Meta: class Meta:
model = Parlamentar model = Parlamentar
exclude = [] exclude = []
widgets = {'fotografia': ImageThumbnailFileInput} widgets = {'fotografia': sapl.utils.ImageThumbnailFileInput,
'biografia': forms.Textarea(
attrs={'id': 'texto-rico'})}
class ParlamentarCreateForm(ParlamentarForm): class ParlamentarCreateForm(ParlamentarForm):

2
parlamentares/models.py

@ -239,8 +239,6 @@ class Parlamentar(models.Model):
biografia = models.TextField( biografia = models.TextField(
blank=True, verbose_name=_('Biografia')) blank=True, verbose_name=_('Biografia'))
# XXX Esse atribuito foi colocado aqui para não atrapalhar a migração # XXX Esse atribuito foi colocado aqui para não atrapalhar a migração
unidade_deliberativa = models.BooleanField(
default=False, verbose_name=_('Unidade Deliberativa'))
fotografia = models.ImageField( fotografia = models.ImageField(
blank=True, blank=True,
null=True, null=True,

6
parlamentares/test_parlamentares_urls.py

@ -1,6 +0,0 @@
from django.core.urlresolvers import reverse
def test_urls_materia():
st = reverse('materia:pesquisar_materia_list')
assert st == '/materia/pesquisar-materia-list'

5
protocoloadm/forms.py

@ -117,6 +117,11 @@ class ProtocoloFilterSet(django_filters.FilterSet):
('tipo_protocolo', 4), ('tipo_protocolo', 4),
('tipo_materia', 4)]) ('tipo_materia', 4)])
row3 = crispy_layout_mixin.to_row(
[('tipo_documento', 4),
('tipo_protocolo', 4),
('tipo_materia', 4)])
row3 = crispy_layout_mixin.to_row( row3 = crispy_layout_mixin.to_row(
[('interessado', 6), [('interessado', 6),
('assunto_ementa', 6)]) ('assunto_ementa', 6)])

1
protocoloadm/views.py

@ -245,6 +245,7 @@ class ComprovanteProtocoloView(TemplateView):
autenticacao = _("** NULO **") autenticacao = _("** NULO **")
if not protocolo.anulado: if not protocolo.anulado:
# data is not i18n sensitive 'Y-m-d' is the right format.
autenticacao = str(protocolo.tipo_processo) + \ autenticacao = str(protocolo.tipo_processo) + \
protocolo.data.strftime("%Y/%m/%d") + \ protocolo.data.strftime("%Y/%m/%d") + \
str(protocolo.numero).zfill(6) str(protocolo.numero).zfill(6)

1
requirements/requirements.txt

@ -7,6 +7,7 @@ django-compressor==2.0
django-crispy-forms==1.6.0 django-crispy-forms==1.6.0
python-decouple==3.0 python-decouple==3.0
django-extra-views==0.7.1 django-extra-views==0.7.1
django-filter==0.13.0
django-model-utils==2.4 django-model-utils==2.4
django-sass-processor==0.3.4 django-sass-processor==0.3.4
django==1.9.5 django==1.9.5

5
sapl/settings.py

@ -122,8 +122,8 @@ EMAIL_HOST_USER = config('EMAIL_HOST_USER', cast=str)
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', cast=str) EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', cast=str)
EMAIL_PORT = config('EMAIL_PORT', cast=int) EMAIL_PORT = config('EMAIL_PORT', cast=int)
MAX_DOC_UPLOAD_SIZE = 5*1024*1024 # 5MB MAX_DOC_UPLOAD_SIZE = 5 * 1024 * 1024 # 5MB
MAX_IMAGE_UPLOAD_SIZE = 2*1024*1024 # 2MB MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/ # https://docs.djangoproject.com/en/1.8/topics/i18n/
@ -188,4 +188,5 @@ SASS_PROCESSOR_INCLUDE_DIRS = (BOWER_COMPONENTS_ROOT.child(
# see sapl.temp_suppress_crispy_form_warnings # see sapl.temp_suppress_crispy_form_warnings
LOGGING = SUPRESS_CRISPY_FORM_WARNINGS_LOGGING LOGGING = SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
# suprime texto de ajuda default do django-filter
FILTERS_HELP_TEXT_FILTER = False FILTERS_HELP_TEXT_FILTER = False

5
sapl/utils.py

@ -6,6 +6,7 @@ from django.apps import apps
from django.contrib import admin from django.contrib import admin
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
autor_label = ''' autor_label = '''
@ -33,6 +34,10 @@ autor_modal = '''
''' '''
class ImageThumbnailFileInput(ClearableFileInput):
template_name = 'floppyforms/image_thumbnail.html'
def register_all_models_in_admin(module_name): def register_all_models_in_admin(module_name):
appname = module_name.split('.')[0] appname = module_name.split('.')[0]
app = apps.get_app_config(appname) app = apps.get_app_config(appname)

12
static/js/app.js

@ -105,9 +105,17 @@ function autorModal() {
id = res.val(); id = res.val();
nome = res.text(); nome = res.text();
$("#id_autor").val(id);
$("#nome_autor").text(nome); $("#nome_autor").text(nome);
// MateriaLegislativa pesquisa Autor via a tabela Autoria
if ($('#id_autoria__autor').length) {
$('#id_autoria__autor').val(id);
}
// Protocolo pesquisa a própria tabela de Autor
if ($('#id_autor').length) {
$("#id_autor").val(id);
}
dialog.dialog( "close" ); dialog.dialog( "close" );
}); });
}); });
@ -119,5 +127,5 @@ $(document).ready(function(){
refreshDatePicker(); refreshDatePicker();
refreshMask(); refreshMask();
autorModal(); autorModal();
initTinymce("biografia-parlamentar,casa-informacoes"); initTinymce("texto-rico");
}); });

48
templates/materia/materialegislativa_filter.html

@ -0,0 +1,48 @@
{% extends "materia/materialegislativa_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block sections_nav %} {% endblock %}
{% block detail_content %}
<h1><b>Pesquisar Matéria</b></h1>
<br></br>
{% crispy filter.form %}
<p></p>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
{% if page_obj|length %}
{% if numero_res > 1 %}
<h3>Pesquisa concluída com sucesso! Foram encontradas {{numero_res}} matérias.</h3>
{% elif numero_res == 1 %}
<h3>Pesquisa concluída com sucesso! Foi encontrada {{numero_res}} matéria.</h3>
{% endif %}
{% for m in page_obj %}
<tr>
<td>
<strong><a href="{% url 'materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a></br>
{{ m.ementa|safe }}</br>
<strong>Localização Atual:</strong> {{m.tramitacao_set.last.unidade_tramitacao_destino|default_if_none:"Não Informada"}}</br>
<p></p>
</tr>
{% endfor %}
{% else %}
<tr>
<td>
<h3>Nenhuma matéria encontrada com essas especificações</h3>
</tr>
{% endif %}
</table>
{% include "paginacao.html" %}
{% endblock detail_content %}

8
templates/materia/pesquisa_materia.html

@ -1,8 +0,0 @@
{% extends "materia/materialegislativa_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block sections_nav %}{% endblock %}
{% block detail_content %}
{% crispy form %}
{% endblock %}

26
templates/materia/pesquisa_materia_list.html

@ -1,26 +0,0 @@
{% extends "materia/materialegislativa_detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block sections_nav %} {% endblock %}
{% block detail_content %}
{% if materias %}
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
{% for m in materias %}
<tr>
<td>
<strong><a href="{% url 'materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a></br>
{{ m.ementa|safe }}</br>
<strong>Localização Atual:</strong> {{m.tramitacao_set.last.unidade_tramitacao_destino|default_if_none:"Não Informada"}}</br>
<p></p>
</tr>
{% endfor %}
</table>
{% include "paginacao.html" %}
{% else %}
<h2>Nenhum Registro recuperado</h2>
{% endif %}
{% endblock detail_content %}

10
templates/materia/proposicao/proposicao_list.html

@ -3,16 +3,16 @@
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %} {% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %}
<!--
{% block sections_nav %} {% block sections_nav %}
{% endblock %} --> {% endblock %}
{% block detail_content %} {% block detail_content %}
<div class="actions btn-group pull-right" role="group"> <h2><b>Proposições</b></h2>
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'materia:adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a> <a href="{% url 'materia:adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a>
</div> </div>
<h2><b>Proposições</b></h2>
<table class="table table-striped table-bordered"> <table class="table table-striped table-bordered">
<thead class="thead-default"> <thead class="thead-default">
<tr> <tr>

Loading…
Cancel
Save