mirror of https://github.com/interlegis/sapl.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
545 lines
17 KiB
545 lines
17 KiB
from datetime import datetime
|
|
|
|
import django_filters
|
|
from crispy_forms.helper import FormHelper
|
|
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
|
|
from django import forms
|
|
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.utils.translation import ugettext_lazy as _
|
|
|
|
import crispy_layout_mixin
|
|
import sapl
|
|
from comissoes.models import Comissao
|
|
from crispy_layout_mixin import form_actions
|
|
from norma.models import LegislacaoCitada, NormaJuridica, TipoNormaJuridica
|
|
from sapl.settings import MAX_DOC_UPLOAD_SIZE
|
|
from sapl.utils import RANGE_ANOS
|
|
|
|
from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
|
|
DespachoInicial, DocumentoAcessorio, MateriaLegislativa,
|
|
Numeracao, Proposicao, Relatoria, TipoMateriaLegislativa,
|
|
Tramitacao, UnidadeTramitacao)
|
|
|
|
ANO_CHOICES = [('', '---------')] + RANGE_ANOS
|
|
|
|
|
|
def em_tramitacao():
|
|
return [('', 'Tanto Faz'),
|
|
(True, 'Sim'),
|
|
(False, 'Não')]
|
|
|
|
|
|
class UnidadeTramitacaoForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = UnidadeTramitacao
|
|
fields = ['comissao', 'orgao', 'parlamentar']
|
|
|
|
def clean(self):
|
|
cleaned_data = self.cleaned_data
|
|
|
|
for key in list(cleaned_data.keys()):
|
|
if cleaned_data[key] is None:
|
|
del cleaned_data[key]
|
|
|
|
if len(cleaned_data) != 1:
|
|
msg = _('Somente um campo deve preenchido!')
|
|
raise ValidationError(msg)
|
|
return cleaned_data
|
|
|
|
|
|
class ProposicaoForm(ModelForm):
|
|
|
|
tipo_materia = forms.ModelChoiceField(
|
|
label=_('Matéria Vinculada'),
|
|
required=False,
|
|
queryset=TipoMateriaLegislativa.objects.all(),
|
|
empty_label='Selecione',
|
|
)
|
|
|
|
numero_materia = forms.CharField(
|
|
label='Número', required=False)
|
|
|
|
ano_materia = forms.CharField(
|
|
label='Ano', required=False)
|
|
|
|
def clean_texto_original(self):
|
|
texto_original = self.cleaned_data.get('texto_original', False)
|
|
if texto_original:
|
|
if texto_original.size > MAX_DOC_UPLOAD_SIZE:
|
|
raise ValidationError("Arquivo muito grande. ( > 5mb )")
|
|
return texto_original
|
|
|
|
def clean_data_envio(self):
|
|
data_envio = self.cleaned_data.get('data_envio')
|
|
if (not data_envio) and bool(self.initial):
|
|
data_envio = datetime.now()
|
|
return data_envio
|
|
|
|
def clean(self):
|
|
cleaned_data = self.cleaned_data
|
|
if 'tipo' in cleaned_data:
|
|
if cleaned_data['tipo'].descricao == 'Parecer':
|
|
try:
|
|
materia = MateriaLegislativa.objects.get(
|
|
tipo_id=cleaned_data['tipo_materia'],
|
|
ano=cleaned_data['ano_materia'],
|
|
numero=cleaned_data['numero_materia'])
|
|
except ObjectDoesNotExist:
|
|
msg = _('Matéria adicionada não existe!')
|
|
raise ValidationError(msg)
|
|
else:
|
|
cleaned_data['materia'] = materia
|
|
cleaned_data['autor'] = materia.autoria_set.first().autor
|
|
|
|
return cleaned_data
|
|
|
|
class Meta:
|
|
model = Proposicao
|
|
fields = ['tipo', 'data_envio', 'descricao', 'texto_original']
|
|
|
|
|
|
class AcompanhamentoMateriaForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = AcompanhamentoMateria
|
|
fields = ['email']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
row1 = crispy_layout_mixin.to_row([('email', 10)])
|
|
|
|
row1.append(
|
|
Column(form_actions(save_label='Cadastrar'), css_class='col-md-2')
|
|
)
|
|
|
|
self.helper = FormHelper()
|
|
self.helper.layout = Layout(
|
|
Fieldset(
|
|
_('Acompanhamento de Matéria por e-mail'), row1
|
|
)
|
|
)
|
|
super(AcompanhamentoMateriaForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
class DocumentoAcessorioForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = DocumentoAcessorio
|
|
fields = ['tipo', 'nome', 'data', 'autor', 'ementa', 'arquivo']
|
|
widgets = {'autor': forms.HiddenInput()}
|
|
|
|
def clean_autor(self):
|
|
autor_field = self.cleaned_data['autor']
|
|
try:
|
|
int(autor_field)
|
|
except ValueError:
|
|
return autor_field
|
|
else:
|
|
if autor_field:
|
|
return str(Autor.objects.get(id=autor_field))
|
|
|
|
|
|
class RelatoriaForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = Relatoria
|
|
fields = ['data_designacao_relator', 'comissao', 'parlamentar',
|
|
'data_destituicao_relator', 'tipo_fim_relatoria']
|
|
|
|
widgets = {'comissao': forms.Select(attrs={'disabled': 'disabled'})}
|
|
|
|
def clean(self):
|
|
cleaned_data = self.cleaned_data
|
|
|
|
try:
|
|
comissao = Comissao.objects.get(id=self.initial['comissao'])
|
|
except ObjectDoesNotExist:
|
|
msg = _('A localização atual deve ser uma comissão.')
|
|
raise ValidationError(msg)
|
|
else:
|
|
cleaned_data['comissao'] = comissao
|
|
|
|
return cleaned_data
|
|
|
|
|
|
class TramitacaoForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = Tramitacao
|
|
fields = ['data_tramitacao',
|
|
'unidade_tramitacao_local',
|
|
'status',
|
|
'turno',
|
|
'urgente',
|
|
'unidade_tramitacao_destino',
|
|
'data_encaminhamento',
|
|
'data_fim_prazo',
|
|
'texto']
|
|
|
|
def clean(self):
|
|
if self.errors:
|
|
return self.errors
|
|
|
|
ultima_tramitacao = Tramitacao.objects.filter(
|
|
materia_id=self.instance.materia.id).last()
|
|
|
|
if ultima_tramitacao:
|
|
destino = ultima_tramitacao.unidade_tramitacao_destino
|
|
if (destino != self.cleaned_data['unidade_tramitacao_local']):
|
|
msg = _('A origem da nova tramitação deve ser igual ao '
|
|
'destino da última adicionada!')
|
|
raise ValidationError(msg)
|
|
|
|
return self.cleaned_data
|
|
|
|
|
|
class LegislacaoCitadaForm(ModelForm):
|
|
|
|
tipo = forms.ModelChoiceField(
|
|
label=_('Tipo Norma'),
|
|
required=True,
|
|
queryset=TipoNormaJuridica.objects.all(),
|
|
empty_label='Selecione',
|
|
)
|
|
|
|
numero = forms.CharField(label='Número', required=True)
|
|
|
|
ano = forms.CharField(label='Ano', required=True)
|
|
|
|
class Meta:
|
|
model = LegislacaoCitada
|
|
fields = ['tipo',
|
|
'numero',
|
|
'ano',
|
|
'disposicoes',
|
|
'parte',
|
|
'livro',
|
|
'titulo',
|
|
'capitulo',
|
|
'secao',
|
|
'subsecao',
|
|
'artigo',
|
|
'paragrafo',
|
|
'inciso',
|
|
'alinea',
|
|
'item']
|
|
|
|
def clean(self):
|
|
if self.errors:
|
|
return self.errors
|
|
|
|
cleaned_data = self.cleaned_data
|
|
|
|
try:
|
|
norma = NormaJuridica.objects.get(
|
|
numero=cleaned_data['numero'],
|
|
ano=cleaned_data['ano'],
|
|
tipo=cleaned_data['tipo'])
|
|
except ObjectDoesNotExist:
|
|
msg = _('A norma a ser inclusa não existe no cadastro'
|
|
' de Normas.')
|
|
raise ValidationError(msg)
|
|
else:
|
|
cleaned_data['norma'] = norma
|
|
|
|
if LegislacaoCitada.objects.filter(
|
|
materia=self.instance.materia,
|
|
norma=cleaned_data['norma']
|
|
).exists():
|
|
msg = _('Essa Legislação já foi cadastrada.')
|
|
raise ValidationError(msg)
|
|
|
|
return cleaned_data
|
|
|
|
def save(self, commit=False):
|
|
legislacao = super(LegislacaoCitadaForm, self).save(commit)
|
|
legislacao.norma = self.cleaned_data['norma']
|
|
legislacao.save()
|
|
return legislacao
|
|
|
|
|
|
class NumeracaoForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = Numeracao
|
|
fields = ['tipo_materia',
|
|
'numero_materia',
|
|
'ano_materia',
|
|
'data_materia']
|
|
|
|
def clean(self):
|
|
if self.errors:
|
|
return self.errors
|
|
|
|
try:
|
|
MateriaLegislativa.objects.get(
|
|
numero=self.cleaned_data['numero_materia'],
|
|
ano=self.cleaned_data['ano_materia'],
|
|
tipo=self.cleaned_data['tipo_materia'])
|
|
except ObjectDoesNotExist:
|
|
msg = _('A matéria a ser inclusa não existe no cadastro'
|
|
' de matérias legislativas.')
|
|
raise ValidationError(msg)
|
|
|
|
if Numeracao.objects.filter(
|
|
materia=self.instance.materia,
|
|
tipo_materia=self.cleaned_data['tipo_materia'],
|
|
ano_materia=self.cleaned_data['ano_materia'],
|
|
numero_materia=self.cleaned_data['numero_materia']
|
|
).exists():
|
|
msg = _('Essa numeração já foi cadastrada.')
|
|
raise ValidationError(msg)
|
|
|
|
return self.cleaned_data
|
|
|
|
|
|
class AnexadaForm(ModelForm):
|
|
|
|
tipo = forms.ModelChoiceField(
|
|
label='Tipo',
|
|
required=True,
|
|
queryset=TipoMateriaLegislativa.objects.all(),
|
|
empty_label='Selecione',
|
|
)
|
|
|
|
numero = forms.CharField(label='Número', required=True)
|
|
|
|
ano = forms.CharField(label='Ano', required=True)
|
|
|
|
def clean(self):
|
|
if self.errors:
|
|
return self.errors
|
|
|
|
cleaned_data = self.cleaned_data
|
|
|
|
try:
|
|
materia_anexada = MateriaLegislativa.objects.get(
|
|
numero=cleaned_data['numero'],
|
|
ano=cleaned_data['ano'],
|
|
tipo=cleaned_data['tipo'])
|
|
except ObjectDoesNotExist:
|
|
msg = _('A matéria a ser anexada não existe no cadastro'
|
|
' de matérias legislativas.')
|
|
raise ValidationError(msg)
|
|
else:
|
|
cleaned_data['materia_anexada'] = materia_anexada
|
|
|
|
return cleaned_data
|
|
|
|
def save(self, commit=False):
|
|
anexada = super(AnexadaForm, self).save(commit)
|
|
anexada.materia_anexada = self.cleaned_data['materia_anexada']
|
|
anexada.save()
|
|
return anexada
|
|
|
|
class Meta:
|
|
model = Anexada
|
|
fields = ['tipo', 'numero', 'ano', 'data_anexacao', 'data_desanexacao']
|
|
|
|
|
|
class RangeWidgetOverride(forms.MultiWidget):
|
|
|
|
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)
|
|
|
|
def decompress(self, value):
|
|
if value:
|
|
return [value.start, value.stop]
|
|
return [None, None]
|
|
|
|
def format_output(self, rendered_widgets):
|
|
return ''.join(rendered_widgets)
|
|
|
|
|
|
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}
|
|
}}
|
|
|
|
ano = django_filters.ChoiceFilter(required=False,
|
|
label=u'Ano da Matéria',
|
|
choices=ANO_CHOICES)
|
|
|
|
autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput())
|
|
|
|
ementa = django_filters.CharFilter(lookup_expr='icontains')
|
|
|
|
class Meta:
|
|
model = MateriaLegislativa
|
|
fields = ['numero',
|
|
'numero_protocolo',
|
|
'ano',
|
|
'tipo',
|
|
'data_apresentacao',
|
|
'data_publicacao',
|
|
'autoria__autor__tipo',
|
|
'autoria__partido',
|
|
'relatoria__parlamentar_id',
|
|
'local_origem_externa',
|
|
'tramitacao__unidade_tramitacao_destino',
|
|
'tramitacao__status',
|
|
'em_tramitacao',
|
|
]
|
|
|
|
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):
|
|
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(
|
|
[('tipo', 12)])
|
|
row2 = crispy_layout_mixin.to_row(
|
|
[('numero', 4),
|
|
('ano', 4),
|
|
('numero_protocolo', 4)])
|
|
row3 = crispy_layout_mixin.to_row(
|
|
[('data_apresentacao', 6),
|
|
('data_publicacao', 6)])
|
|
row4 = crispy_layout_mixin.to_row(
|
|
[('autoria__autor', 0),
|
|
(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(
|
|
[('autoria__autor__tipo', 6),
|
|
('autoria__partido', 6)])
|
|
row6 = crispy_layout_mixin.to_row(
|
|
[('relatoria__parlamentar_id', 6),
|
|
('local_origem_externa', 6)])
|
|
row7 = crispy_layout_mixin.to_row(
|
|
[('tramitacao__unidade_tramitacao_destino', 6),
|
|
('tramitacao__status', 6)])
|
|
row8 = crispy_layout_mixin.to_row(
|
|
[('em_tramitacao', 6),
|
|
('o', 6)])
|
|
row9 = crispy_layout_mixin.to_row(
|
|
[('ementa', 12)])
|
|
|
|
self.form.helper = FormHelper()
|
|
self.form.helper.form_method = 'GET'
|
|
self.form.helper.layout = Layout(
|
|
Fieldset(_('Pesquisa de Matéria'),
|
|
row1, row2, row3,
|
|
HTML(sapl.utils.autor_label),
|
|
HTML(sapl.utils.autor_modal),
|
|
row4, row5, row6, row7, row8, row9,
|
|
form_actions(save_label='Pesquisar'))
|
|
)
|
|
|
|
|
|
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)
|
|
|
|
|
|
class DespachoInicialForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = DespachoInicial
|
|
fields = ['comissao']
|
|
|
|
def clean(self):
|
|
if self.errors:
|
|
return self.errors
|
|
|
|
if DespachoInicial.objects.filter(
|
|
materia=self.instance.materia,
|
|
comissao=self.cleaned_data['comissao'],
|
|
).exists():
|
|
msg = _('Esse Despacho já foi cadastrado.')
|
|
raise ValidationError(msg)
|
|
|
|
return self.cleaned_data
|
|
|
|
|
|
class AutoriaForm(ModelForm):
|
|
|
|
class Meta:
|
|
model = Autoria
|
|
fields = ['autor', 'partido', 'primeiro_autor']
|
|
|
|
def clean(self):
|
|
if self.errors:
|
|
return self.errors
|
|
|
|
if Autoria.objects.filter(
|
|
materia=self.instance.materia,
|
|
autor=self.cleaned_data['autor'],
|
|
).exists():
|
|
msg = _('Esse Autor já foi cadastrado.')
|
|
raise ValidationError(msg)
|
|
|
|
return self.cleaned_data
|
|
|