import logging import re from crispy_forms.bootstrap import InlineRadios, Alert, FormActions from crispy_forms.layout import (Button, Div, Fieldset, HTML, Layout, Submit) from django import forms from django.core.exceptions import (MultipleObjectsReturned, ObjectDoesNotExist, ValidationError) from django.db import transaction from django.db.models import Max from django.forms import ModelForm from django.utils import timezone from django.utils.translation import ugettext_lazy as _ import django_filters from sapl.base.models import Autor, TipoAutor, AppConfig from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper, SaplFormLayout, to_row) from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) from sapl.protocoloadm.models import VinculoDocAdminMateria from sapl.utils import (AnoNumeroOrderingFilter, autor_label, autor_modal, choice_anos_com_documentoadministrativo, choice_anos_com_materias, timing, choice_anos_com_protocolo, choice_force_optional, FileFieldCheckMixin, FilterOverridesMetaMixin, lista_anexados, RANGE_ANOS, validar_arquivo, YES_NO_CHOICES, GoogleRecapthaMixin) from .models import (Anexado, AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, Protocolo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) TIPOS_PROTOCOLO = [('0', 'Recebido'), ('1', 'Enviado'), ('2', 'Interno')] TIPOS_PROTOCOLO_CREATE = [ ('0', 'Recebido'), ('1', 'Enviado'), ('2', 'Interno')] NATUREZA_PROCESSO = [('0', 'Administrativo'), ('1', 'Legislativo')] EM_TRAMITACAO = [(0, 'Sim'), (1, 'Não')] class AcompanhamentoDocumentoForm(GoogleRecapthaMixin, ModelForm): class Meta: model = AcompanhamentoDocumento fields = ['email'] def __init__(self, *args, **kwargs): kwargs['title_label'] = _('Acompanhamento de Documento por e-mail') kwargs['action_label'] = _('Cadastrar') super().__init__(*args, **kwargs) class ProtocoloFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter( required=False, label='Ano', choices=choice_anos_com_protocolo) assunto_ementa = django_filters.CharFilter( label=_('Assunto'), lookup_expr='icontains') interessado = django_filters.CharFilter( label=_('Interessado'), lookup_expr='icontains') autor = django_filters.CharFilter(widget=forms.HiddenInput()) tipo_protocolo = django_filters.ChoiceFilter( required=False, label='Tipo de Protocolo', choices=TIPOS_PROTOCOLO, widget=forms.Select( attrs={'class': 'selector'})) tipo_processo = django_filters.ChoiceFilter( required=False, label='Natureza do Processo', choices=NATUREZA_PROCESSO, widget=forms.Select( attrs={'class': 'selector'})) o = AnoNumeroOrderingFilter(help_text='') class Meta(FilterOverridesMetaMixin): model = Protocolo fields = ['numero', 'tipo_documento', 'timestamp', 'tipo_materia', ] def __init__(self, *args, **kwargs): super(ProtocoloFilterSet, self).__init__(*args, **kwargs) self.filters['timestamp'].label = 'Data (Inicial - Final)' row1 = to_row( [('numero', 4), ('ano', 4), ('timestamp', 4)]) row2 = to_row( [('tipo_documento', 4), ('tipo_protocolo', 4), ('tipo_materia', 4)]) row3 = to_row( [('interessado', 6), ('assunto_ementa', 6)]) row4 = to_row( [('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( [('tipo_processo', 6), ('o', 6)]) self.form.helper = SaplFormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Pesquisar Protocolo'), row1, row2, row3, row5, HTML(autor_label), HTML(autor_modal), row4, form_actions(label='Pesquisar')) ) class DocumentoAdministrativoFilterSet(django_filters.FilterSet): ano = django_filters.ChoiceFilter( required=False, label='Ano', choices=choice_anos_com_documentoadministrativo) tramitacao = django_filters.ChoiceFilter(required=False, label='Em Tramitação?', choices=YES_NO_CHOICES) assunto = django_filters.CharFilter( label=_('Assunto'), lookup_expr='icontains') interessado = django_filters.CharFilter( label=_('Interessado'), lookup_expr='icontains') o = AnoNumeroOrderingFilter(help_text='') class Meta(FilterOverridesMetaMixin): model = DocumentoAdministrativo fields = ['tipo', 'numero', 'complemento', 'protocolo__numero', 'numero_externo', 'data', 'tramitacaoadministrativo__unidade_tramitacao_destino', 'tramitacaoadministrativo__status'] def __init__(self, *args, **kwargs): super(DocumentoAdministrativoFilterSet, self).__init__(*args, **kwargs) local_atual = 'tramitacaoadministrativo__unidade_tramitacao_destino' self.filters['tipo'].label = 'Tipo de Documento' self.filters['protocolo__numero'].label = 'Núm. Protocolo' self.filters['tramitacaoadministrativo__status'].label = 'Situação' self.filters[local_atual].label = 'Localização Atual' row1 = to_row( [('tipo', 8), ('o', 4), ]) row2 = to_row( [('numero', 5), ('complemento', 2), ('ano', 5)]) row3 = to_row( [('protocolo__numero', 4), ('numero_externo', 4), ('data', 4) ]) row4 = to_row( [('interessado', 6), ('assunto', 6)]) row5 = to_row( [ ('tramitacao', 2), ('tramitacaoadministrativo__status', 4), ('tramitacaoadministrativo__unidade_tramitacao_destino', 6), ]) buttons = FormActions( *[ HTML('''
''') ], Submit('pesquisar', _('Pesquisar'), css_class='float-right', onclick='return true;'), css_class='form-group row justify-content-between', ) self.form.helper = SaplFormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Pesquisar Documento'), row1, row2, row3, row4, row5, buttons,) ) class AnularProtocoloAdmForm(ModelForm): logger = logging.getLogger(__name__) numero = forms.CharField(required=True, label=Protocolo._meta. get_field('numero').verbose_name ) ano = forms.ChoiceField(required=True, label=Protocolo._meta. get_field('ano').verbose_name, choices=RANGE_ANOS, widget=forms.Select(attrs={'class': 'selector'})) justificativa_anulacao = forms.CharField( required=True, label=Protocolo._meta.get_field('justificativa_anulacao').verbose_name, widget=forms.Textarea) def clean(self): super(AnularProtocoloAdmForm, self).clean() cleaned_data = self.cleaned_data if not self.is_valid(): return cleaned_data numero = cleaned_data['numero'] ano = cleaned_data['ano'] try: self.logger.debug( "Tentando obter Protocolo com numero={} e ano={}.".format(numero, ano)) protocolo = Protocolo.objects.get(numero=numero, ano=ano) if protocolo.anulado: self.logger.error( "Protocolo %s/%s já encontra-se anulado" % (numero, ano)) raise forms.ValidationError( _("Protocolo %s/%s já encontra-se anulado") % (numero, ano)) except ObjectDoesNotExist: self.logger.error("Protocolo %s/%s não existe" % (numero, ano)) raise forms.ValidationError( _("Protocolo %s/%s não existe" % (numero, ano))) exists = False if protocolo.tipo_materia: exists = MateriaLegislativa.objects.filter( numero_protocolo=protocolo.numero, ano=protocolo.ano).exists() elif protocolo.tipo_documento: exists = protocolo.documentoadministrativo_set.all( ).order_by('-ano', '-numero').exists() if exists: self.logger.error("Protocolo %s/%s não pode ser removido pois existem " "documentos vinculados a ele." % (numero, ano)) raise forms.ValidationError( _("Protocolo %s/%s não pode ser removido pois existem " "documentos vinculados a ele." % (numero, ano))) return cleaned_data class Meta: model = Protocolo fields = ['justificativa_anulacao', 'anulado', 'user_anulacao', 'ip_anulacao', ] widgets = {'anulado': forms.HiddenInput(), 'user_anulacao': forms.HiddenInput(), 'ip_anulacao': forms.HiddenInput(), } def __init__(self, *args, **kwargs): row1 = to_row( [('numero', 6), ('ano', 6)]) row2 = to_row( [('justificativa_anulacao', 12)]) self.helper = SaplFormHelper() self.helper.layout = Layout( Fieldset(_('Identificação do Protocolo'), row1, row2, HTML(" "), form_actions(label='Anular') ) ) super(AnularProtocoloAdmForm, self).__init__( *args, **kwargs) class ProtocoloDocumentoForm(ModelForm): tipo_protocolo = forms.ChoiceField(required=True, label=_('Tipo de Protocolo'), choices=TIPOS_PROTOCOLO_CREATE, initial=0,) tipo_documento = forms.ModelChoiceField( label=_('Tipo de Documento'), required=True, queryset=TipoDocumentoAdministrativo.objects.all(), empty_label='Selecione', ) numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True) assunto = forms.CharField( widget=forms.Textarea, label=_('Assunto'), required=True) interessado = forms.CharField(required=True, label=_('Interessado')) observacao = forms.CharField(required=False, widget=forms.Textarea, label=_('Observação')) data_hora_manual = forms.ChoiceField( label=_('Informar data e hora manualmente?'), widget=forms.RadioSelect(), choices=YES_NO_CHOICES, initial=False) class Meta: model = Protocolo fields = ['tipo_protocolo', 'tipo_documento', 'numero_paginas', 'assunto', 'interessado', 'observacao', 'data', 'hora', ] def __init__(self, *args, **kwargs): row1 = to_row( [(InlineRadios('tipo_protocolo'), 12)]) row2 = to_row( [('tipo_documento', 5), ('numero_paginas', 2), (Div(), 1), (InlineRadios('data_hora_manual'), 4), ]) row3 = to_row([ (Div(), 2), (Alert( """ Usuário: {} - {}
IP: {} - {}
""".format( kwargs['initial']['user_data_hora_manual'], Protocolo._meta.get_field( 'user_data_hora_manual').help_text, kwargs['initial']['ip_data_hora_manual'], Protocolo._meta.get_field( 'ip_data_hora_manual').help_text, ), dismiss=False, css_class='alert-info'), 6), ('data', 2), ('hora', 2), ]) row4 = to_row( [('assunto', 12)]) row5 = to_row( [('interessado', 12)]) row6 = to_row( [('observacao', 12)]) fieldset = Fieldset(_('Protocolo com data e hora informados manualmente'), row3, css_id='protocolo_data_hora_manual') config = AppConfig.objects.first() if not config.protocolo_manual: row3 = to_row([(HTML(" "), 12)]) fieldset = row3 self.helper = SaplFormHelper() self.helper.layout = Layout( Fieldset(_('Identificação de Documento'), row1, row2), fieldset, row4, row5, HTML(" "), Fieldset(HTML(" "), form_actions(label=_('Protocolar Documento')) ) ) super(ProtocoloDocumentoForm, self).__init__( *args, **kwargs) if not config.protocolo_manual: self.fields['data_hora_manual'].widget = forms.HiddenInput() class ProtocoloMateriaForm(ModelForm): logger = logging.getLogger(__name__) autor = forms.ModelChoiceField(required=True, empty_label='------', queryset=Autor.objects.all() ) tipo_autor = forms.ModelChoiceField(required=True, empty_label='------', queryset=TipoAutor.objects.all() ) tipo_materia = forms.ModelChoiceField( label=_('Tipo de Matéria'), required=True, queryset=TipoMateriaLegislativa.objects.all(), empty_label='------', ) numero_materia = forms.CharField( label=_('Número matéria'), required=False) ano_materia = forms.CharField( label=_('Ano matéria'), required=False) vincular_materia = forms.ChoiceField( label=_('Vincular a matéria existente?'), widget=forms.RadioSelect(), choices=YES_NO_CHOICES, initial=False) numero_paginas = forms.CharField(label=_('Núm. Páginas'), required=True) observacao = forms.CharField(required=False, widget=forms.Textarea, label=_('Observação')) assunto_ementa = forms.CharField(required=True, widget=forms.Textarea, label=_('Ementa')) data_hora_manual = forms.ChoiceField( label=_('Informar data e hora manualmente?'), widget=forms.RadioSelect(), choices=YES_NO_CHOICES, initial=False) class Meta: model = Protocolo fields = ['tipo_materia', 'numero_paginas', 'autor', 'tipo_autor', 'assunto_ementa', 'observacao', 'numero_materia', 'ano_materia', 'vincular_materia', 'data', 'hora', ] def clean_autor(self): autor_field = self.cleaned_data['autor'] try: self.logger.debug( "Tentando obter Autor com id={}.".format(autor_field.id)) autor = Autor.objects.get(id=autor_field.id) except ObjectDoesNotExist: self.logger.error( "Autor com id={} não encontrado. Definido como None.".format(autor_field.id)) autor_field = None else: self.logger.info( "Autor com id={} encontrado com sucesso.".format(autor_field.id)) autor_field = autor return autor_field def clean(self): super(ProtocoloMateriaForm, self).clean() if not self.is_valid(): return self.cleaned_data data = self.cleaned_data if self.is_valid(): if data['vincular_materia'] == 'True': try: if not data['ano_materia'] or not data['numero_materia']: self.logger.error( "Não foram informados o número ou ano da matéria a ser vinculada") raise ValidationError( 'Favor informar o número e ano da matéria a ser vinculada') self.logger.debug("Tentando obter MateriaLegislativa com ano={}, numero={} e data={}." .format(data['ano_materia'], data['numero_materia'], data['tipo_materia'])) self.materia = MateriaLegislativa.objects.get(ano=data['ano_materia'], numero=data['numero_materia'], tipo=data['tipo_materia']) if self.materia.numero_protocolo: self.logger.error("MateriaLegislativa informada já possui o protocolo {}/{} vinculado." .format(self.materia.numero_protocolo, self.materia.ano)) raise ValidationError(_('Matéria Legislativa informada já possui o protocolo {}/{} vinculado.' .format(self.materia.numero_protocolo, self.materia.ano))) except ObjectDoesNotExist: self.logger.error("MateriaLegislativa informada (ano={}, numero={} e data={}) não existente." .format(data['ano_materia'], data['numero_materia'], data['tipo_materia'])) raise ValidationError( _('Matéria Legislativa informada não existente.')) return data def __init__(self, *args, **kwargs): row1 = to_row( [('tipo_materia', 4), ('numero_paginas', 2), ('tipo_autor', 3), ('autor', 3)]) row2 = to_row( [(InlineRadios('vincular_materia'), 3), ('numero_materia', 2), ('ano_materia', 2), (Div(), 1), (InlineRadios('data_hora_manual'), 4), ]) row3 = to_row([ (Div(), 2), (Alert( """ Usuário: {} - {}
IP: {} - {}
""".format( kwargs['initial']['user_data_hora_manual'], Protocolo._meta.get_field( 'user_data_hora_manual').help_text, kwargs['initial']['ip_data_hora_manual'], Protocolo._meta.get_field( 'ip_data_hora_manual').help_text, ), dismiss=False, css_class='alert-info'), 6), ('data', 2), ('hora', 2), ]) row4 = to_row( [('assunto_ementa', 12)]) row5 = to_row( [('observacao', 12)]) fieldset = Fieldset(_('Protocolo com data e hora informados manualmente'), row3, css_id='protocolo_data_hora_manual') config = AppConfig.objects.first() if not config.protocolo_manual: row3 = to_row([(HTML(" "), 12)]) fieldset = row3 self.helper = SaplFormHelper() self.helper.layout = Layout( Fieldset(_('Identificação da Matéria'), row1, row2), fieldset, row4, row5, HTML(" "), Fieldset(HTML(" "), form_actions(label=_('Protocolar Matéria'))) ) super(ProtocoloMateriaForm, self).__init__( *args, **kwargs) if not config.protocolo_manual: self.fields['data_hora_manual'].widget = forms.HiddenInput() class DocumentoAcessorioAdministrativoForm(FileFieldCheckMixin, ModelForm): restrito = forms.ChoiceField( label=_('Documento Restrito?'), widget=forms.RadioSelect(), choices=YES_NO_CHOICES, initial=False) class Meta: model = DocumentoAcessorioAdministrativo fields = ['tipo', 'nome', 'restrito', 'data', 'autor', 'arquivo', 'assunto', 'justificativa_restricao'] widgets = { 'data': forms.DateInput(format='%d/%m/%Y') } def clean(self): super(DocumentoAcessorioAdministrativoForm, self).clean() if not self.is_valid(): return self.cleaned_data arquivo = self.cleaned_data.get('arquivo') if arquivo: validar_arquivo(arquivo, "Arquivo") # 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 TramitacaoAdmForm(ModelForm): logger = logging.getLogger(__name__) class Meta: model = TramitacaoAdministrativo fields = ['data_tramitacao', 'unidade_tramitacao_local', 'status', '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(TramitacaoAdmForm, 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? *" def clean(self): cleaned_data = super(TramitacaoAdmForm, 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.is_valid(): return cleaned_data ultima_tramitacao = TramitacaoAdministrativo.objects.filter( documento_id=self.instance.documento_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 ({}) deve ser ' '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 self.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(self.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 (ultima_tramitacao and data_tram_form < ultima_tramitacao.data_tramitacao): 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)) 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: self.logger.error('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 self.cleaned_data @timing @transaction.atomic def save(self, commit=True): tramitacao = super(TramitacaoAdmForm, self).save(commit) documento = tramitacao.documento documento.tramitacao = False if tramitacao.status.indicador == "F" else True documento.save() tramitar_anexados = AppConfig.attr('tramitacao_documento') if tramitar_anexados: lista_tramitacao = [] anexados_list = lista_anexados(documento) for da in anexados_list: if not da.tramitacaoadministrativo_set.all() \ or da.tramitacaoadministrativo_set.last() \ .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: da.tramitacao = False if tramitacao.status.indicador == "F" else True da.save() lista_tramitacao.append(TramitacaoAdministrativo( status=tramitacao.status, documento=da, 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, 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 TramitacaoAdministrativo.objects.bulk_create(lista_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_doc(tramitacao1, tramitacao2): if not tramitacao1 or not tramitacao2: return False lst_items = ['id', 'documento_id', 'timestamp', 'ultima_edicao'] 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 TramitacaoAdmEditForm(TramitacaoAdmForm): 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 = TramitacaoAdministrativo fields = ['data_tramitacao', 'unidade_tramitacao_local', 'status', '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 clean(self): super(TramitacaoAdmEditForm, self).clean() if not self.is_valid(): return self.cleaned_data cd = self.cleaned_data obj = self.instance ultima_tramitacao = TramitacaoAdministrativo.objects.filter( documento_id=obj.documento_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 (id={}), pois irá conflitar com a Unidade ' 'Local da tramitação seguinte'.format(obj.documento_id)) 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') # Se não houve qualquer alteração em um dos dados, mantém o usuário e # ip 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): 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 = TramitacaoAdministrativo.objects.get( id=self.instance.id) nova_tram_principal = super(TramitacaoAdmEditForm, self).save(commit) documento = nova_tram_principal.documento documento.tramitacao = False if nova_tram_principal.status.indicador == "F" else True documento.save() tramitar_anexados = AppConfig.attr('tramitacao_documento') if tramitar_anexados: anexados_list = lista_anexados(documento) for da in anexados_list: tram_anexada = da.tramitacaoadministrativo_set.last() if compara_tramitacoes_doc(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.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() da.tramitacao = False if nova_tram_principal.status.indicador == "F" else True da.save() # TODO: refatorar? return nova_tram_principal class AnexadoForm(ModelForm): logger = logging.getLogger(__name__) tipo = forms.ModelChoiceField( label='Tipo', required=True, queryset=TipoDocumentoAdministrativo.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(AnexadoForm, self).__init__(*args, **kwargs) def clean(self): super(AnexadoForm, 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 DocumentoAdministrativo (numero={}, ano={}, tipo={})." .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']) ) documento_anexado = DocumentoAdministrativo.objects.get( numero=cleaned_data['numero'], ano=cleaned_data['ano'], tipo=cleaned_data['tipo'] ) except ObjectDoesNotExist: msg = _('O {} {}/{} não existe no cadastro de documentos administrativos.' .format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano'])) self.logger.error("O documento a ser anexado não existe no cadastro" " de documentos administrativos") raise ValidationError(msg) documento_principal = self.instance.documento_principal if documento_principal == documento_anexado: self.logger.error("O documento não pode ser anexado a si mesmo.") raise ValidationError( _("O documento não pode ser anexado a si mesmo")) is_anexado = Anexado.objects.filter(documento_principal=documento_principal, documento_anexado=documento_anexado ).exclude(pk=self.instance.pk).exists() if is_anexado: self.logger.error("Documento já se encontra anexado.") raise ValidationError(_('Documento já se encontra anexado')) ciclico = False anexados_anexado = Anexado.objects.filter( documento_principal=documento_anexado) while(anexados_anexado and not ciclico): anexados = [] for anexo in anexados_anexado: if documento_principal == anexo.documento_anexado: ciclico = True else: for a in Anexado.objects.filter(documento_principal=anexo.documento_anexado): anexados.append(a) anexados_anexado = anexados if ciclico: self.logger.error( "O documento não pode ser anexado por um de seus anexados.") raise ValidationError( _('O documento não pode ser anexado por um de seus anexados')) cleaned_data['documento_anexado'] = documento_anexado return cleaned_data def save(self, commit=False): anexado = super(AnexadoForm, self).save(commit) anexado.documento_anexado = self.cleaned_data['documento_anexado'] anexado.save() return anexado class Meta: model = Anexado fields = ['tipo', 'numero', 'ano', 'data_anexacao', 'data_desanexacao'] class AnexadoEmLoteFilterSet(django_filters.FilterSet): class Meta(FilterOverridesMetaMixin): model = DocumentoAdministrativo fields = ['tipo', 'data'] def __init__(self, *args, **kwargs): super(AnexadoEmLoteFilterSet, self).__init__(*args, **kwargs) self.filters['tipo'].label = 'Tipo de Documento*' self.filters['data'].label = 'Data (Inicial - Final)*' row1 = to_row([('tipo', 12)]) row2 = to_row([('data', 12)]) self.form.helper = SaplFormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Pesquisa de Documentos'), row1, row2, form_actions(label='Pesquisar')) ) class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm): logger = logging.getLogger(__name__) data = forms.DateField(initial=timezone.now) ano_protocolo = forms.ChoiceField( required=False, label=Protocolo._meta. get_field('ano').verbose_name, choices=choice_force_optional(choice_anos_com_protocolo), widget=forms.Select( attrs={'class': 'selector'})) numero_protocolo = forms.IntegerField(required=False, label=Protocolo._meta. get_field('numero').verbose_name) restrito = forms.ChoiceField(label=_('Acesso Restrito'), widget=forms.RadioSelect(), choices=YES_NO_CHOICES, initial=False) class Meta: model = DocumentoAdministrativo fields = ['tipo', 'numero', 'complemento', 'ano', 'data', 'numero_protocolo', 'ano_protocolo', 'assunto', 'interessado', 'tramitacao', 'dias_prazo', 'data_fim_prazo', 'numero_externo', 'observacao', 'texto_integral', 'protocolo', 'restrito', 'user', 'ip', 'ultima_edicao', 'autor' ] widgets = {'protocolo': forms.HiddenInput(), 'user': forms.HiddenInput(), 'ip': forms.HiddenInput(), 'ultima_edicao': forms.HiddenInput() } def clean(self): super(DocumentoAdministrativoForm, self).clean() cleaned_data = self.cleaned_data if not self.is_valid(): return cleaned_data numero_protocolo = self.data['numero_protocolo'] ano_protocolo = self.data['ano_protocolo'] complemento = re.sub('\s+', '', self.data['complemento']).upper() numero_documento = int(self.cleaned_data['numero']) tipo_documento = int(self.data['tipo']) ano_documento = int(self.data['ano']) # não permite atualizar para numero/ano/tipo existente if self.instance.pk: mudanca_doc = numero_documento != self.instance.numero \ or ano_documento != self.instance.ano \ or tipo_documento != self.instance.tipo.pk \ or complemento != self.instance.complemento if not self.instance.pk or mudanca_doc: doc_exists = DocumentoAdministrativo.objects.filter(numero=numero_documento, tipo=tipo_documento, ano=ano_documento, complemento=complemento).exists() if doc_exists: self.logger.error("DocumentoAdministrativo " "(numero={}, tipo={}, ano={}, " "complemento={}) já existe." .format(numero_documento, tipo_documento, ano_documento, complemento)) tipo = TipoDocumentoAdministrativo.objects.get( id=tipo_documento) raise ValidationError( _('{}/{} ({}) já existente! ' 'Você diferenciar preenchendo o campo complemento'.format(numero_documento, ano_documento, tipo))) # campos opcionais, mas que se informados devem ser válidos if numero_protocolo and ano_protocolo: try: self.logger.debug("Tentando obter Protocolo com numero={} e ano={}." .format(numero_protocolo, ano_protocolo)) self.fields['protocolo'].initial = Protocolo.objects.get( numero=numero_protocolo, ano=ano_protocolo).pk except ObjectDoesNotExist: self.logger.error("Protocolo %s/%s inexistente." % ( numero_protocolo, ano_protocolo)) msg = _('Protocolo %s/%s inexistente.' % ( numero_protocolo, ano_protocolo)) raise ValidationError(msg) except MultipleObjectsReturned: self.logger.error("Existe mais de um Protocolo com este ano ({}) e número ({}).".format( ano_protocolo, numero_protocolo)) msg = _( 'Existe mais de um Protocolo com este ano (%s) e número (%s).' % ( ano_protocolo, numero_protocolo)) raise ValidationError(msg) inst = self.instance.protocolo protocolo_antigo = inst.numero if inst else None if str(protocolo_antigo) != numero_protocolo: exist_materia = MateriaLegislativa.objects.filter( numero_protocolo=numero_protocolo, ano=ano_protocolo).exists() exist_doc = DocumentoAdministrativo.objects.filter( protocolo__numero=numero_protocolo, protocolo__ano=ano_protocolo).exists() if exist_materia or exist_doc: self.logger.error('Protocolo com numero=%s e ano=%s já possui' ' documento vinculado' % (numero_protocolo, ano_protocolo)) raise ValidationError(_('Protocolo %s/%s já possui' ' documento vinculado' % (numero_protocolo, ano_protocolo))) texto_integral = self.cleaned_data.get('texto_integral') if texto_integral: validar_arquivo(texto_integral, "Texto Integral") # else: # ## TODO: definir arquivo no form e preservar o nome do campo # ## que gerou a mensagem de erro. # ## texto_integral = forms.FileField(required=True, label="Texto Integral") # nome_arquivo = self.fields['texto_integral'].label # raise ValidationError(f'Favor anexar arquivo em {nome_arquivo}') return self.cleaned_data def save(self, commit=True): documento = super(DocumentoAdministrativoForm, self).save(False) if self.fields['protocolo'].initial: documento.protocolo = Protocolo.objects.get( id=int(self.fields['protocolo'].initial)) documento.save() return documento def __init__(self, *args, **kwargs): row1 = to_row( [('tipo', 3), ('numero', 3), ('complemento', 3), ('ano', 3)]) row2 = to_row( [('data', 3), ('numero_protocolo', 3), ('ano_protocolo', 3), ('autor', 3)]) row3 = to_row( [('assunto', 12)]) row4 = to_row( [('interessado', 7), ('tramitacao', 2), (InlineRadios('restrito'), 3)]) row5 = to_row( [('texto_integral', 12)]) row6 = to_row( [('numero_externo', 4), ('dias_prazo', 6), ('data_fim_prazo', 2)]) row7 = to_row( [('observacao', 12)]) self.helper = SaplFormHelper() self.helper.layout = SaplFormLayout( Fieldset(_('Identificação Básica'), row1, row2, row3, row4, row5), Fieldset(_('Outras Informações'), row6, row7)) super(DocumentoAdministrativoForm, self).__init__( *args, **kwargs) class DesvincularDocumentoForm(ModelForm): logger = logging.getLogger(__name__) numero = forms.CharField( required=True, label=DocumentoAdministrativo._meta.get_field('numero').verbose_name) ano = forms.ChoiceField( required=True, label=DocumentoAdministrativo._meta.get_field('ano').verbose_name, choices=choice_anos_com_documentoadministrativo, widget=forms.Select(attrs={'class': 'selector'})) def clean(self): super(DesvincularDocumentoForm, self).clean() cleaned_data = self.cleaned_data if not self.is_valid(): return cleaned_data numero = cleaned_data['numero'] ano = cleaned_data['ano'] tipo = cleaned_data['tipo'] try: self.logger.debug("Tentando obter DocumentoAdministrativo com numero={}, ano={} e tipo={}." .format(numero, ano, tipo)) documento = DocumentoAdministrativo.objects.get( numero=numero, ano=ano, tipo=tipo) if not documento.protocolo: self.logger.error( "DocumentoAdministrativo %s %s/%s não se encontra vinculado a nenhum protocolo." % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não se encontra vinculado a nenhum protocolo" % (tipo, numero, ano))) except ObjectDoesNotExist: self.logger.error( "DocumentoAdministrativo %s %s/%s não existe" % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não existe" % (tipo, numero, ano))) return cleaned_data class Meta: model = DocumentoAdministrativo fields = ['tipo', 'numero', 'ano', ] def __init__(self, *args, **kwargs): row1 = to_row( [('numero', 4), ('ano', 4), ('tipo', 4)]) self.helper = SaplFormHelper() self.helper.layout = Layout( Fieldset(_('Identificação do Documento'), row1, HTML(" "), form_actions(label='Desvincular') ) ) super(DesvincularDocumentoForm, self).__init__( *args, **kwargs) class DesvincularMateriaForm(forms.Form): logger = logging.getLogger(__name__) numero = forms.CharField(required=True, label=_('Número da Matéria')) ano = forms.ChoiceField(required=True, label=_('Ano da Matéria'), choices=choice_anos_com_materias, widget=forms.Select(attrs={'class': 'selector'})) tipo = forms.ModelChoiceField(label=_('Tipo de Matéria'), required=True, queryset=TipoMateriaLegislativa.objects.all(), empty_label='------') def clean(self): super(DesvincularMateriaForm, self).clean() cleaned_data = self.cleaned_data if not self.is_valid(): return cleaned_data numero = cleaned_data['numero'] ano = cleaned_data['ano'] tipo = cleaned_data['tipo'] try: self.logger.info("Tentando obter MateriaLegislativa com numero={}, ano={} e tipo={}." .format(numero, ano, tipo)) materia = MateriaLegislativa.objects.get( numero=numero, ano=ano, tipo=tipo) if not materia.numero_protocolo: self.logger.error( "MateriaLegislativa %s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano))) except ObjectDoesNotExist: self.logger.error( "MateriaLegislativa %s %s/%s não existe" % (tipo, numero, ano)) raise forms.ValidationError( _("%s %s/%s não existe" % (tipo, numero, ano))) return cleaned_data def __init__(self, *args, **kwargs): super(DesvincularMateriaForm, self).__init__(*args, **kwargs) row1 = to_row( [('numero', 4), ('ano', 4), ('tipo', 4)]) self.helper = SaplFormHelper() self.helper.layout = Layout( Fieldset(_('Identificação da Matéria'), row1, HTML(" "), form_actions(label='Desvincular') ) ) def pega_ultima_tramitacao_adm(): return TramitacaoAdministrativo.objects.values( 'documento_id').annotate(data_encaminhamento=Max( 'data_encaminhamento'), id=Max('id')).values_list('id', flat=True) def filtra_tramitacao_adm_status(status): lista = pega_ultima_tramitacao_adm() return TramitacaoAdministrativo.objects.filter( id__in=lista, status=status).distinct().values_list('documento_id', flat=True) def filtra_tramitacao_adm_destino(destino): lista = pega_ultima_tramitacao_adm() return TramitacaoAdministrativo.objects.filter( id__in=lista, unidade_tramitacao_destino=destino).distinct().values_list( 'documento_id', flat=True) def filtra_tramitacao_adm_destino_and_status(status, destino): lista = pega_ultima_tramitacao_adm() return TramitacaoAdministrativo.objects.filter( id__in=lista, status=status, unidade_tramitacao_destino=destino).distinct().values_list( 'documento_id', flat=True) class FichaPesquisaAdmForm(forms.Form): logger = logging.getLogger(__name__) tipo_documento = forms.ModelChoiceField( label=TipoDocumentoAdministrativo._meta.verbose_name, queryset=TipoDocumentoAdministrativo.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(FichaPesquisaAdmForm, self).__init__(*args, **kwargs) row1 = to_row( [('tipo_documento', 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(FichaPesquisaAdmForm, 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 FichaSelecionaAdmForm(forms.Form): documento = forms.ModelChoiceField( widget=forms.RadioSelect, queryset=DocumentoAdministrativo.objects.all(), label='') def __init__(self, *args, **kwargs): super(FichaSelecionaAdmForm, self).__init__(*args, **kwargs) row1 = to_row( [('documento', 12)]) self.helper = SaplFormHelper() self.helper.layout = Layout( Fieldset( ('Selecione a ficha que deseja imprimir'), row1, form_actions(label='Gerar Impresso') ) ) class PrimeiraTramitacaoEmLoteAdmFilterSet(django_filters.FilterSet): class Meta(FilterOverridesMetaMixin): model = DocumentoAdministrativo fields = ['tipo', 'data'] def __init__(self, *args, **kwargs): super(PrimeiraTramitacaoEmLoteAdmFilterSet, self).__init__( *args, **kwargs) self.filters['tipo'].label = 'Tipo de Documento' self.filters['data'].label = 'Data (Inicial - Final)' self.form.fields['tipo'].required = True self.form.fields['data'].required = False row1 = to_row([('tipo', 12)]) row2 = to_row([('data', 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 TramitacaoEmLoteAdmForm(ModelForm): logger = logging.getLogger(__name__) class Meta: model = TramitacaoAdministrativo fields = ['data_tramitacao', 'unidade_tramitacao_local', 'status', '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(TramitacaoEmLoteAdmForm, 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', 6), ('urgente', 6) ]) row4 = to_row([ ('texto', 12) ]) documentos_checkbox_HTML = '''
Selecione os documentos para tramitação:
{% for documento in object_list %} {% endfor %}
Documento
{{documento.tipo.sigla}} {{documento.tipo.descricao}} {{documento.numero}}/{{documento.ano}}
''' 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(TramitacaoEmLoteAdmForm, 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.error('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 @timing @transaction.atomic def save(self, commit=True): cd = self.cleaned_data documentos = self.initial['documentos'] 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_anexados = AppConfig.attr('tramitacao_documento') for doc_id in documentos: doc = DocumentoAdministrativo.objects.get(id=doc_id) tramitacao = TramitacaoAdministrativo.objects.create( status=cd['status'], documento=doc, 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'], texto=cd['texto'], data_fim_prazo=cd['data_fim_prazo'], user=user, ip=ip, ultima_edicao=ultima_edicao ) doc.tramitacao = False if tramitacao.status.indicador == "F" else True doc.save() if tramitar_anexados: lista_tramitacao = [] anexados = lista_anexados(doc) for da in anexados: if not da.tramitacaoadministrativo_set.all() \ or da.tramitacaoadministrativo_set.last() \ .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: da.tramitacao = False if tramitacao.status.indicador == "F" else True da.save() lista_tramitacao.append(TramitacaoAdministrativo( status=tramitacao.status, documento=da, 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, 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 TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao) return tramitacao class TramitacaoEmLoteAdmFilterSet(django_filters.FilterSet): class Meta(FilterOverridesMetaMixin): model = DocumentoAdministrativo fields = ['tipo', 'data', 'tramitacaoadministrativo__status', 'tramitacaoadministrativo__unidade_tramitacao_destino'] def __init__(self, *args, **kwargs): super(TramitacaoEmLoteAdmFilterSet, self).__init__( *args, **kwargs) self.filters['tipo'].label = _('Tipo de Documento') self.filters['data'].label = _('Data (Inicial - Final)') self.filters['tramitacaoadministrativo__unidade_tramitacao_destino' ].label = _('Unidade Destino (Último Destino)') self.filters['tramitacaoadministrativo__status'].label = _('Status') self.form.fields['tipo'].required = True self.form.fields['data'].required = False self.form.fields['tramitacaoadministrativo__status'].required = True self.form.fields[ 'tramitacaoadministrativo__unidade_tramitacao_destino'].required = True row1 = to_row([ ('tipo', 4), ('tramitacaoadministrativo__unidade_tramitacao_destino', 4), ('tramitacaoadministrativo__status', 4)]) row2 = to_row([('data', 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 VinculoDocAdminMateriaForm(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) class Meta: model = VinculoDocAdminMateria fields = ['tipo', 'numero', 'ano', 'data_anexacao', 'data_desanexacao'] def __init__(self, *args, **kwargs): return super().__init__(*args, **kwargs) def clean(self): super().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 = 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) if VinculoDocAdminMateria.objects.filter( documento=self.instance.documento, materia=materia ).exclude(pk=self.instance.pk).exists(): self.logger.error( "Matéria já se encontra vinculada a este documento.") raise ValidationError( _('Matéria já se encontra vinculada a este documento')) cleaned_data['materia'] = materia return cleaned_data def save(self, commit=False): vinculo = super().save(commit) vinculo.materia = self.cleaned_data['materia'] vinculo.save() return vinculo class VinculoDocAdminMateriaEmLoteFilterSet(django_filters.FilterSet): class Meta(FilterOverridesMetaMixin): model = MateriaLegislativa fields = ['tipo', 'data_apresentacao'] def __init__(self, *args, **kwargs): super().__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')))