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.
 
 
 
 
 

1357 lines
47 KiB

from datetime import date, datetime
import os
from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes,
InlineRadios)
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (HTML, Button, Column, Field, Fieldset, Layout,
Submit)
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.core.urlresolvers import reverse
from django.db import models, transaction
from django.db.models import Max
from django.forms import ModelForm, widgets
from django.forms.forms import Form
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor
from sapl.comissoes.models import Comissao
from sapl.compilacao.models import STATUS_TA_PRIVATE,\
STATUS_TA_IMMUTABLE_PUBLIC, TextoArticulado
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row)
from sapl.materia.models import TipoProposicao, MateriaLegislativa,\
RegimeTramitacao, TipoDocumento
from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import Protocolo
from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
ChoiceWithoutValidationField,
MateriaPesquisaOrderingFilter, RangeWidgetOverride,
autor_label, autor_modal, models_with_gr_for_model)
import sapl
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, Numeracao,
Proposicao, Relatoria, TipoMateriaLegislativa, Tramitacao,
UnidadeTramitacao)
def ANO_CHOICES():
return [('', '---------')] + RANGE_ANOS
def em_tramitacao():
return [('', 'Tanto Faz'),
(True, 'Sim'),
(False, 'Não')]
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 = FormHelper()
self.helper.layout = Layout(
Fieldset(
_('Incorporar Proposição'), row1,
form_actions(save_label='Buscar Proposição')
)
)
super(ReceberProposicaoForm, self).__init__(*args, **kwargs)
class MateriaSimplificadaForm(ModelForm):
class Meta:
model = MateriaLegislativa
fields = ['tipo', 'numero', 'ano', 'data_apresentacao',
'numero_protocolo', 'regime_tramitacao',
'em_tramitacao', 'ementa', 'texto_original']
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', 6)])
row4 = to_row([('ementa', 12)])
row5 = to_row([('texto_original', 12)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
_('Formulário Simplificado'),
row1, row2, row3, row4, row5,
form_actions(save_label='Salvar')
)
)
super(MateriaSimplificadaForm, self).__init__(*args, **kwargs)
class UnidadeTramitacaoForm(ModelForm):
class Meta:
model = UnidadeTramitacao
fields = ['comissao', 'orgao', 'parlamentar']
def clean(self):
cleaned_data = self.cleaned_data
for key in list(cleaned_data.keys()):
if cleaned_data[key] is None:
del cleaned_data[key]
if len(cleaned_data) != 1:
msg = _('Somente um campo deve preenchido!')
raise ValidationError(msg)
return cleaned_data
class AcompanhamentoMateriaForm(ModelForm):
class Meta:
model = AcompanhamentoMateria
fields = ['email']
def __init__(self, *args, **kwargs):
row1 = to_row([('email', 10)])
row1.append(
Column(form_actions(save_label='Cadastrar'), css_class='col-md-2')
)
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
_('Acompanhamento de Matéria por e-mail'), row1
)
)
super(AcompanhamentoMateriaForm, self).__init__(*args, **kwargs)
class DocumentoAcessorioForm(ModelForm):
class Meta:
model = DocumentoAcessorio
fields = ['tipo', 'nome', 'data', 'autor', 'ementa', 'arquivo']
widgets = {'autor': forms.HiddenInput()}
def clean_autor(self):
autor_field = self.cleaned_data['autor']
try:
int(autor_field)
except ValueError:
return autor_field
else:
if autor_field:
return str(Autor.objects.get(id=autor_field))
class RelatoriaForm(ModelForm):
class Meta:
model = Relatoria
fields = ['data_designacao_relator', 'comissao', 'parlamentar',
'data_destituicao_relator', 'tipo_fim_relatoria']
widgets = {'comissao': forms.Select(attrs={'disabled': 'disabled'})}
def __init__(self, *args, **kwargs):
super(RelatoriaForm, self).__init__(*args, **kwargs)
self.fields['parlamentar'].queryset = Parlamentar.objects.filter(
ativo=True).order_by('nome_completo')
def clean(self):
cleaned_data = self.cleaned_data
try:
comissao = Comissao.objects.get(id=self.initial['comissao'])
except ObjectDoesNotExist:
msg = _('A localização atual deve ser uma comissão.')
raise ValidationError(msg)
else:
cleaned_data['comissao'] = comissao
return cleaned_data
class TramitacaoForm(ModelForm):
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'turno',
'urgente',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto']
def __init__(self, *args, **kwargs):
super(TramitacaoForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = datetime.now()
def clean(self):
if 'data_encaminhamento' in self.data:
data_enc_form = self.cleaned_data['data_encaminhamento']
if 'data_fim_prazo' in self.data:
data_prazo_form = self.cleaned_data['data_fim_prazo']
if 'data_tramitacao' in self.data:
data_tram_form = self.cleaned_data['data_tramitacao']
if self.errors:
return self.errors
ultima_tramitacao = Tramitacao.objects.filter(
materia_id=self.instance.materia_id).exclude(
id=self.instance.id).last()
if not self.instance.data_tramitacao:
if ultima_tramitacao:
destino = ultima_tramitacao.unidade_tramitacao_destino
if (destino != self.cleaned_data['unidade_tramitacao_local']):
msg = _('A origem da nova tramitação deve ser igual ao '
'destino da última adicionada!')
raise ValidationError(msg)
if self.cleaned_data['data_tramitacao'] > datetime.now().date():
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!')
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!')
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!')
raise ValidationError(msg)
return self.cleaned_data
class TramitacaoUpdateForm(TramitacaoForm):
unidade_tramitacao_local = forms.ModelChoiceField(
queryset=UnidadeTramitacao.objects.all(),
widget=forms.HiddenInput())
data_tramitacao = forms.DateField(widget=forms.HiddenInput())
class Meta:
model = Tramitacao
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'turno',
'urgente',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto',
]
widgets = {
'data_encaminhamento': forms.DateInput(format='%d/%m/%Y'),
'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'),
}
def clean(self):
local = self.instance.unidade_tramitacao_local
data_tram = self.instance.data_tramitacao
self.cleaned_data['data_tramitacao'] = data_tram
self.cleaned_data['unidade_tramitacao_local'] = local
return super(TramitacaoUpdateForm, self).clean()
class LegislacaoCitadaForm(ModelForm):
tipo = forms.ModelChoiceField(
label=_('Tipo Norma'),
required=True,
queryset=TipoNormaJuridica.objects.all(),
empty_label='Selecione',
)
numero = forms.CharField(label='Número', required=True)
ano = forms.CharField(label='Ano', required=True)
class Meta:
model = LegislacaoCitada
fields = ['tipo',
'numero',
'ano',
'disposicoes',
'parte',
'livro',
'titulo',
'capitulo',
'secao',
'subsecao',
'artigo',
'paragrafo',
'inciso',
'alinea',
'item']
def clean(self):
if self.errors:
return self.errors
cleaned_data = self.cleaned_data
try:
norma = NormaJuridica.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
msg = _('A norma a ser inclusa não existe no cadastro'
' de Normas.')
raise ValidationError(msg)
else:
cleaned_data['norma'] = norma
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.')
raise ValidationError(msg)
else:
if filtro_base.exclude(id=self.instance.id).exists():
msg = _('Essa Legislação já foi cadastrada.')
raise ValidationError(msg)
return cleaned_data
def save(self, commit=False):
legislacao = super(LegislacaoCitadaForm, self).save(commit)
legislacao.norma = self.cleaned_data['norma']
legislacao.save()
return legislacao
class NumeracaoForm(ModelForm):
class Meta:
model = Numeracao
fields = ['tipo_materia',
'numero_materia',
'ano_materia',
'data_materia']
def clean(self):
if self.errors:
return self.errors
try:
MateriaLegislativa.objects.get(
numero=self.cleaned_data['numero_materia'],
ano=self.cleaned_data['ano_materia'],
tipo=self.cleaned_data['tipo_materia'])
except ObjectDoesNotExist:
msg = _('A matéria a ser inclusa não existe no cadastro'
' de matérias legislativas.')
raise ValidationError(msg)
if Numeracao.objects.filter(
materia=self.instance.materia,
tipo_materia=self.cleaned_data['tipo_materia'],
ano_materia=self.cleaned_data['ano_materia'],
numero_materia=self.cleaned_data['numero_materia']
).exists():
msg = _('Essa numeração já foi cadastrada.')
raise ValidationError(msg)
return self.cleaned_data
class AnexadaForm(ModelForm):
tipo = forms.ModelChoiceField(
label='Tipo',
required=True,
queryset=TipoMateriaLegislativa.objects.all(),
empty_label='Selecione',
)
numero = forms.CharField(label='Número', required=True)
ano = forms.CharField(label='Ano', required=True)
def __init__(self, *args, **kwargs):
return super(AnexadaForm, self).__init__(*args, **kwargs)
def clean(self):
if self.errors:
return self.errors
cleaned_data = self.cleaned_data
try:
materia_anexada = MateriaLegislativa.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
msg = _('A matéria a ser anexada não existe no cadastro'
' de matérias legislativas.')
raise ValidationError(msg)
else:
cleaned_data['materia_anexada'] = materia_anexada
return cleaned_data
def save(self, commit=False):
anexada = super(AnexadaForm, self).save(commit)
anexada.materia_anexada = self.cleaned_data['materia_anexada']
anexada.save()
return anexada
class Meta:
model = Anexada
fields = ['tipo', 'numero', 'ano', 'data_anexacao', 'data_desanexacao']
class MateriaLegislativaFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
ano = django_filters.ChoiceFilter(required=False,
label=u'Ano da Matéria',
choices=ANO_CHOICES)
autoria__autor = django_filters.CharFilter(widget=forms.HiddenInput())
ementa = django_filters.CharFilter(lookup_expr='icontains')
em_tramitacao = django_filters.ChoiceFilter(required=False,
label=u'Ano da Matéria',
choices=em_tramitacao)
o = MateriaPesquisaOrderingFilter()
class Meta:
model = MateriaLegislativa
fields = ['numero',
'numero_protocolo',
'ano',
'tipo',
'data_apresentacao',
'data_publicacao',
'autoria__autor__tipo',
# FIXME 'autoria__autor__partido',
'relatoria__parlamentar_id',
'local_origem_externa',
'tramitacao__unidade_tramitacao_destino',
'tramitacao__status',
'em_tramitacao',
]
def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['autoria__autor__tipo'].label = 'Tipo de Autor'
# self.filters['autoria__autor__partido'].label = 'Partido do Autor'
self.filters['relatoria__parlamentar_id'].label = 'Relatoria'
row1 = to_row(
[('tipo', 12)])
row2 = to_row(
[('numero', 4),
('ano', 4),
('numero_protocolo', 4)])
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'), 10)])
row5 = to_row(
[('autoria__autor__tipo', 12),
# ('autoria__autor__partido', 6)
])
row6 = to_row(
[('relatoria__parlamentar_id', 6),
('local_origem_externa', 6)])
row7 = to_row(
[('tramitacao__unidade_tramitacao_destino', 6),
('tramitacao__status', 6)])
row8 = to_row(
[('em_tramitacao', 6),
('o', 6)])
row9 = to_row(
[('ementa', 12)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Matéria'),
row1, row2, row3,
HTML(autor_label),
HTML(autor_modal),
row4, row5, row6, row7, row8, row9,
form_actions(save_label='Pesquisar'))
)
def pega_ultima_tramitacao():
ultimas_tramitacoes = Tramitacao.objects.values(
'materia_id').annotate(data_encaminhamento=Max(
'data_encaminhamento'),
id=Max('id')).values_list('id')
lista = [item for sublist in ultimas_tramitacoes for item in sublist]
return lista
def filtra_tramitacao_status(status):
lista = pega_ultima_tramitacao()
return Tramitacao.objects.filter(
id__in=lista,
status=status).distinct().values_list('materia_id', flat=True)
def filtra_tramitacao_destino(destino):
lista = pega_ultima_tramitacao()
return Tramitacao.objects.filter(
id__in=lista,
unidade_tramitacao_destino=destino).distinct().values_list(
'materia_id', flat=True)
def filtra_tramitacao_destino_and_status(status, destino):
lista = pega_ultima_tramitacao()
return Tramitacao.objects.filter(
id__in=lista,
status=status,
unidade_tramitacao_destino=destino).distinct().values_list(
'materia_id', flat=True)
class DespachoInicialForm(ModelForm):
class Meta:
model = DespachoInicial
fields = ['comissao']
def clean(self):
if self.errors:
return self.errors
if DespachoInicial.objects.filter(
materia=self.instance.materia,
comissao=self.cleaned_data['comissao'],
).exists():
msg = _('Esse Despacho já foi cadastrado.')
raise ValidationError(msg)
return self.cleaned_data
class AutoriaForm(ModelForm):
class Meta:
model = Autoria
fields = ['autor', 'primeiro_autor']
def clean(self):
if self.errors:
return self.errors
if Autoria.objects.filter(
materia=self.instance.materia,
autor=self.cleaned_data['autor'],
).exists():
msg = _('Esse Autor já foi cadastrado.')
raise ValidationError(msg)
return self.cleaned_data
class AcessorioEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta:
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 = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Documentos Acessórios em Lote'),
row1, row2, form_actions(save_label='Pesquisar')))
class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta:
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 = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Primeira Tramitação'),
row1, row2, form_actions(save_label='Pesquisar')))
class TramitacaoEmLoteFilterSet(django_filters.FilterSet):
filter_overrides = {models.DateField: {
'filter_class': django_filters.DateFromToRangeFilter,
'extra': lambda f: {
'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')),
'widget': RangeWidgetOverride}
}}
class Meta:
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.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = True
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 = FormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Tramitação em Lote'),
row1, row2, form_actions(save_label='Pesquisar')))
class TipoProposicaoForm(ModelForm):
content_type = forms.ModelChoiceField(
queryset=ContentType.objects.all(),
label=TipoProposicao._meta.get_field('content_type').verbose_name,
required=True)
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']
widgets = {'tipo_conteudo_related': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
tipo_select = Fieldset(TipoProposicao._meta.verbose_name,
to_column(('descricao', 5)),
to_column(('content_type', 7)),
to_column(('tipo_conteudo_related_radio', 12)))
self.helper = FormHelper()
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()]
self.fields['content_type'].choices.sort(key=lambda x: str(x[1]))
if self.instance.pk:
self.fields[
'tipo_conteudo_related'].initial = self.instance.object_id
def clean(self):
cd = self.cleaned_data
content_type = cd['content_type']
if 'tipo_conteudo_related' not in cd or not cd[
'tipo_conteudo_related']:
raise ValidationError(
_('Seleção de Tipo não definida'))
if not content_type.model_class().objects.filter(
pk=cd['tipo_conteudo_related']).exists():
raise ValidationError(
_('O Registro definido (%s) não está na base de %s.'
) % (cd['tipo_conteudo_related'], cd['q'], content_type))
return self.cleaned_data
@transaction.atomic
def save(self, commit=False):
tipo_proposicao = super(TipoProposicaoForm, self).save(commit)
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'])
tipo_proposicao.save()
return tipo_proposicao
class ProposicaoForm(forms.ModelForm):
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.MultipleChoiceField(
label=_('Tipo do Texto da Proposição'),
required=False,
choices=TIPO_TEXTO_CHOICE,
widget=widgets.CheckboxSelectMultiple())
materia_de_vinculo = forms.ModelChoiceField(
queryset=MateriaLegislativa.objects.all(),
widget=widgets.HiddenInput(),
required=False)
class Meta:
model = Proposicao
fields = ['tipo',
'descricao',
'texto_original',
'materia_de_vinculo',
'tipo_materia',
'numero_materia',
'ano_materia',
'tipo_texto']
widgets = {
'descricao': widgets.Textarea(attrs={'rows': 4})}
def __init__(self, *args, **kwargs):
self.texto_articulado_proposicao = sapl.base.models.AppConfig.attr(
'texto_articulado_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')), 3)),
Fieldset(_('Vincular a Matéria Legislativa Existente'),
to_column(('tipo_materia', 4)),
to_column(('numero_materia', 4)),
to_column(('ano_materia', 4))
),
to_column(
(Alert('teste',
css_class="ementa_materia hidden alert-info",
dismiss=False), 12)),
to_column(('descricao', 12)),
]
if self.texto_articulado_proposicao:
fields.append(
to_column((InlineCheckboxes('tipo_texto'), 5)),)
fields.append(to_column((
'texto_original', 7 if self.texto_articulado_proposicao else 12)))
self.helper = FormHelper()
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.append('D')
if self.texto_articulado_proposicao:
if self.instance.texto_articulado.exists():
self.fields['tipo_texto'].initial.append('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:
if texto_original.size > MAX_DOC_UPLOAD_SIZE:
raise ValidationError("Arquivo muito grande. ( > 5mb )")
return texto_original
def clean(self):
cd = self.cleaned_data
tm, am, nm = (cd.get('tipo_materia', ''),
cd.get('ano_materia', ''),
cd.get('numero_materia', ''))
if tm and am and nm:
try:
materia_de_vinculo = MateriaLegislativa.objects.get(
tipo_id=tm,
ano=am,
numero=nm
)
except ObjectDoesNotExist:
raise ValidationError(_('Matéria Vinculada não existe!'))
else:
cd['materia_de_vinculo'] = materia_de_vinculo
return cd
def save(self, commit=True):
if self.instance.pk:
return super().save(commit)
self.instance.ano = datetime.now().year
numero__max = Proposicao.objects.filter(
autor=self.instance.autor,
ano=datetime.now().year).aggregate(Max('numero_proposicao'))
numero__max = numero__max['numero_proposicao__max']
self.instance.numero_proposicao = (
numero__max + 1) if numero__max else 1
self.instance.save()
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'}))
justificativa_devolucao = forms.CharField(
required=False, widget=widgets.Textarea(attrs={'rows': 5}))
regime_tramitacao = forms.ModelChoiceField(
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',
'justificativa_devolucao',
'gerar_protocolo',
'numero_de_paginas'
]
widgets = {
'descricao': widgets.Textarea(
attrs={'readonly': 'readonly', 'rows': 4}),
'data_envio': widgets.DateTimeInput(
attrs={'readonly': 'readonly'}),
}
def __init__(self, *args, **kwargs):
self.proposicao_incorporacao_obrigatoria = \
sapl.base.models.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')
# esta chamada isola o __init__ de ProposicaoForm
super(ProposicaoForm, self).__init__(*args, **kwargs)
fields = [
Fieldset(
_('Dados Básicos'),
to_column(('tipo_readonly', 4)),
to_column(('data_envio', 3)),
to_column(('autor_readonly', 5)),
to_column(('descricao', 12)))]
fields.append(
Fieldset(_('Vinculado a Matéria Legislativa'),
to_column(('tipo_materia', 3)),
to_column(('numero_materia', 2)),
to_column(('ano_materia', 2)),
to_column(
(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)),
to_column(
(Alert('',
css_class="ementa_materia hidden alert-info",
dismiss=False), 12))))
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((FormActions(Submit(
'incorporar', _('Incorporar'), css_class='pull-right')), 12)))
fields.append(
Fieldset(_('Registro de Incorporação'), *itens_incorporacao))
fields.append(
Fieldset(
_('Registro de Devolução'),
to_column(('justificativa_devolucao', 12)),
to_column((FormActions(Submit(
'devolver', _('Devolver'),
css_class='btn-danger pull-right')), 12))
))
self.helper = FormHelper()
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.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):
if 'incorporar' in self.data:
cd = ProposicaoForm.clean(self)
if self.instance.tipo.content_type.model_class() ==\
TipoMateriaLegislativa:
if 'regime_tramitacao' not in cd or\
not cd['regime_tramitacao']:
raise ValidationError(
_('Regimente de Tramitação deve ser informado.'))
elif self.instance.tipo.content_type.model_class(
) == TipoDocumento and not cd['materia_de_vinculo']:
raise ValidationError(
_('Documentos não podem ser incorporados sem definir '
'para qual Matéria Legislativa ele se destina.'))
elif 'devolver' in self.data:
cd = self.cleaned_data
if 'justificativa_devolucao' not in cd or\
not cd['justificativa_devolucao']:
# TODO Implementar notificação ao autor por email
raise ValidationError(
_('Adicione uma Justificativa para devolução.'))
else:
raise ValidationError(
_('Dados de Confirmação invalidos.'))
return cd
@transaction.atomic
def save(self, commit=False):
# TODO Implementar workflow entre protocolo e autores
cd = self.cleaned_data
if 'devolver' in self.data:
self.instance.data_devolucao = datetime.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()
self.instance.results = {
'messages': {
'success': [_('Devolução efetuada com sucesso.'), ]
},
'url': reverse('sapl.materia:receber-proposicao')
}
return self.instance
elif 'incorporar' in self.data:
self.instance.justificativa_devolucao = ''
self.instance.data_devolucao = None
self.instance.data_recebimento = datetime.now()
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
if self.instance.tipo.content_type.model_class(
) == TipoMateriaLegislativa:
numero__max = MateriaLegislativa.objects.filter(
tipo=proposicao.tipo.tipo_conteudo_related,
ano=datetime.now().year).aggregate(Max('numero'))
numero__max = numero__max['numero__max']
# dados básicos
materia = MateriaLegislativa()
materia.numero = (numero__max + 1) if numero__max else 1
materia.tipo = proposicao.tipo.tipo_conteudo_related
materia.ementa = proposicao.descricao
materia.ano = datetime.now().year
materia.data_apresentacao = datetime.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.id = None
ta.content_object = materia
ta.save()
pass
# FIXME - gerar texto_articulado da materia com base na prop.
# materia.texto_articulo = proposicao.texto_articulado
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 = datetime.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)
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()
# 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 = sapl.base.models.AppConfig.attr('sequencia_numeracao')
if numeracao == 'A':
nm = Protocolo.objects.filter(
ano=date.today().year).aggregate(Max('numero'))
elif numeracao == 'U':
nm = Protocolo.objects.all().aggregate(Max('numero'))
protocolo = Protocolo()
protocolo.numero = (nm['numero__max'] + 1) if nm['numero__max'] else 1
protocolo.ano = date.today().year
protocolo.data = date.today()
protocolo.hora = datetime.now().time()
# TODO transformar campo timestamp em auto_now_add
protocolo.timestamp = datetime.now()
protocolo.tipo_protocolo = '1'
# 1 Processo Legislativo
# 0 Processo Administrativo
protocolo.tipo_processo = '1'
protocolo.interessado = str(proposicao.autor)
protocolo.autor = proposicao.autor
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
elif self.instance.tipo.content_type.model_class() == TipoDocumento:
protocolo.tipo_documento = proposicao.tipo.tipo_conteudo_related
protocolo.save()
self.instance.results['messages']['success'].append(_(
'Protocolo realizado com sucesso'))
# FIXME qdo protocoloadm estiver homologado, verifique a necessidade
# de redirecionamento para o protocolo.
"""
self.instance.results['url'] = reverse(
'sapl.protocoloadm:...',
kwargs={'pk': protocolo.pk})
"""
conteudo_gerado.numero_protocolo = protocolo.numero
conteudo_gerado.save()
return self.instance