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.
533 lines
19 KiB
533 lines
19 KiB
import logging
|
|
import re
|
|
|
|
from crispy_forms.layout import (Button, Fieldset, HTML, Layout)
|
|
from django import forms
|
|
from django.contrib.postgres.search import SearchVector
|
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
from django.db.models import Q, F, Func, Value
|
|
from django.forms import ModelChoiceField, ModelForm, widgets
|
|
from django.utils import timezone
|
|
from django.utils.translation import ugettext_lazy as _
|
|
import django_filters
|
|
|
|
from sapl.base.models import TipoAutor
|
|
from sapl.crispy_layout_mixin import form_actions, SaplFormHelper, to_row
|
|
from sapl.materia.models import (MateriaLegislativa,
|
|
TipoMateriaLegislativa, Orgao)
|
|
from sapl.parlamentares.models import Partido
|
|
from sapl.utils import (autor_label, autor_modal, ANO_CHOICES, choice_anos_com_normas,
|
|
FileFieldCheckMixin, FilterOverridesMetaMixin,
|
|
NormaPesquisaOrderingFilter, validar_arquivo)
|
|
|
|
from .models import (AnexoNormaJuridica, AssuntoNorma, AutoriaNorma,
|
|
NormaJuridica, NormaRelacionada, TipoNormaJuridica)
|
|
|
|
|
|
def get_esferas():
|
|
return [('E', 'Estadual'),
|
|
('F', 'Federal'),
|
|
('M', 'Municipal')]
|
|
|
|
|
|
YES_NO_CHOICES = [('', '---------'),
|
|
(True, _('Sim')),
|
|
(False, _('Não'))]
|
|
|
|
ORDENACAO_CHOICES = [('', '---------'),
|
|
('tipo,ano,numero', _('Tipo/Ano/Número')),
|
|
('data,tipo,ano,numero', _('Data/Tipo/Ano/Número'))]
|
|
|
|
|
|
class AssuntoNormaFilterSet(django_filters.FilterSet):
|
|
assunto = django_filters.CharFilter(label=_("Assunto"),
|
|
method='multifield_filter')
|
|
|
|
class Meta:
|
|
model = AssuntoNorma
|
|
fields = ["assunto"]
|
|
|
|
def multifield_filter(self, queryset, name, value):
|
|
return queryset.filter(Q(assunto__icontains=value) | Q(descricao__icontains=value))
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
row0 = to_row([("assunto", 12)])
|
|
|
|
self.form.helper = SaplFormHelper()
|
|
self.form.helper.form_method = "GET"
|
|
self.form.helper.layout = Layout(
|
|
Fieldset(
|
|
_("Pesquisa de Assunto de Norma Jurídica"),
|
|
row0, form_actions(label="Pesquisar"))
|
|
)
|
|
|
|
|
|
class NormaFilterSet(django_filters.FilterSet):
|
|
|
|
ano = django_filters.ChoiceFilter(required=False,
|
|
label='Ano',
|
|
choices=choice_anos_com_normas)
|
|
|
|
numero = django_filters.CharFilter(
|
|
method='filter_numero',
|
|
label=_('Número'))
|
|
|
|
ementa = django_filters.CharFilter(
|
|
method='filter_ementa',
|
|
label=_('Pesquisar expressões na ementa da norma'))
|
|
|
|
indexacao = django_filters.CharFilter(method='filter_indexacao',
|
|
label=_('Indexação'))
|
|
|
|
assuntos = django_filters.ModelChoiceFilter(
|
|
queryset=AssuntoNorma.objects.all())
|
|
|
|
autorianorma__autor = django_filters.CharFilter(widget=forms.HiddenInput())
|
|
autorianorma__primeiro_autor = django_filters.BooleanFilter(
|
|
required=False,
|
|
label=_('Primeiro Autor'))
|
|
autorianorma__autor__parlamentar_set__filiacao__partido = django_filters.ModelChoiceFilter(
|
|
queryset=Partido.objects.all(),
|
|
label=_('Normas por Partido'))
|
|
|
|
o = NormaPesquisaOrderingFilter(help_text='')
|
|
|
|
class Meta(FilterOverridesMetaMixin):
|
|
model = NormaJuridica
|
|
fields = ['orgao', 'tipo', 'numero', 'ano', 'data',
|
|
'data_vigencia', 'data_publicacao', 'ementa', 'assuntos',
|
|
'autorianorma__autor', 'autorianorma__primeiro_autor', 'autorianorma__autor__tipo']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(NormaFilterSet, self).__init__(*args, **kwargs)
|
|
self.filters['autorianorma__autor__tipo'].label = _('Tipo de Autor')
|
|
|
|
row1 = to_row([('tipo', 4), ('numero', 4), ('ano', 4)])
|
|
row2 = to_row([('data', 6), ('data_publicacao', 6)])
|
|
row3 = to_row([('ementa', 6), ('assuntos', 6)])
|
|
row4 = to_row([('data_vigencia', 6), ('orgao', 6), ])
|
|
row5 = to_row([('o', 6), ('indexacao', 6)])
|
|
row6 = to_row([
|
|
('autorianorma__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'), 2),
|
|
('autorianorma__primeiro_autor', 2),
|
|
('autorianorma__autor__tipo', 3),
|
|
('autorianorma__autor__parlamentar_set__filiacao__partido', 3)
|
|
])
|
|
|
|
self.form.helper = SaplFormHelper()
|
|
self.form.helper.form_method = 'GET'
|
|
self.form.helper.layout = Layout(
|
|
Fieldset(_('Pesquisa de Norma'),
|
|
row1, row2, row3, row4, row5,
|
|
Fieldset(_('Pesquisa Avançada'),
|
|
row6,
|
|
HTML(autor_label),
|
|
HTML(autor_modal)),
|
|
form_actions(label='Pesquisar'))
|
|
)
|
|
|
|
def filter_numero(self, queryset, name, value):
|
|
p = r'(\W|_)'
|
|
value = re.sub(p, '', value, flags=re.IGNORECASE)
|
|
return queryset.annotate(
|
|
numero_clean=Func(
|
|
F('numero'),
|
|
Value(p),
|
|
Value(''),
|
|
Value('g'),
|
|
function='REGEXP_REPLACE'
|
|
)
|
|
).filter(numero_clean=value)
|
|
|
|
def filter_ementa(self, queryset, name, value):
|
|
return queryset.annotate(search=SearchVector('ementa',
|
|
config='portuguese')).filter(search=value)
|
|
|
|
def filter_indexacao(self, queryset, name, value):
|
|
return queryset.annotate(search=SearchVector('indexacao',
|
|
config='portuguese')).filter(search=value)
|
|
|
|
def filter_autoria(self, queryset, name, value):
|
|
return queryset.filter(**{
|
|
name: value,
|
|
})
|
|
|
|
|
|
class NormaJuridicaForm(FileFieldCheckMixin, ModelForm):
|
|
|
|
# Campos de MateriaLegislativa
|
|
tipo_materia = forms.ModelChoiceField(
|
|
label='Matéria',
|
|
required=False,
|
|
queryset=TipoMateriaLegislativa.objects.all(),
|
|
empty_label='Selecione',
|
|
widget=forms.Select(attrs={'autocomplete': 'off'})
|
|
)
|
|
numero_materia = forms.CharField(
|
|
label='Número Matéria',
|
|
required=False,
|
|
widget=forms.TextInput(attrs={'autocomplete': 'off'})
|
|
)
|
|
ano_materia = forms.ChoiceField(
|
|
label='Ano Matéria',
|
|
required=False,
|
|
choices=ANO_CHOICES,
|
|
widget=forms.Select(attrs={'autocomplete': 'off'})
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class Meta:
|
|
model = NormaJuridica
|
|
fields = ['tipo',
|
|
'numero',
|
|
'ano',
|
|
'orgao',
|
|
'data',
|
|
'esfera_federacao',
|
|
'complemento',
|
|
'tipo_materia',
|
|
'numero_materia',
|
|
'ano_materia',
|
|
'data_publicacao',
|
|
'data_vigencia',
|
|
'veiculo_publicacao',
|
|
'pagina_inicio_publicacao',
|
|
'pagina_fim_publicacao',
|
|
'ementa',
|
|
'indexacao',
|
|
'observacao',
|
|
'texto_integral',
|
|
'assuntos',
|
|
'user',
|
|
'ip',
|
|
'ultima_edicao']
|
|
|
|
widgets = {'assuntos': widgets.CheckboxSelectMultiple,
|
|
'user': forms.HiddenInput(),
|
|
'ip': forms.HiddenInput(),
|
|
'ultima_edicao': forms.HiddenInput()}
|
|
|
|
def clean(self):
|
|
|
|
cleaned_data = super(NormaJuridicaForm, self).clean()
|
|
|
|
if not self.is_valid():
|
|
return cleaned_data
|
|
|
|
import re
|
|
has_digits = re.sub('[^0-9]', '', cleaned_data['numero'])
|
|
if not has_digits:
|
|
self.logger.error("Número de norma ({}) não pode conter somente letras.".format(
|
|
cleaned_data['numero']))
|
|
raise ValidationError(
|
|
'Número de norma não pode conter somente letras')
|
|
|
|
if self.instance.numero != cleaned_data['numero']:
|
|
params = {
|
|
'ano': cleaned_data['ano'],
|
|
'numero': cleaned_data['numero'],
|
|
'tipo': cleaned_data['tipo'],
|
|
}
|
|
params['orgao'] = cleaned_data['orgao']
|
|
norma = NormaJuridica.objects.filter(**params).exists()
|
|
if norma:
|
|
self.logger.warning("Já existe uma norma de mesmo Tipo ({}), Ano ({}) "
|
|
"e Número ({}) no sistema."
|
|
.format(cleaned_data['tipo'], cleaned_data['ano'], cleaned_data['numero']))
|
|
raise ValidationError("Já existe uma norma de mesmo Tipo, Ano, Órgão "
|
|
"e Número no sistema")
|
|
if (cleaned_data['tipo_materia'] and
|
|
cleaned_data['numero_materia'] and
|
|
cleaned_data['ano_materia']):
|
|
try:
|
|
self.logger.debug("Tentando obter objeto MateriaLegislativa com tipo={}, numero={}, ano={}."
|
|
.format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia']))
|
|
materia = MateriaLegislativa.objects.get(
|
|
tipo_id=cleaned_data['tipo_materia'],
|
|
numero=cleaned_data['numero_materia'],
|
|
ano=cleaned_data['ano_materia'])
|
|
|
|
except ObjectDoesNotExist:
|
|
self.logger.error("Matéria Legislativa %s/%s (%s) é inexistente." % (
|
|
self.cleaned_data['numero_materia'],
|
|
self.cleaned_data['ano_materia'],
|
|
cleaned_data['tipo_materia'].descricao))
|
|
raise forms.ValidationError(
|
|
_("Matéria Legislativa %s/%s (%s) é inexistente." % (
|
|
self.cleaned_data['numero_materia'],
|
|
self.cleaned_data['ano_materia'],
|
|
cleaned_data['tipo_materia'].descricao)))
|
|
else:
|
|
self.logger.info("MateriaLegislativa com tipo={}, numero={}, ano={} obtida com sucesso."
|
|
.format(cleaned_data['tipo_materia'], cleaned_data['numero_materia'], cleaned_data['ano_materia']))
|
|
cleaned_data['materia'] = materia
|
|
|
|
else:
|
|
cleaned_data['materia'] = None
|
|
|
|
return cleaned_data
|
|
|
|
def clean_texto_integral(self):
|
|
super(NormaJuridicaForm, self).clean()
|
|
|
|
texto_integral = self.cleaned_data.get('texto_integral', False)
|
|
|
|
if texto_integral:
|
|
validar_arquivo(texto_integral, "Texto Original")
|
|
|
|
return texto_integral
|
|
|
|
def save(self, commit=False):
|
|
norma = self.instance
|
|
norma.timestamp = timezone.now()
|
|
norma.materia = self.cleaned_data['materia']
|
|
norma = super(NormaJuridicaForm, self).save(commit=True)
|
|
|
|
return norma
|
|
|
|
|
|
class AutoriaNormaForm(ModelForm):
|
|
|
|
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
|
|
required=False,
|
|
queryset=TipoAutor.objects.all(),
|
|
empty_label=_('Selecione'),)
|
|
|
|
data_relativa = forms.DateField(
|
|
widget=forms.HiddenInput(), required=False)
|
|
|
|
legislatura_anterior = forms.BooleanField(label=_('Legislatura Anterior'),
|
|
required=False)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(AutoriaNormaForm, self).__init__(*args, **kwargs)
|
|
|
|
row1 = to_row([('tipo_autor', 4),
|
|
('autor', 4),
|
|
('primeiro_autor', 4)])
|
|
|
|
self.helper = SaplFormHelper()
|
|
self.helper.layout = Layout(
|
|
Fieldset(_('Autoria'),
|
|
row1, 'data_relativa',
|
|
form_actions(label='Salvar'),
|
|
to_row([('legislatura_anterior', 12)])))
|
|
|
|
if not self.instance:
|
|
self.fields['autor'].choices = []
|
|
|
|
class Meta:
|
|
model = AutoriaNorma
|
|
fields = ['tipo_autor', 'autor',
|
|
'primeiro_autor', 'data_relativa',
|
|
'legislatura_anterior']
|
|
|
|
def clean(self):
|
|
cd = super(AutoriaNormaForm, self).clean()
|
|
|
|
if not self.is_valid():
|
|
return self.cleaned_data
|
|
|
|
autorias = AutoriaNorma.objects.filter(
|
|
norma=self.instance.norma, autor=cd['autor'])
|
|
pk = self.instance.pk
|
|
|
|
if ((not pk and autorias.exists()) or
|
|
(pk and autorias.exclude(pk=pk).exists())):
|
|
self.logger.error(
|
|
"Autor ({}) já foi cadastrado.".format(cd['autor']))
|
|
raise ValidationError(_('Esse Autor já foi cadastrado.'))
|
|
|
|
return cd
|
|
|
|
|
|
class AnexoNormaJuridicaForm(FileFieldCheckMixin, ModelForm):
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
anexo_arquivo = forms.FileField(
|
|
required=True,
|
|
label="Arquivo Anexo"
|
|
)
|
|
|
|
class Meta:
|
|
model = AnexoNormaJuridica
|
|
fields = ['norma', 'anexo_arquivo', 'assunto_anexo']
|
|
widgets = {
|
|
'norma': forms.HiddenInput(),
|
|
}
|
|
|
|
def clean(self):
|
|
cleaned_data = super(AnexoNormaJuridicaForm, self).clean()
|
|
|
|
if not self.is_valid():
|
|
return cleaned_data
|
|
|
|
anexo_arquivo = self.cleaned_data.get('anexo_arquivo', False)
|
|
|
|
if anexo_arquivo:
|
|
validar_arquivo(anexo_arquivo, "Arquivo Anexo")
|
|
|
|
return cleaned_data
|
|
|
|
def save(self, commit=False):
|
|
anexo = self.instance
|
|
anexo.ano = self.cleaned_data['norma'].ano
|
|
anexo.norma = self.cleaned_data['norma']
|
|
anexo.assunto_anexo = self.cleaned_data['assunto_anexo']
|
|
anexo.anexo_arquivo = self.cleaned_data['anexo_arquivo']
|
|
anexo = super(AnexoNormaJuridicaForm, self).save(commit=True)
|
|
return anexo
|
|
|
|
|
|
class NormaRelacionadaForm(ModelForm):
|
|
|
|
orgao = forms.ModelChoiceField(
|
|
label='Órgão',
|
|
required=False,
|
|
queryset=Orgao.objects.all(),
|
|
empty_label='----------',
|
|
)
|
|
tipo = forms.ModelChoiceField(
|
|
label='Tipo',
|
|
required=True,
|
|
queryset=TipoNormaJuridica.objects.all(),
|
|
empty_label='----------',
|
|
)
|
|
numero = forms.CharField(label='Número', required=True)
|
|
ano = forms.CharField(label='Ano', required=True)
|
|
ementa = forms.CharField(
|
|
required=False,
|
|
widget=forms.Textarea(attrs={'disabled': 'disabled'}))
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class Meta:
|
|
model = NormaRelacionada
|
|
fields = ['orgao', 'tipo', 'numero', 'ano',
|
|
'resumo', 'ementa', 'tipo_vinculo']
|
|
|
|
widgets = {
|
|
'resumo': forms.Textarea(
|
|
attrs={'id': 'texto-rico'})}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(NormaRelacionadaForm, self).__init__(*args, **kwargs)
|
|
|
|
def clean(self):
|
|
super(NormaRelacionadaForm, self).clean()
|
|
|
|
if not self.is_valid():
|
|
return self.cleaned_data
|
|
cleaned_data = self.cleaned_data
|
|
|
|
try:
|
|
self.logger.debug("Tentando obter objeto NormaJuridica com numero={}, ano={}, tipo={}, orgao={}.".format(
|
|
cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'], cleaned_data['orgao']))
|
|
norma_relacionada = NormaJuridica.objects.get(
|
|
numero=cleaned_data['numero'],
|
|
ano=cleaned_data['ano'],
|
|
tipo=cleaned_data['tipo'],
|
|
orgao=cleaned_data['orgao'])
|
|
except ObjectDoesNotExist:
|
|
self.logger.info("NormaJuridica com numero={}, ano={}, tipo={}, orgao={} não existe.".format(
|
|
cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'], cleaned_data['orgao']))
|
|
msg = _('A norma a ser relacionada não existe.')
|
|
raise ValidationError(msg)
|
|
else:
|
|
self.logger.info("NormaJuridica com numero={}, ano={}, tipo={} , orgao={} obtida com sucesso.".format(
|
|
cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'], cleaned_data['orgao']))
|
|
cleaned_data['norma_relacionada'] = norma_relacionada
|
|
|
|
return cleaned_data
|
|
|
|
def save(self, commit=False):
|
|
relacionada = super(NormaRelacionadaForm, self).save(commit)
|
|
relacionada.norma_relacionada = self.cleaned_data['norma_relacionada']
|
|
if relacionada.tipo_vinculo.revoga_integralmente:
|
|
relacionada.norma_relacionada.data_vigencia = relacionada.norma_principal.data
|
|
relacionada.norma_relacionada.save()
|
|
relacionada.save()
|
|
return relacionada
|
|
|
|
|
|
class NormaPesquisaSimplesForm(forms.Form):
|
|
tipo_norma = forms.ModelChoiceField(
|
|
label=TipoNormaJuridica._meta.verbose_name,
|
|
queryset=TipoNormaJuridica.objects.all(),
|
|
required=False,
|
|
empty_label='Selecione')
|
|
|
|
data_inicial = forms.DateField(
|
|
label='Data Inicial',
|
|
required=False,
|
|
widget=forms.DateInput(format='%d/%m/%Y')
|
|
)
|
|
|
|
data_final = forms.DateField(
|
|
label='Data Final',
|
|
required=False,
|
|
widget=forms.DateInput(format='%d/%m/%Y')
|
|
)
|
|
|
|
titulo = forms.CharField(
|
|
label='Título do Relatório',
|
|
required=False,
|
|
max_length=150)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
row1 = to_row(
|
|
[('tipo_norma', 6),
|
|
('data_inicial', 3),
|
|
('data_final', 3)])
|
|
|
|
row2 = to_row(
|
|
[('titulo', 12)])
|
|
|
|
self.helper = SaplFormHelper()
|
|
self.helper.layout = Layout(
|
|
Fieldset(
|
|
'Índice de Normas',
|
|
row1, row2,
|
|
form_actions(label='Pesquisar')
|
|
)
|
|
)
|
|
|
|
def clean(self):
|
|
super().clean()
|
|
|
|
if not self.is_valid():
|
|
return self.cleaned_data
|
|
|
|
cleaned_data = self.cleaned_data
|
|
data_inicial = cleaned_data['data_inicial']
|
|
data_final = cleaned_data['data_final']
|
|
|
|
if data_inicial or data_final:
|
|
if not(data_inicial and data_final):
|
|
self.logger.error("Caso pesquise por data, os campos de Data Inicial e "
|
|
"Data Final devem ser preenchidos obrigatoriamente")
|
|
raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e '
|
|
'Data Final devem ser preenchidos obrigatoriamente'))
|
|
elif data_inicial > data_final:
|
|
self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(
|
|
data_final, data_inicial))
|
|
raise ValidationError(
|
|
_('A Data Final não pode ser menor que a Data Inicial'))
|
|
|
|
return cleaned_data
|
|
|