Sistema de Apoio ao Processo Legislativo
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.
 
 
 
 
 

3001 lines
111 KiB

import logging
import os
from crispy_forms.bootstrap import Alert, InlineRadios
from crispy_forms.layout import (Button, Field, Fieldset, HTML, Layout, Row)
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.files.base import File
from django.db import transaction
from django.db.models import F, Max, Q
from django.forms import ModelChoiceField, ModelForm, widgets
from django.forms.forms import Form
from django.forms.models import ModelMultipleChoiceField
from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import AppConfig, Autor, TipoAutor
from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PRIVATE)
from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper,
SaplFormLayout, to_column, to_row)
from sapl.materia.models import (AssuntoMateria, MateriaAssunto,
MateriaLegislativa, Orgao,
RegimeTramitacao, StatusTramitacao,
TipoDocumento, TipoProposicao,
ConfigEtiquetaMateriaLegislativa, HistoricoProposicao)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
from sapl.parlamentares.models import Legislatura, Partido
from sapl.protocoloadm.models import (DocumentoAdministrativo,
Protocolo)
from sapl.utils import (autor_label, autor_modal, timing,
ChoiceWithoutValidationField,
choice_anos_com_materias, FileFieldCheckMixin,
FilterOverridesMetaMixin, gerar_hash_arquivo,
lista_anexados, MateriaPesquisaOrderingFilter,
models_with_gr_for_model, qs_override_django_filter,
SEPARADOR_HASH_PROPOSICAO,
validar_arquivo, YES_NO_CHOICES,
GoogleRecapthaMixin)
import sapl
from .models import (AcompanhamentoMateria, Anexada, Autoria,
DespachoInicial, DocumentoAcessorio, Numeracao,
Proposicao, Relatoria, TipoMateriaLegislativa,
Tramitacao, UnidadeTramitacao)
def CHOICE_TRAMITACAO():
return [('', 'Tanto Faz'),
(1, 'Sim'),
(0, 'Não')]
def CHOICE_TIPO_LISTAGEM():
return [
(1, _('Detalhada')),
(2, _('Simplificada')),
]
class AdicionarVariasAutoriasFilterSet(django_filters.FilterSet):
class Meta:
model = Autor
fields = ['nome']
def __init__(self, *args, **kwargs):
super(AdicionarVariasAutoriasFilterSet, self).__init__(*args, **kwargs)
row1 = to_row([('nome', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Filtrar Autores'),
row1, form_actions(label='Filtrar'))
)
class OrgaoForm(ModelForm):
class Meta:
model = Orgao
fields = ['nome', 'sigla', 'unidade_deliberativa',
'endereco', 'telefone']
@transaction.atomic
def save(self, commit=True):
orgao = super(OrgaoForm, self).save(commit)
content_type = ContentType.objects.get_for_model(Orgao)
object_id = orgao.pk
tipo = TipoAutor.objects.get(content_type=content_type)
nome = orgao.nome + ' - ' + orgao.sigla
Autor.objects.create(
content_type=content_type,
object_id=object_id,
tipo=tipo,
nome=nome
)
return orgao
class ReceberProposicaoForm(Form):
cod_hash = forms.CharField(label='Código do Documento', required=True)
def __init__(self, *args, **kwargs):
row1 = to_row([('cod_hash', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
_('Incorporar Proposição'), row1,
form_actions(label='Recuperar Proposição')
)
)
super(ReceberProposicaoForm, self).__init__(*args, **kwargs)
class MateriaSimplificadaForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = MateriaLegislativa
fields = ['tipo', 'numero', 'ano', 'data_apresentacao',
'numero_protocolo', 'regime_tramitacao',
'em_tramitacao', 'ementa', 'tipo_apresentacao',
'texto_original']
widgets = {
'numero_protocolo': forms.TextInput(attrs={'readonly': True}),
}
def __init__(self, *args, **kwargs):
row1 = to_row([('tipo', 6), ('numero', 3), ('ano', 3)])
row2 = to_row([('data_apresentacao', 6), ('numero_protocolo', 6)])
row3 = to_row([('regime_tramitacao', 6),
('em_tramitacao', 3), ('tipo_apresentacao', 3)])
row4 = to_row([('ementa', 12)])
row5 = to_row([('texto_original', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
_('Formulário Simplificado'),
row1, row2, row3, row4, row5,
form_actions(label='Salvar')
)
)
super(MateriaSimplificadaForm, self).__init__(*args, **kwargs)
class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__)
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=False,
queryset=TipoAutor.objects.all(),
empty_label=_('------'), )
autor = forms.ModelChoiceField(required=False,
empty_label='------',
queryset=Autor.objects.all()
)
class Meta:
model = MateriaLegislativa
exclude = ['texto_articulado', 'autores', 'proposicao',
'anexadas', 'data_ultima_atualizacao']
widgets = {
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()
}
def __init__(self, *args, **kwargs):
super(MateriaLegislativaForm, self).__init__(*args, **kwargs)
self.fields['ementa'].widget.attrs['maxlength'] = 1000
if self.instance and self.instance.pk:
self.fields['tipo_autor'] = forms.CharField(required=False,
widget=forms.HiddenInput())
self.fields['autor'] = forms.CharField(required=False,
widget=forms.HiddenInput())
if kwargs['instance'].numero_protocolo and Protocolo.objects.filter(numero=kwargs['instance'].numero_protocolo, ano=kwargs['instance'].ano).exists():
self.fields['numero_protocolo'].widget.attrs['readonly'] = True
def clean(self):
super(MateriaLegislativaForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
data_apresentacao = cleaned_data['data_apresentacao']
ano = cleaned_data['ano']
protocolo = cleaned_data['numero_protocolo']
protocolo_antigo = self.instance.numero_protocolo
if protocolo:
if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists():
self.logger.warning(
"Protocolo %s/%s não existe" % (protocolo, ano))
raise ValidationError(
_('Protocolo %s/%s não existe' % (protocolo, ano)))
if protocolo_antigo != protocolo:
exist_materia = MateriaLegislativa.objects.filter(
numero_protocolo=protocolo,
ano=ano).exists()
exist_doc = DocumentoAdministrativo.objects.filter(
protocolo_id=protocolo,
ano=ano).exists()
if exist_materia or exist_doc:
self.logger.error("Protocolo %s/%s ja possui"
" documento vinculado"
% (protocolo, ano))
raise ValidationError(_('Protocolo %s/%s ja possui'
' documento vinculado'
% (protocolo, ano)))
p = Protocolo.objects.get(numero=protocolo, ano=ano)
if p.tipo_materia != cleaned_data['tipo']:
self.logger.error("Tipo do Protocolo ({}) deve ser o mesmo do Tipo Matéria ({})."
.format(cleaned_data['tipo'], p.tipo_materia))
raise ValidationError(
_('Tipo do Protocolo deve ser o mesmo do Tipo Matéria'))
ano_origem_externa = cleaned_data['ano_origem_externa']
data_origem_externa = cleaned_data['data_origem_externa']
if ano_origem_externa and data_origem_externa and \
ano_origem_externa != data_origem_externa.year:
self.logger.error("O ano de origem externa da matéria ({}) é "
" diferente do ano na data de origem externa ({})."
.format(ano_origem_externa, data_origem_externa))
raise ValidationError(_("O ano de origem externa da matéria não "
"pode ser diferente do ano na data de "
"origem externa"))
texto_original = self.cleaned_data.get('texto_original', False)
if texto_original:
validar_arquivo(texto_original, "Texto Original")
return cleaned_data
def save(self, commit=False):
if not self.instance.pk:
primeiro_autor = True
else:
primeiro_autor = False
materia = super(MateriaLegislativaForm, self).save(commit)
materia.save()
if self.cleaned_data['autor']:
autoria = Autoria()
autoria.primeiro_autor = primeiro_autor
autoria.materia = materia
autoria.autor = self.cleaned_data['autor']
autoria.save()
return materia
class UnidadeTramitacaoForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = UnidadeTramitacao
fields = ['comissao', 'orgao', 'parlamentar']
def clean(self):
super(UnidadeTramitacaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
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 ser preenchido!')
self.logger.error("Somente um campo deve ser preenchido!")
raise ValidationError(msg)
return cleaned_data
def save(self, commit=False):
unidade = super(UnidadeTramitacaoForm, self).save(commit)
cd = self.cleaned_data
if not cd.get('orgao'):
unidade.orgao = None
if not cd.get('parlamentar'):
unidade.parlamentar = None
if not cd.get('comissao'):
unidade.comissao = None
unidade.save()
return unidade
class AcompanhamentoMateriaForm(GoogleRecapthaMixin, ModelForm):
class Meta:
model = AcompanhamentoMateria
fields = ['email']
def __init__(self, *args, **kwargs):
kwargs['title_label'] = _('Acompanhamento de Matéria por e-mail')
kwargs['action_label'] = _('Cadastrar')
super().__init__(*args, **kwargs)
class DocumentoAcessorioForm(FileFieldCheckMixin, ModelForm):
data = forms.DateField(required=True)
class Meta:
model = DocumentoAcessorio
fields = ['tipo', 'nome', 'data', 'autor',
'ementa', 'indexacao', 'arquivo']
def clean(self):
super(DocumentoAcessorioForm, self).clean()
if not self.is_valid():
return self.cleaned_data
arquivo = self.cleaned_data.get('arquivo')
if arquivo:
validar_arquivo(arquivo, "Texto Integral")
else:
# TODO: definir arquivo no form e preservar o nome do campo
# que gerou a mensagem de erro.
## arquivo = forms.FileField(required=True, label="Texto Integral")
nome_arquivo = self.fields['arquivo'].label
raise ValidationError(f'Favor anexar arquivo em {nome_arquivo}')
return self.cleaned_data
class RelatoriaForm(ModelForm):
logger = logging.getLogger(__name__)
composicao = forms.ModelChoiceField(
required=True,
empty_label='---------',
queryset=Composicao.objects.all(),
label=_('Composição')
)
tipo_unidade_tramitacao_destino = forms.CharField(required=False)
unidade_tramitacao_destino = forms.CharField(required=False)
class Meta:
model = Relatoria
fields = [
'comissao',
'data_designacao_relator',
'data_destituicao_relator',
'tipo_fim_relatoria',
'composicao',
'parlamentar'
]
widgets = {
'comissao': forms.Select(attrs={'disabled': 'disabled'}),
'tipo_unidade_tramitacao_destino': forms.HiddenInput(),
'unidade_tramitacao_destino': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
row1 = to_row([('comissao', 12)])
row2 = to_row([('data_designacao_relator', 4),
('data_destituicao_relator', 4),
('tipo_fim_relatoria', 4)])
row3 = to_row([('composicao', 4),
('parlamentar', 8)])
self.helper = SaplFormHelper()
self.helper.layout = SaplFormLayout(
Fieldset(_('Relatoria'), row1, row2, row3))
super().__init__(*args, **kwargs)
comissao_pk = kwargs['initial']['comissao']
composicoes = Composicao.objects.filter(comissao_id=comissao_pk)
self.fields['composicao'].choices = [('', '---------')] + \
[(c.pk, c) for c in composicoes]
# UPDATE
if self.initial.get('composicao') and self.initial.get('parlamentar'):
parlamentares = [(p.parlamentar.id, p.parlamentar) for p in
Participacao.objects.filter(composicao__comissao_id=comissao_pk,
composicao_id=self.initial['composicao'])]
self.fields['parlamentar'].choices = [
('', '---------')] + parlamentares
# INSERT
else:
self.fields['parlamentar'].choices = [('', '---------')]
def clean(self):
super().clean()
cleaned_data = self.cleaned_data
if not self.is_valid():
return cleaned_data
try:
self.logger.debug("Tentando obter objeto Comissao.")
comissao = Comissao.objects.get(id=self.initial['comissao'])
except ObjectDoesNotExist as e:
self.logger.error(
"Objeto Comissao não encontrado com id={}. A localização atual deve ser uma comissão. ".format(
self.initial['comissao']) + str(e))
msg = _('A localização atual deve ser uma comissão.')
raise ValidationError(msg)
else:
cleaned_data['comissao'] = comissao
if cleaned_data['data_designacao_relator'] < cleaned_data['composicao'].periodo.data_inicio \
or cleaned_data['data_designacao_relator'] > cleaned_data['composicao'].periodo.data_fim:
raise ValidationError(
_('Data de designação deve estar dentro do período da composição.'))
return cleaned_data
class TramitacaoForm(ModelForm):
urgente = forms.ChoiceField(required=True,
choices=YES_NO_CHOICES,
initial=False,
label=_("Urgente?"))
logger = logging.getLogger(__name__)
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'turno',
'urgente',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto',
'user',
'ip',
'ultima_edicao']
widgets = {'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super(TramitacaoForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date()
ust = UnidadeTramitacao.objects.select_related().all()
unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut)
for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.orgao])
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.parlamentar])
self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
def clean(self):
super(TramitacaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
if 'data_encaminhamento' in cleaned_data:
data_enc_form = cleaned_data['data_encaminhamento']
if 'data_fim_prazo' in cleaned_data:
data_prazo_form = cleaned_data['data_fim_prazo']
if 'data_tramitacao' in cleaned_data:
data_tram_form = cleaned_data['data_tramitacao']
ultima_tramitacao = Tramitacao.objects.filter(
materia_id=self.instance.materia_id).exclude(
id=self.instance.id).order_by(
'-data_tramitacao',
'-id').first()
if not self.instance.data_tramitacao:
if ultima_tramitacao:
destino = ultima_tramitacao.unidade_tramitacao_destino
if (destino != self.cleaned_data['unidade_tramitacao_local']):
self.logger.error("A origem da nova tramitação ({}) não é igual ao "
"destino da última adicionada ({})!"
.format(self.cleaned_data['unidade_tramitacao_local'], destino))
msg = _('A origem da nova tramitação deve ser igual ao '
'destino da última adicionada!')
raise ValidationError(msg)
if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.warning('A data de tramitação informada ({}) não é menor ou igual a data de hoje!'
.format(cleaned_data['data_tramitacao']))
msg = _(
'A data de tramitação deve ser menor ou igual a data de hoje!')
raise ValidationError(msg)
if (ultima_tramitacao and
data_tram_form < ultima_tramitacao.data_tramitacao):
msg = _('A data da nova tramitação deve ser ' +
'maior que a data da última tramitação!')
self.logger.error("A data da nova tramitação ({}) deve ser "
"maior que a data da última tramitação ({})!"
.format(data_tram_form, ultima_tramitacao.data_tramitacao))
raise ValidationError(msg)
if data_enc_form:
if data_enc_form < data_tram_form:
msg = _(
'A data de encaminhamento deve ser maior que a data de tramitação!')
self.logger.warning("A data de encaminhamento ({}) deve ser maior que a data de tramitação! ({})"
.format(data_enc_form, data_tram_form))
raise ValidationError(msg)
if data_prazo_form:
if data_prazo_form < data_tram_form:
msg = _('A data fim de prazo deve ser ' +
'maior que a data de tramitação!')
self.logger.error("A data fim de prazo ({}) deve ser " +
"maior que a data de tramitação ({})!"
.format(data_prazo_form, data_tram_form))
raise ValidationError(msg)
return cleaned_data
@timing
@transaction.atomic
def save(self, commit=True):
tramitacao = super(TramitacaoForm, self).save(commit)
materia = tramitacao.materia
materia.em_tramitacao = False if tramitacao.status.indicador == "F" else True
materia.save()
tramitar_anexadas = sapl.base.models.AppConfig.attr(
'tramitacao_materia')
if tramitar_anexadas:
lista_tramitacao = []
materias_anexadas = lista_anexados(materia)
for mat in materias_anexadas:
ultima_tramitacao = mat.tramitacao_set.\
select_related('unidade_tramitacao_destino').\
order_by('-data_tramitacao', '-id').first()
if not ultima_tramitacao or \
ultima_tramitacao.unidade_tramitacao_destino \
== tramitacao.unidade_tramitacao_local:
mat.em_tramitacao = False if \
tramitacao.status.indicador == "F" else True
lista_tramitacao.append(Tramitacao(
status=tramitacao.status,
materia=mat,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
turno=tramitacao.turno,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip,
ultima_edicao=tramitacao.ultima_edicao
))
# TODO: BULK UPDATE não envia Signal para Tramitacao
Tramitacao.objects.bulk_create(lista_tramitacao)
# Atualiza status 'em_tramitacao'
MateriaLegislativa.objects.bulk_update(
materias_anexadas, ['em_tramitacao'])
return tramitacao
# Compara se os campos de duas tramitações são iguais,
# exceto os campos id, documento_id e timestamp
def compara_tramitacoes_mat(tramitacao1, tramitacao2):
if not tramitacao1 or not tramitacao2:
return False
lst_items = ['id', 'materia_id', 'timestamp']
values = [(k, v) for k, v in tramitacao1.__dict__.items()
if ((k not in lst_items) and (k[0] != '_'))]
other_values = [(k, v) for k, v in tramitacao2.__dict__.items()
if (k not in lst_items and k[0] != '_')]
return values == other_values
class TramitacaoUpdateForm(TramitacaoForm):
unidade_tramitacao_local = forms.ModelChoiceField(
queryset=UnidadeTramitacao.objects.all(),
widget=forms.HiddenInput())
data_tramitacao = forms.DateField(widget=forms.HiddenInput())
logger = logging.getLogger(__name__)
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'turno',
'urgente',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto',
'user',
'ip',
'ultima_edicao'
]
widgets = {
'data_encaminhamento': forms.DateInput(format='%d/%m/%Y'),
'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'),
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()
}
def clean(self):
super(TramitacaoUpdateForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cd = self.cleaned_data
obj = self.instance
ultima_tramitacao = Tramitacao.objects.filter(
materia_id=obj.materia_id).order_by(
'-data_tramitacao',
'-id').first()
# Se a Tramitação que está sendo editada não for a mais recente,
# ela não pode ter seu destino alterado.
if ultima_tramitacao != obj:
if cd['unidade_tramitacao_destino'] != \
obj.unidade_tramitacao_destino:
self.logger.error("Você não pode mudar a Unidade de Destino desta "
"tramitação para {}, pois irá conflitar com a Unidade "
"Local da tramitação seguinte ({})."
.format(cd['unidade_tramitacao_destino'],
obj.unidade_tramitacao_destino))
raise ValidationError(
'Você não pode mudar a Unidade de Destino desta '
'tramitação, pois irá conflitar com a Unidade '
'Local da tramitação seguinte')
if not (cd['data_tramitacao'] != obj.data_tramitacao or
cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or
cd['status'] != obj.status or cd['texto'] != obj.texto or
cd['data_encaminhamento'] != obj.data_encaminhamento or
cd['data_fim_prazo'] != obj.data_fim_prazo or cd['urgente'] != str(obj.urgente) or
cd['turno'] != obj.turno):
# Se não ocorreram alterações, o usuário, ip, data e hora da última
# edição (real) são mantidos
cd['user'] = obj.user
cd['ip'] = obj.ip
cd['ultima_edicao'] = obj.ultima_edicao
cd['data_tramitacao'] = obj.data_tramitacao
cd['unidade_tramitacao_local'] = obj.unidade_tramitacao_local
return cd
@timing
@transaction.atomic
def save(self, commit=True):
ant_tram_principal = Tramitacao.objects.get(id=self.instance.id)
nova_tram_principal = super(TramitacaoUpdateForm, self).save(commit)
materia = nova_tram_principal.materia
materia.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True
materia.save()
tramitar_anexadas = sapl.base.models.AppConfig.attr(
'tramitacao_materia')
if tramitar_anexadas:
anexadas_list = lista_anexados(materia)
for ma in anexadas_list:
tram_anexada = ma.tramitacao_set.order_by(
'-data_tramitacao', '-id').first()
if compara_tramitacoes_mat(ant_tram_principal, tram_anexada):
tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local
tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento
tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino
tram_anexada.urgente = nova_tram_principal.urgente
tram_anexada.turno = nova_tram_principal.turno
tram_anexada.texto = nova_tram_principal.texto
tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo
tram_anexada.user = nova_tram_principal.user
tram_anexada.ip = nova_tram_principal.ip
tram_anexada.ultima_edicao = nova_tram_principal.ultima_edicao
tram_anexada.save()
ma.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True
ma.save()
# TODO: refatorar?
return nova_tram_principal
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)
logger = logging.getLogger(__name__)
class Meta:
model = LegislacaoCitada
fields = ['tipo',
'numero',
'ano',
'disposicoes',
'parte',
'livro',
'titulo',
'capitulo',
'secao',
'subsecao',
'artigo',
'paragrafo',
'inciso',
'alinea',
'item']
def clean(self):
super(LegislacaoCitadaForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
try:
self.logger.debug("Tentando obter objeto NormalJuridica (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
norma = NormaJuridica.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
self.logger.error("A norma a ser inclusa (numero={}, ano={}, tipo={}) "
"não existe no cadastro de Normas."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
msg = _('A norma a ser inclusa não existe no cadastro'
' de Normas.')
raise ValidationError(msg)
else:
cleaned_data['norma'] = norma
filtro_base = LegislacaoCitada.objects.filter(
materia=self.instance.materia,
norma=self.cleaned_data['norma'],
disposicoes=self.cleaned_data['disposicoes'],
parte=self.cleaned_data['parte'],
livro=self.cleaned_data['livro'],
titulo=self.cleaned_data['titulo'],
capitulo=self.cleaned_data['capitulo'],
secao=self.cleaned_data['secao'],
subsecao=self.cleaned_data['subsecao'],
artigo=self.cleaned_data['artigo'],
paragrafo=self.cleaned_data['paragrafo'],
inciso=self.cleaned_data['inciso'],
alinea=self.cleaned_data['alinea'],
item=self.cleaned_data['item'])
if not self.instance.id:
if filtro_base.exists():
msg = _('Essa Legislação já foi cadastrada.')
self.logger.error("Essa Legislação já foi cadastrada.")
raise ValidationError(msg)
else:
if filtro_base.exclude(id=self.instance.id).exists():
msg = _('Essa Legislação já foi cadastrada.')
self.logger.error("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):
logger = logging.getLogger(__name__)
class Meta:
model = Numeracao
fields = ['tipo_materia',
'numero_materia',
'ano_materia',
'data_materia']
def clean(self):
super(NumeracaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}. tipo={})."
.format(self.cleaned_data['numero_materia'],
self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia']))
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.')
self.logger.error("A MateriaLegislativa a ser inclusa (numero={}, ano={}. tipo={}) não existe no cadastro de matérias legislativas."
.format(self.cleaned_data['numero_materia'],
self.cleaned_data['ano_materia'], self.cleaned_data['tipo_materia']))
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.')
self.logger.error("Essa numeração (materia={}, tipo_materia={}, ano_materia={}, numero_materia={}) "
"já foi cadastrada.".format(self.instance.materia, self.cleaned_data['tipo_materia'],
self.cleaned_data['ano_materia'], self.cleaned_data['numero_materia']))
raise ValidationError(msg)
return self.cleaned_data
class AnexadaForm(ModelForm):
logger = logging.getLogger(__name__)
tipo = forms.ModelChoiceField(
label='Tipo',
required=True,
queryset=TipoMateriaLegislativa.objects.all(),
empty_label='Selecione',
)
numero = forms.IntegerField(label='Número', required=True)
ano = forms.CharField(label='Ano', required=True)
def __init__(self, *args, **kwargs):
return super(AnexadaForm, self).__init__(*args, **kwargs)
def clean(self):
super(AnexadaForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
data_anexacao = cleaned_data['data_anexacao']
data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao
if data_anexacao > data_desanexacao:
self.logger.error(
"Data de anexação posterior à data de desanexação.")
raise ValidationError(
_("Data de anexação posterior à data de desanexação."))
try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
materia_anexada = MateriaLegislativa.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.'
.format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano']))
self.logger.warning(
"A matéria a ser anexada não existe no cadastro de matérias legislativas.")
raise ValidationError(msg)
materia_principal = self.instance.materia_principal
if materia_principal == materia_anexada:
self.logger.error("Matéria não pode ser anexada a si mesma.")
raise ValidationError(_('Matéria não pode ser anexada a si mesma'))
is_anexada = Anexada.objects.filter(
materia_principal=materia_principal,
materia_anexada=materia_anexada
).exclude(pk=self.instance.pk).exists()
if is_anexada:
self.logger.error("Matéria já se encontra anexada.")
raise ValidationError(_('Matéria já se encontra anexada'))
ciclico = False
anexadas_anexada = Anexada.objects.filter(
materia_principal=materia_anexada)
anexadas_visitadas = [materia_principal]
while anexadas_anexada:
anexadas = []
for anexa in anexadas_anexada:
if anexa.materia_anexada in anexadas_visitadas:
ciclico = True
break
else:
anexadas_visitadas.append(anexa.materia_anexada)
for a in Anexada.objects.filter(materia_principal=anexa.materia_anexada):
anexadas.append(a)
if ciclico:
break
anexadas_anexada = anexadas
if ciclico:
self.logger.error(
"A matéria não pode ser anexada por uma de suas anexadas.")
raise ValidationError(
_("A matéria não pode ser anexada por uma de suas anexadas."))
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 MateriaLegislativaFilterSet(django_filters.FilterSet):
ano = django_filters.ChoiceFilter(required=False,
label='Ano da Matéria',
choices=choice_anos_com_materias)
autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput())
autoria__primeiro_autor = django_filters.BooleanFilter(
required=False,
label=_('Primeiro Autor'))
autoria__autor__parlamentar_set__filiacao__partido = django_filters.ModelChoiceFilter(
queryset=Partido.objects.all(),
label=_('Matérias por Partido'))
ementa = django_filters.CharFilter(
label=_('Pesquisar expressões na ementa'),
method='filter_ementa'
)
indexacao = django_filters.CharFilter(lookup_expr='icontains',
label=_('Indexação'))
em_tramitacao = django_filters.ChoiceFilter(required=False,
label='Em tramitação',
choices=CHOICE_TRAMITACAO)
materiaassunto__assunto = django_filters.ModelChoiceFilter(
queryset=AssuntoMateria.objects.all(),
label=_('Assunto'))
numeracao__numero_materia = django_filters.NumberFilter(
required=False,
label=_('Número do processo'))
o = MateriaPesquisaOrderingFilter(help_text='')
tipo_listagem = forms.ChoiceField(
required=False,
choices=CHOICE_TIPO_LISTAGEM,
label=_('Tipo da Listagem do Resultado da Pesquisa'))
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['numero',
'numero_protocolo',
'numeracao__numero_materia',
'ano',
'tipo',
'data_apresentacao',
'data_publicacao',
'autoria__autor__tipo',
'autoria__primeiro_autor',
'autoria__autor__parlamentar_set__filiacao__partido',
'relatoria__parlamentar_id',
'tramitacao__unidade_tramitacao_destino',
'tramitacao__status',
'materiaassunto__assunto',
'em_tramitacao',
'tipo_origem_externa',
'numero_origem_externa',
'ano_origem_externa',
'data_origem_externa',
'local_origem_externa',
]
def filter_ementa(self, queryset, name, value):
texto = value.split()
q = Q()
for t in texto:
q &= Q(ementa__icontains=t)
return queryset.filter(q)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# self.filters['tipo'].label = 'Tipo de Matéria'
self.filters[
'autoria__autor__parlamentar_set__filiacao__partido'
].label = 'Partido do Autor'
self.filters['autoria__autor__tipo'].label = _('Tipo de Autor')
self.filters['relatoria__parlamentar_id'].label = _('Relatoria')
self.filters['tramitacao__unidade_tramitacao_destino'].label = _(
'Unidade de tramitação atual')
self.filters['tramitacao__status'].label = _(
'Status da tramitação atual')
self.filters['tramitacao__status'].label = _(
'Status da tramitação atual')
self.filters['o'].label = _('Ordenação')
self.form.fields['tipo_listagem'] = self.tipo_listagem
row1 = to_row(
[('tipo', 5), ('ementa', 7)])
row2 = to_row(
[('numero', 3),
('numeracao__numero_materia', 3),
('numero_protocolo', 3),
('ano', 3)])
row3 = to_row(
[('data_apresentacao', 6),
('data_publicacao', 6)])
row4 = 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'), 2),
('autoria__primeiro_autor', 2),
('autoria__autor__tipo', 3),
('autoria__autor__parlamentar_set__filiacao__partido', 3)
])
row6 = to_row(
[('relatoria__parlamentar_id', 6),
('em_tramitacao', 6)])
row7 = to_row(
[('tramitacao__unidade_tramitacao_destino', 6),
('tramitacao__status', 6),
])
row9 = to_row(
[('materiaassunto__assunto', 6), ('indexacao', 6)])
row8 = to_row(
[
('o', 8),
('tipo_listagem', 4)
])
row10 = to_row([
('tipo_origem_externa', 4),
('numero_origem_externa', 4),
('ano_origem_externa', 4),
])
row11 = to_row([
('data_origem_externa', 8),
('local_origem_externa', 4)
])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa Básica'),
row1, row2),
Fieldset(_('Como listar os resultados da pesquisa'),
row8
),
Fieldset(_('Origem externa'),
row10, row11
),
Fieldset(_('Pesquisa Avançada'),
row3,
HTML(autor_label),
HTML(autor_modal),
row4, row6, row7, row9,
form_actions(label=_('Pesquisar')))
)
@property
def qs(self):
qs = qs_override_django_filter(self)
if hasattr(self.form, 'cleaned_data') and self.form.cleaned_data[
'autoria__autor__parlamentar_set__filiacao__partido']:
q_data_inicio_e_fim = Q(data_apresentacao__gte=F(
'autoria__autor__parlamentar_set__filiacao__data'),
data_apresentacao__lte=F(
'autoria__autor__parlamentar_set__filiacao__data_desfiliacao'))
q_data_inicio = Q(
data_apresentacao__gte=F(
'autoria__autor__parlamentar_set__filiacao__data'),
autoria__autor__parlamentar_set__filiacao__data_desfiliacao__isnull=True
)
qs = qs.filter(
q_data_inicio_e_fim | q_data_inicio
)
return qs
def pega_ultima_tramitacao():
return Tramitacao.objects.values(
'materia_id').annotate(data_encaminhamento=Max(
'data_encaminhamento'),
id=Max('id')).values_list('id', flat=True)
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 DespachoInicialCreateForm(forms.Form):
comissao = forms.ModelMultipleChoiceField(
queryset=Comissao.objects.filter(ativa=True),
widget=forms.CheckboxSelectMultiple(),
label=Comissao._meta.verbose_name_plural)
def __init__(self, *args, **kwargs):
row1 = to_row(
[('comissao', 12), ])
self.helper = SaplFormHelper()
self.helper.form_method = 'POST'
self.helper.layout = SaplFormLayout(row1)
super().__init__(*args, **kwargs)
def clean(self):
super().clean()
comissoes = self.cleaned_data.get('comissao')
if not comissoes:
msg = _('Você deve escolher pelo menos uma comissão.')
raise ValidationError(msg)
if not self.is_valid():
return self.cleaned_data
errors = []
for comissao in comissoes:
if DespachoInicial.objects.filter(
materia=self.initial['materia'],
comissao=comissao,
).exists():
msg = _('Já existe um Despacho cadastrado para %s' %
comissao)
errors.append(msg)
if errors:
raise ValidationError(errors)
return self.cleaned_data
class DespachoInicialForm(ModelForm):
comissao = forms.ModelChoiceField(
queryset=Comissao.objects.filter(ativa=True), label=_('Comissão'))
class Meta:
model = DespachoInicial
fields = ['comissao']
def clean(self):
super(DespachoInicialForm, self).clean()
if not self.is_valid():
return self.cleaned_data
if DespachoInicial.objects.filter(
materia=self.instance.materia,
comissao=self.cleaned_data['comissao'],
).exclude(pk=self.instance.pk).exists():
msg = _('Já existe um Despacho cadastrado para %s' %
self.cleaned_data['comissao'])
raise ValidationError(msg)
return self.cleaned_data
class AutoriaForm(ModelForm):
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=True,
queryset=TipoAutor.objects.all(),
empty_label=_('Selecione'),)
data_relativa = forms.DateField(
widget=forms.HiddenInput(), required=False)
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super(AutoriaForm, self).__init__(*args, **kwargs)
self.fields['primeiro_autor'].required = True
if 'initial' in kwargs and 'materia' in kwargs['initial']:
materia = kwargs['initial']['materia']
self.fields['primeiro_autor'].initial = Autoria.objects.filter(
materia=materia).count() == 0
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')))
if not kwargs['instance']:
self.fields['autor'].choices = []
class Meta:
model = Autoria
fields = ['tipo_autor', 'autor', 'primeiro_autor', 'data_relativa']
def clean(self):
cd = super(AutoriaForm, self).clean()
if not self.is_valid():
return self.cleaned_data
autorias = Autoria.objects.filter(
materia=self.instance.materia, autor=cd['autor'])
pk = self.instance.pk
if ((not pk and autorias.exists()) or
(pk and autorias.exclude(pk=pk).exists())):
self.logger.error(
"Esse Autor (pk={}) já foi cadastrado.".format(pk))
raise ValidationError(_('Esse Autor já foi cadastrado.'))
return cd
class AutoriaMultiCreateForm(Form):
logger = logging.getLogger(__name__)
tipo_autor = ModelChoiceField(label=_('Tipo Autor'),
required=True,
queryset=TipoAutor.objects.all(),
empty_label=_('Selecione'),)
data_relativa = forms.DateField(
widget=forms.HiddenInput(), required=False)
autor = ModelMultipleChoiceField(
queryset=Autor.objects.all(),
label=_('Possiveis Autores'),
required=True,
widget=CheckboxSelectMultiple)
autores = ModelMultipleChoiceField(
queryset=Autor.objects.all(),
required=False,
widget=HiddenInput)
primeiro_autor = forms.ChoiceField(
required=True,
choices=YES_NO_CHOICES,
label="Primeiro Autor?"
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'initial' in kwargs and 'autores' in kwargs['initial']:
self.fields['primeiro_autor'].initial = kwargs['initial']['autores'].count(
) == 0
row1 = to_row([('tipo_autor', 10), ('primeiro_autor', 2)])
row2 = to_row([('autor', 12), ])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
_('Autorias'), row1, row2, 'data_relativa', 'autores',
form_actions(label='Incluir Autores Selecionados')))
self.fields['autor'].choices = []
def clean(self):
cd = super().clean()
if 'autores' in self.errors:
del self.errors['autores']
if 'autor' not in cd or not cd['autor'].exists():
self.logger.error(
"Ao menos um autor deve ser selecionado para inclusão")
raise ValidationError(
_('Ao menos um autor deve ser selecionado para inclusão'))
return cd
class AcessorioEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao']
def __init__(self, *args, **kwargs):
super(AcessorioEmLoteFilterSet, self).__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['data_apresentacao'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Documentos Acessórios em Lote'),
row1, row2, form_actions(label='Pesquisar')))
class AnexadaEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao']
def __init__(self, *args, **kwargs):
super(AnexadaEmLoteFilterSet, self).__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['data_apresentacao'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Matérias'),
row1, row2, form_actions(label='Pesquisar')))
class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao']
def __init__(self, *args, **kwargs):
super(PrimeiraTramitacaoEmLoteFilterSet, self).__init__(
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['data_apresentacao'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = False
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Primeira Tramitação'),
row1, row2, form_actions(label='Pesquisar')))
class TramitacaoEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao', 'tramitacao__status',
'tramitacao__unidade_tramitacao_destino']
def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteFilterSet, self).__init__(
*args, **kwargs)
self.filters['tipo'].label = _('Tipo de Matéria')
self.filters['data_apresentacao'].label = _('Data (Inicial - Final)')
self.filters['tramitacao__unidade_tramitacao_destino'
].label = _('Unidade Destino (Último Destino)')
self.filters['tramitacao__status'].label = _('Status')
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = False
self.form.fields['tramitacao__status'].required = True
self.form.fields[
'tramitacao__unidade_tramitacao_destino'].required = True
row1 = to_row([
('tipo', 4),
('tramitacao__unidade_tramitacao_destino', 4),
('tramitacao__status', 4)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Tramitação em Lote'),
row1, row2, form_actions(label=_('Pesquisar'))))
class TipoProposicaoForm(ModelForm):
logger = logging.getLogger(__name__)
content_type = forms.ModelChoiceField(
queryset=ContentType.objects.all(),
label=TipoProposicao._meta.get_field('content_type').verbose_name,
required=True,
help_text=TipoProposicao._meta.get_field('content_type').help_text)
tipo_conteudo_related_radio = ChoiceWithoutValidationField(
label="Seleção de Tipo",
required=False,
widget=forms.RadioSelect())
tipo_conteudo_related = forms.IntegerField(
widget=forms.HiddenInput(),
required=True)
class Meta:
model = TipoProposicao
fields = ['descricao',
'content_type',
'tipo_conteudo_related_radio',
'tipo_conteudo_related',
'perfis']
widgets = {'tipo_conteudo_related': forms.HiddenInput(),
'perfis': widgets.CheckboxSelectMultiple()}
def __init__(self, *args, **kwargs):
tipo_select = Fieldset(
TipoProposicao._meta.verbose_name,
Row(
to_column(
(
Row(
to_column(('descricao', 12)),
to_column(('perfis', 12)),
),
5
)
),
to_column(
(
Row(
to_column(('content_type', 12)),
to_column(('tipo_conteudo_related_radio', 12)),
to_column(('tipo_conteudo_related', 12)),
),
7
)
),
)
)
self.helper = SaplFormHelper()
self.helper.layout = SaplFormLayout(tipo_select)
super(TipoProposicaoForm, self).__init__(*args, **kwargs)
content_types = ContentType.objects.get_for_models(
*models_with_gr_for_model(TipoProposicao))
self.fields['content_type'].choices = [
(ct.pk, ct) for k, ct in content_types.items()]
# Ordena por id
self.fields['content_type'].choices.sort(key=lambda x: x[0])
if self.instance.pk:
self.fields[
'tipo_conteudo_related'].initial = self.instance.object_id
def clean(self):
super(TipoProposicaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cd = self.cleaned_data
content_type = cd['content_type']
if 'tipo_conteudo_related' not in cd or not cd[
'tipo_conteudo_related']:
self.logger.error("Seleção de Tipo não definida.")
raise ValidationError(
_('Seleção de Tipo não definida.'))
if not content_type.model_class().objects.filter(
pk=cd['tipo_conteudo_related']).exists():
self.logger.error("O Registro definido (%s) não está na base de %s."
% (cd['tipo_conteudo_related'], content_type))
raise ValidationError(
_('O Registro definido (%s) não está na base de %s.'
) % (cd['tipo_conteudo_related'], content_type))
"""
A unicidade de tipo proposição para tipo de conteudo
foi desabilitada pois existem casos em quem é o procedimento da
instituição convergir vários tipos de proposição
para um tipo de matéria.
unique_value = self._meta.model.objects.filter(
content_type=content_type, object_id=cd['tipo_conteudo_related'])
if self.instance.pk:
unique_value = unique_value.exclude(pk=self.instance.pk)
unique_value = unique_value.first()
if unique_value:
raise ValidationError(
_('Já existe um Tipo de Proposição (%s) '
'que foi defindo como (%s) para (%s)'
) % (unique_value,
content_type,
unique_value.tipo_conteudo_related))"""
return self.cleaned_data
@transaction.atomic
def save(self, commit=False):
tipo_proposicao = self.instance
assert tipo_proposicao.content_type
tipo_proposicao.tipo_conteudo_related = \
tipo_proposicao.content_type.model_class(
).objects.get(pk=self.cleaned_data['tipo_conteudo_related'])
return super().save(True)
class TipoProposicaoSelect(Select):
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option = super().create_option(name, value, label, selected,
index, subindex=subindex, attrs=attrs)
if value:
tipo = TipoProposicao.objects.get(id=value)
option['attrs']['data-has-perfil'] = str(tipo.perfis.exists())
return option
class TramitacaoEmLoteForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'urgente',
'turno',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto',
'user',
'ip',
'ultima_edicao']
widgets = {'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date()
ust = UnidadeTramitacao.objects.select_related().all()
unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut)
for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.orgao])
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.parlamentar])
self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
self.fields['urgente'].label = "Urgente? *"
row1 = to_row([
('data_tramitacao', 4),
('data_encaminhamento', 4),
('data_fim_prazo', 4)
])
row2 = to_row([
('unidade_tramitacao_local', 6),
('unidade_tramitacao_destino', 6),
])
row3 = to_row([
('status', 4),
('urgente', 4),
('turno', 4)
])
row4 = to_row([
('texto', 12)
])
documentos_checkbox_HTML = '''
<br\><br\><br\>
<fieldset>
<legend style="font-size: 24px;">Selecione as matérias para tramitação:</legend>
<table class="table table-striped table-hover">
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
</div>
<thead>
<tr><th>Matéria</th></tr>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td>
<input type="checkbox" name="materias" value="{{materia.id}}" {% if check %} checked {% endif %}/>
<a href="{% url 'sapl.materia:materialegislativa_detail' materia.id %}">
{{materia.tipo.sigla}} {{materia.tipo.descricao}} {{materia.numero}}/{{materia.ano}}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
'''
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
'Detalhes da tramitação:',
row1, row2, row3, row4,
HTML(documentos_checkbox_HTML),
form_actions(label='Salvar')
)
)
def clean(self):
cleaned_data = super(TramitacaoEmLoteForm, self).clean()
if not self.is_valid():
return self.cleaned_data
if 'data_encaminhamento' in cleaned_data:
data_enc_form = cleaned_data['data_encaminhamento']
if 'data_fim_prazo' in cleaned_data:
data_prazo_form = cleaned_data['data_fim_prazo']
if 'data_tramitacao' in cleaned_data:
data_tram_form = cleaned_data['data_tramitacao']
if not self.instance.data_tramitacao:
if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.error('A data de tramitação ({}) deve ser '
'menor ou igual a data de hoje ({})!'
.format(cleaned_data['data_tramitacao'], timezone.now().date()))
msg = _(
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
raise ValidationError(msg)
if data_enc_form:
if data_enc_form < data_tram_form:
self.logger.warning('A data de encaminhamento ({}) deve ser maior que a data de tramitação ({})!'
.format(data_enc_form, data_tram_form))
msg = _(
'A data de encaminhamento deve ser maior que a data de tramitação!')
raise ValidationError(msg)
if data_prazo_form:
if data_prazo_form < data_tram_form:
self.logger.error('A data fim de prazo ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_prazo_form, data_tram_form))
msg = _('A data fim de prazo deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
return cleaned_data
@transaction.atomic
def save(self, commit=True):
cd = self.cleaned_data
materias = self.initial['materias']
user = self.initial['user'] if 'user' in self.initial else None
ip = self.initial['ip'] if 'ip' in self.initial else ''
ultima_edicao = self.initial['ultima_edicao'] if 'ultima_edicao' in self.initial else ''
tramitar_anexadas = AppConfig.attr('tramitacao_materia')
for mat_id in materias:
mat = MateriaLegislativa.objects.get(id=mat_id)
tramitacao = Tramitacao.objects.create(
status=cd['status'],
materia=mat,
data_tramitacao=cd['data_tramitacao'],
unidade_tramitacao_local=cd['unidade_tramitacao_local'],
unidade_tramitacao_destino=cd['unidade_tramitacao_destino'],
data_encaminhamento=cd['data_encaminhamento'],
urgente=cd['urgente'],
turno=cd['turno'],
texto=cd['texto'],
data_fim_prazo=cd['data_fim_prazo'],
user=user,
ip=ip,
ultima_edicao=ultima_edicao
)
mat.em_tramitacao = False if tramitacao.status.indicador == "F" else True
mat.save()
if tramitar_anexadas:
lista_tramitacao = []
anexadas = lista_anexados(mat)
for ml in anexadas:
if not ml.tramitacao_set.order_by('-data_tramitacao', '-id').all() or \
ml.tramitacao_set.order_by('-data_tramitacao', '-id').first().unidade_tramitacao_destino \
== tramitacao.unidade_tramitacao_local:
ml.em_tramitacao = False if tramitacao.status.indicador == "F" else True
ml.save()
lista_tramitacao.append(Tramitacao(
status=tramitacao.status,
materia=ml,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
turno=tramitacao.turno,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip,
ultima_edicao=tramitacao.ultima_edicao
))
# TODO: BULK UPDATE não envia Signal para Tramitacao
Tramitacao.objects.bulk_create(lista_tramitacao)
return tramitacao
class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
logger = logging.getLogger(__name__)
TIPO_TEXTO_CHOICE = [
('D', _('Arquivo Digital')),
('T', _('Texto Articulado'))
]
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
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)
tipo_texto = forms.ChoiceField(
label=_('Tipo do Texto da Proposição'),
required=False,
choices=TIPO_TEXTO_CHOICE,
widget=widgets.RadioSelect())
materia_de_vinculo = forms.ModelChoiceField(
queryset=MateriaLegislativa.objects.all(),
widget=widgets.HiddenInput(),
required=False)
receber_recibo = forms.TypedChoiceField(
choices=YES_NO_CHOICES,
widget=widgets.HiddenInput(),
required=False)
numero_materia_futuro = forms.IntegerField(
label='Número (Opcional)', required=False)
class Meta:
model = Proposicao
fields = ['tipo',
'receber_recibo',
'descricao',
'observacao',
'texto_original',
'materia_de_vinculo',
'tipo_materia',
'numero_materia',
'ano_materia',
'tipo_texto',
'hash_code',
'numero_materia_futuro',
'user',
'ip',
'ultima_edicao']
widgets = {
'descricao': widgets.Textarea(attrs={'rows': 4}),
'tipo': TipoProposicaoSelect(),
'hash_code': forms.HiddenInput(),
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()
}
def __init__(self, *args, **kwargs):
self.texto_articulado_proposicao = AppConfig.attr(
'texto_articulado_proposicao')
self.receber_recibo = AppConfig.attr(
'receber_recibo_proposicao')
if not self.texto_articulado_proposicao:
if 'tipo_texto' in self._meta.fields:
self._meta.fields.remove('tipo_texto')
else:
if 'tipo_texto' not in self._meta.fields:
self._meta.fields.append('tipo_texto')
fields = [
to_column((Fieldset(
TipoProposicao._meta.verbose_name, Field('tipo')), 12)),
to_column(
(Alert('teste',
css_class="ementa_materia hidden alert-info",
dismiss=False), 12)),
to_column(('descricao', 12)),
to_column(('observacao', 12)),
]
if AppConfig.objects.last().escolher_numero_materia_proposicao:
fields.append(to_column(('numero_materia_futuro', 12)),)
else:
if 'numero_materia_futuro' in self._meta.fields:
self._meta.fields.remove('numero_materia_futuro')
if self.texto_articulado_proposicao:
fields.append(
to_column((InlineRadios('tipo_texto'), 5)),)
fields.append(to_column((
'texto_original', 7 if self.texto_articulado_proposicao else 12)))
fields.append(
to_column(
(
Fieldset(
_('Outras informações - Vincular a Matéria Legislativa Existente'),
to_row([('tipo_materia', 12), ]),
to_row([('numero_materia', 6),
('ano_materia', 6)]),
), 12)),
)
self.helper = SaplFormHelper()
self.helper.layout = SaplFormLayout(*fields)
super(ProposicaoForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.fields['tipo_texto'].initial = ''
if self.instance.texto_original:
self.fields['tipo_texto'].initial = 'D'
if self.texto_articulado_proposicao:
if self.instance.texto_articulado.exists():
self.fields['tipo_texto'].initial = 'T'
if self.instance.materia_de_vinculo:
self.fields[
'tipo_materia'
].initial = self.instance.materia_de_vinculo.tipo
self.fields[
'numero_materia'
].initial = self.instance.materia_de_vinculo.numero
self.fields[
'ano_materia'
].initial = self.instance.materia_de_vinculo.ano
def clean_texto_original(self):
texto_original = self.cleaned_data.get('texto_original', False)
if texto_original:
validar_arquivo(texto_original, "Texto Original")
return texto_original
def gerar_hash(self, inst, receber_recibo):
inst.save()
if receber_recibo == True:
inst.hash_code = ''
else:
if inst.texto_original:
inst.hash_code = gerar_hash_arquivo(
inst.texto_original.path, str(inst.pk))
elif inst.texto_articulado.exists():
ta = inst.texto_articulado.first()
inst.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(inst.pk)
def clean(self):
super(ProposicaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cd = self.cleaned_data
texto_original = cd.get('texto_original', False)
if texto_original:
validar_arquivo(texto_original, 'Texto Original')
tm, am, nm = (cd.get('tipo_materia', ''),
cd.get('ano_materia', ''),
cd.get('numero_materia', ''))
if cd['numero_materia_futuro'] and \
'tipo' in cd and \
MateriaLegislativa.objects.filter(tipo=cd['tipo'].tipo_conteudo_related,
ano=timezone.now().year,
numero=cd['numero_materia_futuro']):
raise ValidationError(_("A matéria {} {}/{} já existe.".format(cd['tipo'].tipo_conteudo_related.descricao,
cd['numero_materia_futuro'],
timezone.now().year)))
if tm and am and nm:
try:
self.logger.debug("Tentando obter objeto MateriaLegislativa (tipo_id={}, ano={}, numero={})."
.format(tm, am, nm))
materia_de_vinculo = MateriaLegislativa.objects.get(
tipo_id=tm,
ano=am,
numero=nm
)
except ObjectDoesNotExist:
self.logger.error("Objeto MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) não existe!"
.format(tm, am, nm))
raise ValidationError(_('Matéria Vinculada não existe!'))
else:
self.logger.info("MateriaLegislativa vinculada (tipo_id={}, ano={}, numero={}) com sucesso."
.format(tm, am, nm))
cd['materia_de_vinculo'] = materia_de_vinculo
return cd
def save(self, commit=True):
cd = self.cleaned_data
inst = self.instance
receber_recibo = AppConfig.objects.last().receber_recibo_proposicao
if inst.pk:
if 'tipo_texto' in cd:
if cd['tipo_texto'] == 'T' and inst.texto_original:
inst.texto_original.delete()
elif cd['tipo_texto'] != 'T':
inst.texto_articulado.all().delete()
if 'texto_original' in cd and\
not cd['texto_original'] and \
inst.texto_original:
inst.texto_original.delete()
self.gerar_hash(inst, receber_recibo)
return super().save(commit)
inst.ano = timezone.now().year
sequencia_numeracao = AppConfig.attr('sequencia_numeracao_proposicao')
if sequencia_numeracao == 'A':
numero__max = Proposicao.objects.filter(
autor=inst.autor,
ano=timezone.now().year).aggregate(Max('numero_proposicao'))
elif sequencia_numeracao == 'B':
numero__max = Proposicao.objects.filter(
ano=timezone.now().year).aggregate(Max('numero_proposicao'))
numero__max = numero__max['numero_proposicao__max']
inst.numero_proposicao = (
numero__max + 1) if numero__max else 1
self.gerar_hash(inst, receber_recibo)
inst.save()
return inst
class DevolverProposicaoForm(forms.ModelForm):
justificativa_devolucao = forms.CharField(
required=False, widget=widgets.Textarea(attrs={'rows': 5}))
logger = logging.getLogger(__name__)
class Meta:
model = Proposicao
fields = [
'justificativa_devolucao',
'observacao',
'user',
'ip'
]
widgets = {
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
# esta chamada isola o __init__ de ProposicaoForm
super(DevolverProposicaoForm, self).__init__(*args, **kwargs)
fields = []
fields.append(
Fieldset(
_('Registro de Devolução'),
to_column(('justificativa_devolucao', 12)),
to_column(('observacao', 12)),
to_column(
(form_actions(label=_('Devolver'),
name='devolver',
css_class='btn-danger float-right'), 12)
)
)
)
self.helper = SaplFormHelper()
self.helper.layout = Layout(*fields)
def clean(self):
super(DevolverProposicaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cd = self.cleaned_data
if 'justificativa_devolucao' not in cd or\
not cd['justificativa_devolucao']:
# TODO Implementar notificação ao autor por email
self.logger.error("Adicione uma Justificativa para devolução.")
raise ValidationError(
_('Adicione uma Justificativa para devolução.'))
return cd
@transaction.atomic
def save(self, commit=False):
cd = self.cleaned_data
self.instance.data_devolucao = timezone.now()
self.instance.data_recebimento = None
self.instance.data_envio = None
self.instance.save()
if self.instance.texto_articulado.exists():
ta = self.instance.texto_articulado.first()
ta.privacidade = STATUS_TA_PRIVATE
ta.editing_locked = False
ta.save()
observacao = self.instance.justificativa_devolucao
HistoricoProposicao.objects.create(proposicao=self.instance,
status='D',
user=self.initial['user'],
ip=self.initial['ip'],
observacao=observacao)
self.instance.results = {
'messages': {
'success': [_('Devolução efetuada com sucesso.'), ]
},
'url': reverse('sapl.materia:receber-proposicao')
}
return self.instance
class ConfirmarProposicaoForm(ProposicaoForm):
tipo_readonly = forms.CharField(
label=TipoProposicao._meta.verbose_name,
required=False, widget=widgets.TextInput(
attrs={'readonly': 'readonly'}))
autor_readonly = forms.CharField(
label=Autor._meta.verbose_name,
required=False, widget=widgets.TextInput(
attrs={'readonly': 'readonly'}))
regime_tramitacao = forms.ModelChoiceField(label="Regime de tramitação",
required=False, queryset=RegimeTramitacao.objects.all())
gerar_protocolo = forms.ChoiceField(
required=False,
label=_(
'Gerar Protocolo na incorporação?'),
choices=YES_NO_CHOICES,
widget=widgets.RadioSelect())
numero_de_paginas = forms.IntegerField(required=False, min_value=0,
label=_('Número de Páginas'),)
class Meta:
model = Proposicao
fields = [
'data_envio',
'descricao',
'observacao',
'gerar_protocolo',
'numero_de_paginas',
'numero_materia_futuro',
'user',
'ip'
]
widgets = {
'descricao': widgets.Textarea(
attrs={'readonly': 'readonly', 'rows': 4}),
'data_envio': widgets.DateTimeInput(
attrs={'readonly': 'readonly'}),
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
self.proposicao_incorporacao_obrigatoria = \
AppConfig.attr('proposicao_incorporacao_obrigatoria')
if self.proposicao_incorporacao_obrigatoria != 'C':
if 'gerar_protocolo' in self._meta.fields:
self._meta.fields.remove('gerar_protocolo')
else:
if 'gerar_protocolo' not in self._meta.fields:
self._meta.fields.append('gerar_protocolo')
if self.proposicao_incorporacao_obrigatoria == 'N':
if 'numero_de_paginas' in self._meta.fields:
self._meta.fields.remove('numero_de_paginas')
else:
if 'numero_de_paginas' not in self._meta.fields:
self._meta.fields.append('numero_de_paginas')
self.instance = kwargs.get('instance', None)
if not self.instance:
self.logger.error("Erro na Busca por proposição a incorporar")
raise ValueError(_('Erro na Busca por proposição a incorporar'))
if self.instance.tipo.content_type.model_class() == TipoDocumento:
if 'numero_de_paginas' in self._meta.fields:
self._meta.fields.remove('numero_de_paginas')
if 'gerar_protocolo' in self._meta.fields:
self._meta.fields.remove('gerar_protocolo')
if 'regime_tramitacao' in self._meta.fields:
self._meta.fields.remove('regime_tramitacao')
# esta chamada isola o __init__ de ProposicaoForm
super(ProposicaoForm, self).__init__(*args, **kwargs)
if self.instance.tipo.content_type.model_class() ==\
TipoMateriaLegislativa:
self.fields['regime_tramitacao'].required = True
fields = [
Fieldset(
_('Dados Básicos'),
to_row(
[
('tipo_readonly', 3),
('data_envio', 3),
('autor_readonly', 3),
('numero_materia_futuro', 3),
('descricao', 12),
('observacao', 12)
]
)
)
]
if not AppConfig.objects.last().escolher_numero_materia_proposicao or \
not self.instance.numero_materia_futuro:
if 'numero_materia_futuro' in self._meta.fields:
del fields[0][0][3]
fields.append(
Fieldset(
_('Vinculado a Matéria Legislativa'),
to_row(
[
('tipo_materia', 3),
('numero_materia', 2),
('ano_materia', 2),
(Alert(_('O responsável pela incorporação pode '
'alterar a anexação. Limpar os campos '
'de Vinculação gera um %s independente '
'sem anexação se for possível para esta '
'Proposição. Não sendo, a rotina de incorporação '
'não permitirá estes campos serem vazios.'
) % self.instance.tipo.content_type,
css_class="alert-info",
dismiss=False), 5),
(Alert('',
css_class="ementa_materia hidden alert-info",
dismiss=False), 12),
]
)
)
)
itens_incorporacao = []
if self.instance.tipo.content_type.model_class() == \
TipoMateriaLegislativa:
itens_incorporacao = [to_column(('regime_tramitacao', 4))]
if self.proposicao_incorporacao_obrigatoria == 'C':
itens_incorporacao.append(to_column((InlineRadios(
'gerar_protocolo'), 4)))
if self.proposicao_incorporacao_obrigatoria != 'N':
itens_incorporacao.append(to_column(('numero_de_paginas', 4)))
itens_incorporacao.append(
to_column(
(form_actions(label=_('Incorporar'),
name='incorporar'), 12)
)
)
fields.append(
Fieldset(_('Registro de Incorporação'), Row(*itens_incorporacao)))
self.helper = SaplFormHelper()
self.helper.layout = Layout(*fields)
self.fields['tipo_readonly'].initial = self.instance.tipo.descricao
self.fields['autor_readonly'].initial = str(self.instance.autor)
if self.instance.numero_materia_futuro:
self.fields['numero_materia_futuro'].initial = self.instance.numero_materia_futuro
if self.instance.materia_de_vinculo:
self.fields[
'tipo_materia'
].initial = self.instance.materia_de_vinculo.tipo
self.fields[
'numero_materia'
].initial = self.instance.materia_de_vinculo.numero
self.fields[
'ano_materia'
].initial = self.instance.materia_de_vinculo.ano
if self.proposicao_incorporacao_obrigatoria == 'C':
self.fields['gerar_protocolo'].initial = True
def clean(self):
super(ConfirmarProposicaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
numeracao = AppConfig.attr('sequencia_numeracao_proposicao')
if not numeracao:
self.logger.error("A sequência de numeração (por ano ou geral)"
" não foi configurada para a aplicação em "
"tabelas auxiliares")
raise ValidationError("A sequência de numeração (por ano ou geral)"
" não foi configurada para a aplicação em "
"tabelas auxiliares")
cd = ProposicaoForm.clean(self)
if self.instance.tipo.content_type.model_class() ==\
TipoMateriaLegislativa:
if 'regime_tramitacao' not in cd or\
not cd['regime_tramitacao']:
self.logger.error("Regime de Tramitação deve ser informado.")
raise ValidationError(
_('Regime de Tramitação deve ser informado.'))
elif self.instance.tipo.content_type.model_class(
) == TipoDocumento and not cd['materia_de_vinculo']:
self.logger.error("Documentos não podem ser incorporados sem definir "
"para qual Matéria Legislativa ele se destina.")
raise ValidationError(
_('Documentos não podem ser incorporados sem definir '
'para qual Matéria Legislativa ele se destina.'))
return cd
@transaction.atomic
def save(self, commit=False):
# TODO Implementar workflow entre protocolo e autores
cd = self.cleaned_data
self.instance.justificativa_devolucao = ''
self.instance.data_devolucao = None
self.instance.data_recebimento = timezone.now()
self.instance.materia_de_vinculo = cd['materia_de_vinculo']
if self.instance.texto_articulado.exists():
ta = self.instance.texto_articulado.first()
ta.privacidade = STATUS_TA_IMMUTABLE_PUBLIC
ta.editing_locked = True
ta.save()
self.instance.save()
"""
TipoProposicao possui conteúdo genérico para a modelegam de tipos
relacionados e, a esta modelagem, qual o objeto que está associado.
Porem, cada registro a ser gerado pode possuir uma estrutura diferente,
é os casos básicos já implementados,
TipoDocumento e TipoMateriaLegislativa, que são modelos utilizados
em DocumentoAcessorio e MateriaLegislativa geradas,
por sua vez a partir de uma Proposição.
Portanto para estas duas e para outras implementações que possam surgir
possuindo com matéria prima uma Proposição, dada sua estrutura,
deverá contar também com uma implementação particular aqui no código
abaixo.
"""
self.instance.results = {
'messages': {
'success': [_('Proposição incorporada com sucesso'), ]
},
'url': reverse('sapl.materia:receber-proposicao')
}
proposicao = self.instance
conteudo_gerado = None
HistoricoProposicao.objects.create(proposicao=proposicao,
status='R',
user=self.initial['user'],
ip=self.initial['ip'],
)
if self.instance.tipo.content_type.model_class(
) == TipoMateriaLegislativa:
numeracao = None
try:
self.logger.debug(
"Tentando obter modelo de sequência de numeração.")
numeracao = AppConfig.objects.last(
).sequencia_numeracao_protocolo
except AttributeError as e:
self.logger.error("Erro ao obter modelo. " + str(e))
pass
tipo = self.instance.tipo.tipo_conteudo_related
if tipo.sequencia_numeracao:
numeracao = tipo.sequencia_numeracao
ano = timezone.now().year
if numeracao == 'A':
numero = MateriaLegislativa.objects.filter(
ano=ano, tipo=tipo).aggregate(Max('numero'))
elif numeracao == 'L':
legislatura = Legislatura.objects.filter(
data_inicio__year__lte=ano,
data_fim__year__gte=ano).first()
data_inicio = legislatura.data_inicio
data_fim = legislatura.data_fim
numero = MateriaLegislativa.objects.filter(
data_apresentacao__gte=data_inicio,
data_apresentacao__lte=data_fim,
tipo=tipo).aggregate(
Max('numero'))
elif numeracao == 'U':
numero = MateriaLegislativa.objects.filter(
tipo=tipo).aggregate(Max('numero'))
if numeracao is None:
numero['numero__max'] = 0
if cd['numero_materia_futuro'] and not MateriaLegislativa.objects.filter(tipo=tipo,
ano=ano,
numero=cd['numero_materia_futuro']):
max_numero = cd['numero_materia_futuro']
else:
max_numero = numero['numero__max'] + \
1 if numero['numero__max'] else 1
# dados básicos
materia = MateriaLegislativa()
materia.numero = max_numero
materia.tipo = tipo
materia.ementa = proposicao.descricao
materia.ano = ano
materia.data_apresentacao = timezone.now()
materia.em_tramitacao = True
materia.regime_tramitacao = cd['regime_tramitacao']
if proposicao.texto_original:
materia.texto_original = File(
proposicao.texto_original,
os.path.basename(proposicao.texto_original.path))
materia.save()
conteudo_gerado = materia
if proposicao.texto_articulado.exists():
ta = proposicao.texto_articulado.first()
ta_materia = ta.clone_for(materia)
ta_materia.editing_locked = True
ta_materia.privacidade = STATUS_TA_IMMUTABLE_PUBLIC
ta_materia.save()
self.instance.results['messages']['success'].append(_(
'Matéria Legislativa registrada com sucesso (%s)'
) % str(materia))
# autoria
autoria = Autoria()
autoria.autor = proposicao.autor
autoria.materia = materia
autoria.primeiro_autor = True
autoria.save()
self.instance.results['messages']['success'].append(_(
'Autoria registrada para (%s)'
) % str(autoria.autor))
# Matéria de vinlculo
if proposicao.materia_de_vinculo:
anexada = Anexada()
anexada.materia_principal = proposicao.materia_de_vinculo
anexada.materia_anexada = materia
anexada.data_anexacao = timezone.now()
anexada.save()
self.instance.results['messages']['success'].append(_(
'Matéria anexada a (%s)'
) % str(anexada.materia_principal))
self.instance.results['url'] = reverse(
'sapl.materia:materialegislativa_detail',
kwargs={'pk': materia.pk})
elif self.instance.tipo.content_type.model_class() == TipoDocumento:
# dados básicos
doc = DocumentoAcessorio()
doc.materia = proposicao.materia_de_vinculo
doc.autor = str(proposicao.autor)[:200]
doc.tipo = proposicao.tipo.tipo_conteudo_related
doc.ementa = proposicao.descricao
""" FIXME verificar questão de nome e data de documento,
doc acessório. Possivelmente pode possuir data anterior a
data de envio e/ou recebimento dada a incorporação.
"""
doc.nome = str(proposicao.tipo.tipo_conteudo_related)[:30]
doc.data = proposicao.data_envio
doc.arquivo = proposicao.texto_original = File(
proposicao.texto_original,
os.path.basename(proposicao.texto_original.path))
doc.save()
conteudo_gerado = doc
self.instance.results['messages']['success'].append(_(
'Documento Acessório registrado com sucesso e anexado (%s)'
) % str(doc.materia))
self.instance.results['url'] = reverse(
'sapl.materia:documentoacessorio_detail',
kwargs={'pk': doc.pk})
proposicao.conteudo_gerado_related = conteudo_gerado
proposicao.save()
if self.instance.tipo.content_type.model_class() == TipoDocumento:
return self.instance
# Nunca gerar protocolo
if self.proposicao_incorporacao_obrigatoria == 'N':
return self.instance
# ocorre se proposicao_incorporacao_obrigatoria == 'C' (condicional)
# and gerar_protocolo == False
if 'gerar_protocolo' not in cd or cd['gerar_protocolo'] == 'False':
return self.instance
# resta a opção proposicao_incorporacao_obrigatoria == 'C'
# and gerar_protocolo == True
# ou, proposicao_incorporacao_obrigatoria == 'O'
# que são idênticas.
"""
apesar de TipoProposicao estar com conteudo e tipo conteudo genérico,
aqui na incorporação de proposições, para gerar protocolo, cada caso
possível de conteudo em tipo de proposição deverá ser tratado
isoladamente justamente por Protocolo não estar generalizado com
GenericForeignKey
"""
numeracao = AppConfig.attr('sequencia_numeracao_protocolo')
if numeracao == 'A':
nm = Protocolo.objects.filter(
ano=timezone.now().year).aggregate(Max('numero'))
elif numeracao == 'L':
legislatura = Legislatura.objects.filter(
data_inicio__year__lte=timezone.now().year,
data_fim__year__gte=timezone.now().year).first()
ano_inicio = legislatura.data_inicio.year
ano_fim = legislatura.data_fim.year
nm = Protocolo.objects.filter(
ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero'))
else:
# numeracao == 'U' ou não informada
nm = Protocolo.objects.all().aggregate(Max('numero'))
protocolo = Protocolo()
protocolo.numero = (nm['numero__max'] + 1) if nm['numero__max'] else 1
protocolo.ano = timezone.now().year
protocolo.tipo_protocolo = '1'
protocolo.user = proposicao.user
protocolo.de_proposicao = True
protocolo.interessado = str(proposicao.autor)[
:200] # tamanho máximo 200
protocolo.autor = proposicao.autor
protocolo.assunto_ementa = proposicao.descricao
protocolo.numero_paginas = cd['numero_de_paginas']
protocolo.anulado = False
if self.instance.tipo.content_type.model_class(
) == TipoMateriaLegislativa:
protocolo.tipo_materia = proposicao.tipo.tipo_conteudo_related
protocolo.tipo_processo = '1'
elif self.instance.tipo.content_type.model_class() == TipoDocumento:
protocolo.tipo_documento = proposicao.tipo.tipo_conteudo_related
protocolo.tipo_processo = '0'
protocolo.save()
HistoricoProposicao.objects.create(proposicao=proposicao,
status='E')
self.instance.results['messages']['success'].append(_(
'Protocolo realizado com sucesso'))
self.instance.results['url'] = reverse(
'sapl.protocoloadm:protocolo_mostrar',
kwargs={'pk': protocolo.pk})
conteudo_gerado.numero_protocolo = protocolo.numero
conteudo_gerado.save()
return self.instance
class MateriaAssuntoForm(ModelForm):
class Meta:
model = MateriaAssunto
fields = ['materia', 'assunto']
widgets = {'materia': forms.HiddenInput()}
class EtiquetaPesquisaForm(forms.Form):
logger = logging.getLogger(__name__)
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
queryset=TipoMateriaLegislativa.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')
)
processo_inicial = forms.IntegerField(
label='Processo Inicial',
required=False)
processo_final = forms.IntegerField(
label='Processo Final',
required=False)
def __init__(self, *args, **kwargs):
super(EtiquetaPesquisaForm, self).__init__(*args, **kwargs)
row1 = to_row(
[('tipo_materia', 6),
('data_inicial', 3),
('data_final', 3)])
row2 = to_row(
[('processo_inicial', 6),
('processo_final', 6)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
('Formulário de Etiqueta'),
row1, row2,
form_actions(label='Pesquisar')
)
)
def clean(self):
super(EtiquetaPesquisaForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
# Verifica se algum campo de data foi preenchido
if cleaned_data['data_inicial'] or cleaned_data['data_final']:
# Então verifica se o usuário preencheu o Incial e mas não
# preencheu o Final, ou vice-versa
if (not cleaned_data['data_inicial'] or
not cleaned_data['data_final']):
self.logger.error("Caso pesquise por data, os campos de Data Incial e "
"Data Final devem ser preenchidos obrigatoriamente")
raise ValidationError(_(
'Caso pesquise por data, os campos de Data Incial e ' +
'Data Final devem ser preenchidos obrigatoriamente'))
# Caso tenha preenchido, verifica se a data final é maior que
# a inicial
elif cleaned_data['data_final'] < cleaned_data['data_inicial']:
self.logger.error("A Data Final ({}) não pode ser menor que a Data Inicial({})."
.format(cleaned_data['data_final'], cleaned_data['data_inicial']))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
# O mesmo processo anterior é feito com o processo
if (cleaned_data['processo_inicial'] or
cleaned_data['processo_final']):
if (not cleaned_data['processo_inicial'] or
not cleaned_data['processo_final']):
self.logger.error("Caso pesquise por número de processo, os campos de "
"Processo Inicial e Processo Final "
"devem ser preenchidos obrigatoriamente")
raise ValidationError(_(
'Caso pesquise por número de processo, os campos de ' +
'Processo Inicial e Processo Final ' +
'devem ser preenchidos obrigatoriamente'))
elif (cleaned_data['processo_final'] <
cleaned_data['processo_inicial']):
self.logger.error("O processo final ({}) não pode ser menor que o inicial ({})."
.format(cleaned_data['processo_final'], cleaned_data['processo_inicial']))
raise ValidationError(_(
'O processo final não pode ser menor que o inicial'))
return cleaned_data
class FichaPesquisaForm(forms.Form):
logger = logging.getLogger(__name__)
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
queryset=TipoMateriaLegislativa.objects.all(),
empty_label='Selecione')
data_inicial = forms.DateField(
label='Data Inicial',
widget=forms.DateInput(format='%d/%m/%Y')
)
data_final = forms.DateField(
label='Data Final',
widget=forms.DateInput(format='%d/%m/%Y')
)
def __init__(self, *args, **kwargs):
super(FichaPesquisaForm, self).__init__(*args, **kwargs)
row1 = to_row(
[('tipo_materia', 6),
('data_inicial', 3),
('data_final', 3)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
('Formulário de Ficha'),
row1,
form_actions(label='Pesquisar')
)
)
def clean(self):
super(FichaPesquisaForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
if not self.is_valid():
return cleaned_data
if cleaned_data['data_final'] < cleaned_data['data_inicial']:
self.logger.error("A Data Final ({}) não pode ser menor que a Data Inicial ({})."
.format(cleaned_data['data_final'], cleaned_data['data_inicial']))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
return cleaned_data
class FichaSelecionaForm(forms.Form):
materia = forms.ModelChoiceField(
widget=forms.RadioSelect,
queryset=MateriaLegislativa.objects.all(),
label='')
def __init__(self, *args, **kwargs):
super(FichaSelecionaForm, self).__init__(*args, **kwargs)
row1 = to_row(
[('materia', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
('Selecione a ficha que deseja imprimir'),
row1,
form_actions(label='Gerar Impresso')
)
)
class StatusTramitacaoFilterSet(django_filters.FilterSet):
descricao = django_filters.CharFilter(
label=_("Descrição do Status"), method='multifield_filter')
class Meta:
model = StatusTramitacao
fields = ["descricao"]
def multifield_filter(self, queryset, name, value):
return queryset.filter(Q(sigla__icontains=value) | Q(descricao__icontains=value))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
row0 = to_row([("descricao", 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = "GET"
self.form.helper.layout = Layout(
Fieldset(_("Pesquisa de Status de Tramitacao"),
row0, form_actions(label="Pesquisar"))
)
class ExcluirTramitacaoEmLote(forms.Form):
logger = logging.getLogger(__name__)
data_tramitacao = forms.DateField(required=True,
label=_('Data da Tramitação'))
unidade_tramitacao_local = forms.ModelChoiceField(label=_('Unidade Local'),
required=True,
queryset=UnidadeTramitacao.objects.all(),
empty_label='------')
unidade_tramitacao_destino = forms.ModelChoiceField(label=_('Unidade Destino'),
required=True,
queryset=UnidadeTramitacao.objects.all(),
empty_label='------')
status = forms.ModelChoiceField(label=_('Status'),
required=True,
queryset=StatusTramitacao.objects.all(),
empty_label='------')
def clean(self):
super(ExcluirTramitacaoEmLote, self).clean()
cleaned_data = self.cleaned_data
if not self.is_valid():
return cleaned_data
data_tramitacao = cleaned_data['data_tramitacao']
unidade_tramitacao_local = cleaned_data['unidade_tramitacao_local']
unidade_tramitacao_destino = cleaned_data['unidade_tramitacao_destino']
status = cleaned_data['status']
tramitacao_set = Tramitacao.objects.filter(data_tramitacao=data_tramitacao,
unidade_tramitacao_local=unidade_tramitacao_local,
unidade_tramitacao_destino=unidade_tramitacao_destino,
status=status)
if not tramitacao_set.exists():
self.logger.error("Não existem tramitações com os dados informados "
" (data_tramitacao={}, unidade_tramitacao_local={})."
"unidade_tramitacao_destino={}, status={})."
.format(data_tramitacao, unidade_tramitacao_local,
unidade_tramitacao_destino, status))
raise forms.ValidationError(
_("Não existem tramitações com os dados informados."))
return cleaned_data
def __init__(self, *args, **kwargs):
super(ExcluirTramitacaoEmLote, self).__init__(*args, **kwargs)
row1 = to_row(
[('data_tramitacao', 6),
('status', 6), ])
row2 = to_row(
[('unidade_tramitacao_local', 6),
('unidade_tramitacao_destino', 6)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(_('Dados das Tramitações'),
row1,
row2,
HTML("&nbsp;"),
form_actions(label='Excluir')
)
)
class MateriaPesquisaSimplesForm(forms.Form):
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
queryset=TipoMateriaLegislativa.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_materia', 6),
('data_inicial', 3),
('data_final', 3)])
row2 = to_row(
[('titulo', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
'Índice de Materias',
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
class ConfigEtiquetaMateriaLegislativaForms(ModelForm):
class Meta:
model = ConfigEtiquetaMateriaLegislativa
fields = '__all__'