import logging import os from crispy_forms.bootstrap import Alert, InlineRadios from crispy_forms.layout import (Button, Field, Fieldset, HTML, Layout, Row, Div) 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 as BaseAppConfig, 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, get_client_ip) from sapl.utils_template import adicionar_cabecalho_materia 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') # Quando criando via OnlyOffice, arquivo não é obrigatório if self.data.get('action') == 'onlyoffice': if arquivo: validar_arquivo(arquivo, "Texto Integral") return self.cleaned_data if arquivo: validar_arquivo(arquivo, "Texto Integral") else: 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 and BaseAppConfig.attr('tramitacao_origem_fixa'): 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 = BaseAppConfig.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 and BaseAppConfig.attr('tramitacao_origem_fixa'): 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 = BaseAppConfig.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', 'regime_tramitacao', ] 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', 4), ('indexacao', 4), ('regime_tramitacao', 4)]) 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( Div( Fieldset(_('Pesquisa Básica'), row1, row2, HTML(autor_label), HTML(autor_modal), row4, ), Button('btn_pesquisa_avancada', 'Pesquisa Avançada >>>', css_id='btn_pesquisa_avancada_id', css_class='btn btn-dark', onClick="pesquisaAvancada()", style='margin-bottom: 2vh;font-weight: bold' ), Fieldset(_('Como listar os resultados da pesquisa'), row8, css_class='pesquisa_avancada', style='display: none;', ), Fieldset(_('Origem externa'), row10, row11, css_class='pesquisa_avancada', style='display: none;', ), Fieldset(_('Mais Opções de Pesquisa...'), row3, row6, row7, row9, css_class='pesquisa_avancada', style='display: none;' ), 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): try: content_types_choices = [ ( f'{ct.app_label}/{ct.model}', ct ) for k, ct in ContentType.objects.get_for_models( *models_with_gr_for_model(TipoProposicao) ).items() ] except: content_types_choices = [] logger = logging.getLogger(__name__) content_type = forms.ChoiceField( choices=content_types_choices, 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( ( Div( Row( to_column(('content_type', 10)), to_column(( HTML('''
'''), 2 )), ), Row( 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) 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'].split('/') content_type = ContentType.objects.filter( app_label=content_type[0], model=content_type[1]).first() cd['content_type'] = content_type if not content_type: self.logger.error("Meta Tipo Inexistente") raise ValidationError( _('Meta Tipo Inexistente.')) 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 = r'''