Browse Source

refatora auditlog para post_save e post_delete genéricos (#3298)

* refatora auditlog para post_save e post_delete generico

* muda teste para captura de auth.User

* ignora auditlog se sender não faz parte das apps do sapl

* corrige teste de sender a ser ignorado

* retira audit_log dos saves executados dentro de migrate

* corrige código para erros apontados no travis no ultimo commit
pull/3302/head
Leandro Roberto Silva 4 years ago
committed by GitHub
parent
commit
e9b5fd6ad4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 74
      sapl/base/receivers.py
  2. 3
      sapl/base/signals.py
  3. 36
      sapl/crud/base.py
  4. 57
      sapl/materia/forms.py
  5. 161
      sapl/materia/views.py
  6. 95
      sapl/protocoloadm/forms.py
  7. 83
      sapl/protocoloadm/views.py

74
sapl/base/receivers.py

@ -1,13 +1,15 @@
import inspect
import logging import logging
from django.conf import settings
from django.core import serializers from django.core import serializers
from django.db.models.signals import post_delete from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.utils import timezone from django.utils import timezone
from sapl.base.email_utils import do_envia_email_tramitacao from sapl.base.email_utils import do_envia_email_tramitacao
from sapl.base.models import AuditLog from sapl.base.models import AuditLog
from sapl.base.signals import tramitacao_signal, post_delete_signal, post_save_signal from sapl.base.signals import tramitacao_signal
from sapl.materia.models import Tramitacao from sapl.materia.models import Tramitacao
from sapl.protocoloadm.models import TramitacaoAdministrativo from sapl.protocoloadm.models import TramitacaoAdministrativo
from sapl.utils import get_base_url from sapl.utils import get_base_url
@ -46,28 +48,53 @@ def status_tramitacao_materia(sender, instance, **kwargs):
documento.save() documento.save()
@receiver(post_delete_signal) def audit_log_function(sender, **kwargs):
@receiver(post_save_signal)
def audit_log(sender, **kwargs): try:
logger = logging.getLogger(__name__) if not sender._meta.app_config.name.startswith('sapl'):
return
except:
# não é necessário usar logger, aqui é usada apenas para
# eliminar um o if complexo
return
instance = kwargs.get('instance') instance = kwargs.get('instance')
operation = kwargs.get('operation') if instance._meta.model == AuditLog:
user = kwargs.get('request').user return
model_name = instance.__class__.__name__
app_name = instance._meta.app_label
object_id = instance.id
data = serializers.serialize('json', [instance])
if len(data) > AuditLog.MAX_DATA_LENGTH: logger = logging.getLogger(__name__)
data = data[:AuditLog.MAX_DATA_LENGTH]
if user: u = None
username = user.username pilha_de_execucao = inspect.stack()
else: for i in pilha_de_execucao:
username = '' if i.function == 'migrate':
return
r = i.frame.f_locals.get('request', None)
try:
if r.user._meta.label == settings.AUTH_USER_MODEL:
u = r.user
break
except:
# não é necessário usar logger, aqui é usada apenas para
# eliminar um o if complexo
pass
try: try:
operation = kwargs.get('operation')
user = u
model_name = instance.__class__.__name__
app_name = instance._meta.app_label
object_id = instance.id
data = serializers.serialize('json', [instance])
if len(data) > AuditLog.MAX_DATA_LENGTH:
data = data[:AuditLog.MAX_DATA_LENGTH]
if user:
username = user.username
else:
username = ''
AuditLog.objects.create(username=username, AuditLog.objects.create(username=username,
operation=operation, operation=operation,
model_name=model_name, model_name=model_name,
@ -78,3 +105,14 @@ def audit_log(sender, **kwargs):
except Exception as e: except Exception as e:
logger.error('Error saving auditing log object') logger.error('Error saving auditing log object')
logger.error(e) logger.error(e)
@receiver(post_delete)
def audit_log_post_delete(sender, **kwargs):
audit_log_function(sender, operation='D', **kwargs)
@receiver(post_save)
def audit_log_post_save(sender, **kwargs):
operation = 'C' if kwargs.get('created') else 'U'
audit_log_function(sender, operation=operation, **kwargs)

3
sapl/base/signals.py

@ -46,6 +46,3 @@ def cria_models_tipo_autor(app_config=None, verbosity=2, interactive=True,
post_migrate.connect(receiver=cria_models_tipo_autor) post_migrate.connect(receiver=cria_models_tipo_autor)
post_delete_signal = django.dispatch.Signal(providing_args=['instance', 'request'])
post_save_signal = django.dispatch.Signal(providing_args=['instance', 'operation', 'request'])

36
sapl/crud/base.py

@ -22,7 +22,6 @@ from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
from django.views.generic.base import ContextMixin from django.views.generic.base import ContextMixin
from django.views.generic.list import MultipleObjectMixin from django.views.generic.list import MultipleObjectMixin
from sapl.base.signals import post_delete_signal, post_save_signal
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
from sapl.crispy_layout_mixin import SaplFormHelper from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
@ -626,37 +625,8 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
return queryset return queryset
class AuditLogMixin(object):
def delete(self, request, *args, **kwargs):
# Classe deve implementar um get_object(), i.e., deve ser uma View
deleted_object = self.get_object()
try:
return super(AuditLogMixin, self).delete(request, args, kwargs)
finally:
post_delete_signal.send(sender=None,
instance=deleted_object,
operation='D',
request=self.request)
# SAVE/UPDATE method
def form_valid(self, form):
try:
if not form.instance.pk:
operation = 'C'
else:
operation = 'U'
return super(AuditLogMixin, self).form_valid(form)
finally:
post_save_signal.send(sender=None,
instance=form.instance,
operation=operation,
request=self.request
)
class CrudCreateView(PermissionRequiredContainerCrudMixin, class CrudCreateView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, AuditLogMixin, CreateView): FormMessagesMixin, CreateView):
permission_required = (RP_ADD,) permission_required = (RP_ADD,)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -874,7 +844,7 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
class CrudUpdateView(PermissionRequiredContainerCrudMixin, class CrudUpdateView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, AuditLogMixin, UpdateView): FormMessagesMixin, UpdateView):
permission_required = (RP_CHANGE,) permission_required = (RP_CHANGE,)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -905,7 +875,7 @@ class CrudUpdateView(PermissionRequiredContainerCrudMixin,
class CrudDeleteView(PermissionRequiredContainerCrudMixin, class CrudDeleteView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, AuditLogMixin, DeleteView): FormMessagesMixin, DeleteView):
permission_required = (RP_DELETE,) permission_required = (RP_DELETE,)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

57
sapl/materia/forms.py

@ -1,30 +1,28 @@
import django_filters
import logging import logging
import os import os
import sapl
from crispy_forms.bootstrap import Alert, InlineRadios from crispy_forms.bootstrap import Alert, InlineRadios
from crispy_forms.layout import (Button, Field, Fieldset, HTML, Layout, Row) from crispy_forms.layout import (Button, Field, Fieldset, HTML, Layout, Row)
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.files.base import File from django.core.files.base import File
from django.urls import reverse
from django.db import models, transaction from django.db import models, transaction
from django.db.models import F, Max, Q from django.db.models import F, Max, Q
from django.forms import ModelChoiceField, ModelForm, widgets from django.forms import ModelChoiceField, ModelForm, widgets
from django.forms.forms import Form from django.forms.forms import Form
from django.forms.models import ModelMultipleChoiceField from django.forms.models import ModelMultipleChoiceField
from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select
from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
import sapl
from sapl.base.models import AppConfig, Autor, TipoAutor from sapl.base.models import AppConfig, Autor, TipoAutor
from sapl.base.signals import post_save_signal
from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PRIVATE) STATUS_TA_PRIVATE)
@ -34,7 +32,7 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto,
MateriaLegislativa, Orgao, MateriaLegislativa, Orgao,
RegimeTramitacao, StatusTramitacao, RegimeTramitacao, StatusTramitacao,
TipoDocumento, TipoProposicao, TipoDocumento, TipoProposicao,
UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa) UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica, from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica) TipoNormaJuridica)
from sapl.parlamentares.models import Legislatura, Partido, Parlamentar from sapl.parlamentares.models import Legislatura, Partido, Parlamentar
@ -211,8 +209,10 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
if protocolo: if protocolo:
if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists(): if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists():
self.logger.warning("Protocolo %s/%s não existe" % (protocolo, ano)) self.logger.warning(
raise ValidationError(_('Protocolo %s/%s não existe' % (protocolo, ano))) "Protocolo %s/%s não existe" % (protocolo, ano))
raise ValidationError(
_('Protocolo %s/%s não existe' % (protocolo, ano)))
if protocolo_antigo != protocolo: if protocolo_antigo != protocolo:
exist_materia = MateriaLegislativa.objects.filter( exist_materia = MateriaLegislativa.objects.filter(
@ -525,7 +525,8 @@ class TramitacaoForm(ModelForm):
if cleaned_data['data_tramitacao'] > timezone.now().date(): 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!' self.logger.warning('A data de tramitação informada ({}) não é menor ou igual a data de hoje!'
.format(cleaned_data['data_tramitacao'])) .format(cleaned_data['data_tramitacao']))
msg = _('A data de tramitação deve ser menor ou igual a data de hoje!') msg = _(
'A data de tramitação deve ser menor ou igual a data de hoje!')
raise ValidationError(msg) raise ValidationError(msg)
if (ultima_tramitacao and if (ultima_tramitacao and
@ -539,9 +540,10 @@ class TramitacaoForm(ModelForm):
if data_enc_form: if data_enc_form:
if data_enc_form < data_tram_form: if data_enc_form < data_tram_form:
msg = _('A data de encaminhamento deve ser maior que a data de tramitação!') 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! ({})" self.logger.warning("A data de encaminhamento ({}) deve ser maior que a data de tramitação! ({})"
.format(data_enc_form, data_tram_form)) .format(data_enc_form, data_tram_form))
raise ValidationError(msg) raise ValidationError(msg)
if data_prazo_form: if data_prazo_form:
@ -669,13 +671,14 @@ class TramitacaoUpdateForm(TramitacaoForm):
'tramitação, pois irá conflitar com a Unidade ' 'tramitação, pois irá conflitar com a Unidade '
'Local da tramitação seguinte') 'Local da tramitação seguinte')
if not (cd['data_tramitacao'] != obj.data_tramitacao or \ if not (cd['data_tramitacao'] != obj.data_tramitacao or
cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or \ cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or
cd['status'] != obj.status or cd['texto'] != obj.texto or \ cd['status'] != obj.status or cd['texto'] != obj.texto or
cd['data_encaminhamento'] != obj.data_encaminhamento or \ cd['data_encaminhamento'] != obj.data_encaminhamento or
cd['data_fim_prazo'] != obj.data_fim_prazo or cd['urgente'] != str(obj.urgente) or \ cd['data_fim_prazo'] != obj.data_fim_prazo or cd['urgente'] != str(obj.urgente) or
cd['turno'] != obj.turno): 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 # 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['user'] = obj.user
cd['ip'] = obj.ip cd['ip'] = obj.ip
cd['ultima_edicao'] = obj.ultima_edicao cd['ultima_edicao'] = obj.ultima_edicao
@ -698,7 +701,8 @@ class TramitacaoUpdateForm(TramitacaoForm):
if tramitar_anexadas: if tramitar_anexadas:
anexadas_list = lista_anexados(materia) anexadas_list = lista_anexados(materia)
for ma in anexadas_list: for ma in anexadas_list:
tram_anexada = ma.tramitacao_set.order_by('-data_tramitacao', '-id').first() tram_anexada = ma.tramitacao_set.order_by(
'-data_tramitacao', '-id').first()
if compara_tramitacoes_mat(ant_tram_principal, tram_anexada): if compara_tramitacoes_mat(ant_tram_principal, tram_anexada):
tram_anexada.status = nova_tram_principal.status tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
@ -907,7 +911,8 @@ class AnexadaForm(ModelForm):
except ObjectDoesNotExist: except ObjectDoesNotExist:
msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.' msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.'
.format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano'])) .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.") self.logger.warning(
"A matéria a ser anexada não existe no cadastro de matérias legislativas.")
raise ValidationError(msg) raise ValidationError(msg)
materia_principal = self.instance.materia_principal materia_principal = self.instance.materia_principal
@ -1118,7 +1123,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
), ),
Fieldset(_('Origem externa'), Fieldset(_('Origem externa'),
row10, row11 row10, row11
), ),
Fieldset(_('Pesquisa Avançada'), Fieldset(_('Pesquisa Avançada'),
row3, row3,
HTML(autor_label), HTML(autor_label),
@ -1645,7 +1650,6 @@ class TramitacaoEmLoteForm(ModelForm):
'ip': forms.HiddenInput(), 'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()} 'ultima_edicao': forms.HiddenInput()}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs) super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date() self.fields['data_tramitacao'].initial = timezone.now().date()
@ -1746,7 +1750,8 @@ class TramitacaoEmLoteForm(ModelForm):
if data_enc_form < data_tram_form: if data_enc_form < data_tram_form:
self.logger.warning('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)) .format(data_enc_form, data_tram_form))
msg = _('A data de encaminhamento deve ser maior que a data de tramitação!') msg = _(
'A data de encaminhamento deve ser maior que a data de tramitação!')
raise ValidationError(msg) raise ValidationError(msg)
if data_prazo_form: if data_prazo_form:
@ -2555,7 +2560,8 @@ class ConfirmarProposicaoForm(ProposicaoForm):
data_fim__year__gte=timezone.now().year).first() data_fim__year__gte=timezone.now().year).first()
ano_inicio = legislatura.data_inicio.year ano_inicio = legislatura.data_inicio.year
ano_fim = legislatura.data_fim.year ano_fim = legislatura.data_fim.year
nm = Protocolo.objects.filter(ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero')) nm = Protocolo.objects.filter(
ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero'))
else: else:
# numeracao == 'U' ou não informada # numeracao == 'U' ou não informada
nm = Protocolo.objects.all().aggregate(Max('numero')) nm = Protocolo.objects.all().aggregate(Max('numero'))
@ -2923,9 +2929,8 @@ class MateriaPesquisaSimplesForm(forms.Form):
return cleaned_data return cleaned_data
class ConfigEtiquetaMateriaLegislativaForms(ModelForm): class ConfigEtiquetaMateriaLegislativaForms(ModelForm):
class Meta: class Meta:
model = ConfigEtiquetaMateriaLegislativa model = ConfigEtiquetaMateriaLegislativa
fields = '__all__' fields = '__all__'

161
sapl/materia/views.py

@ -1,46 +1,43 @@
from datetime import datetime
from datetime import datetime
from io import BytesIO
import itertools import itertools
import logging import logging
import os import os
import sapl from random import choice
import shutil import shutil
from string import ascii_letters, digits
import tempfile import tempfile
import weasyprint
import time import time
from crispy_forms.layout import HTML
from datetime import datetime
from random import choice
from string import ascii_letters, digits
from datetime import datetime
from PyPDF4 import PdfFileReader, PdfFileMerger
import zipfile import zipfile
from io import BytesIO
from PyPDF4 import PdfFileReader, PdfFileMerger
from crispy_forms.layout import HTML
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError
from django.urls import reverse
from django.db.models import Max, Q from django.db.models import Max, Q
from django.http import HttpResponse, JsonResponse from django.http import HttpResponse, JsonResponse
from django.http.response import Http404, HttpResponseRedirect from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.shortcuts import render
from django.template import loader, RequestContext from django.template import loader, RequestContext
from django.urls import reverse
from django.utils import formats, timezone from django.utils import formats, timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django.shortcuts import render
from django_filters.views import FilterView from django_filters.views import FilterView
import weasyprint
import sapl
from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig
from sapl.base.signals import tramitacao_signal, post_delete_signal, post_save_signal from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao, Participacao, Composicao from sapl.comissoes.models import Comissao, Participacao, Composicao
from sapl.compilacao.models import STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE from sapl.compilacao.models import STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
@ -51,7 +48,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm
ConfirmarProposicaoForm, DevolverProposicaoForm, ConfirmarProposicaoForm, DevolverProposicaoForm,
DespachoInicialCreateForm, LegislacaoCitadaForm, DespachoInicialCreateForm, LegislacaoCitadaForm,
MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm, MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm,
TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm,ConfigEtiquetaMateriaLegislativaForms) TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm, ConfigEtiquetaMateriaLegislativaForms)
from sapl.norma.models import LegislacaoCitada from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
@ -59,7 +56,7 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE, MEDIA_ROOT
from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url, from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url,
get_client_ip, get_mime_type_from_file_extension, lista_anexados, get_client_ip, get_mime_type_from_file_extension, lista_anexados,
mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO, mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO,
show_results_filter_set, YES_NO_CHOICES,get_tempfile_dir) show_results_filter_set, YES_NO_CHOICES, get_tempfile_dir)
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet, AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet,
@ -75,7 +72,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, De
DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao,
Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao, Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa) Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa)
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@ -812,7 +809,8 @@ class ProposicaoCrud(Crud):
elif p.data_envio: elif p.data_envio:
msg_error = _('Proposição já foi enviada.') msg_error = _('Proposição já foi enviada.')
elif not p.texto_original and not p.texto_articulado.exists(): elif not p.texto_original and not p.texto_articulado.exists():
msg_error = _('Proposição não possui nenhum tipo de Texto associado.') msg_error = _(
'Proposição não possui nenhum tipo de Texto associado.')
else: else:
if p.texto_articulado.exists(): if p.texto_articulado.exists():
ta = p.texto_articulado.first() ta = p.texto_articulado.first()
@ -820,7 +818,8 @@ class ProposicaoCrud(Crud):
ta.editing_locked = True ta.editing_locked = True
ta.save() ta.save()
receber_recibo = BaseAppConfig.attr('receber_recibo_proposicao') receber_recibo = BaseAppConfig.attr(
'receber_recibo_proposicao')
if not receber_recibo: if not receber_recibo:
ta = p.texto_articulado.first() ta = p.texto_articulado.first()
@ -830,7 +829,8 @@ class ProposicaoCrud(Crud):
p.data_envio = timezone.now() p.data_envio = timezone.now()
p.save() p.save()
messages.success(request, _('Proposição enviada com sucesso.')) messages.success(request, _(
'Proposição enviada com sucesso.'))
try: try:
self.logger.debug("User={}. Tentando obter número do objeto MateriaLegislativa " self.logger.debug("User={}. Tentando obter número do objeto MateriaLegislativa "
"com atributos tipo={} e ano={}." "com atributos tipo={} e ano={}."
@ -845,13 +845,16 @@ class ProposicaoCrud(Crud):
"número que pode não corresponder com a realidade" "número que pode não corresponder com a realidade"
.format(p.tipo, numero, p.ano))) .format(p.tipo, numero, p.ano)))
except ValueError as e: except ValueError as e:
self.logger.warning("User=" + username + ". " + str(e)) self.logger.warning(
"User=" + username + ". " + str(e))
pass pass
except AttributeError as e: except AttributeError as e:
self.logger.warning("User=" + username + ". " + str(e)) self.logger.warning(
"User=" + username + ". " + str(e))
pass pass
except TypeError as e: except TypeError as e:
self.logger.warning("User=" + username + ". " + str(e)) self.logger.warning(
"User=" + username + ". " + str(e))
pass pass
elif action == 'return': elif action == 'return':
@ -862,7 +865,8 @@ class ProposicaoCrud(Crud):
elif p.data_recebimento: elif p.data_recebimento:
self.logger.warning("User={}. Proposição (numero={}) já foi recebida, " self.logger.warning("User={}. Proposição (numero={}) já foi recebida, "
"não é possível retorná-la.".format(username, p.numero_proposicao)) "não é possível retorná-la.".format(username, p.numero_proposicao))
msg_error = _('Proposição já foi recebida, não é possível retorná-la.') msg_error = _(
'Proposição já foi recebida, não é possível retorná-la.')
else: else:
p.data_envio = None p.data_envio = None
p.save() p.save()
@ -873,7 +877,8 @@ class ProposicaoCrud(Crud):
ta.save() ta.save()
self.logger.info("User={}. Proposição (numero={}) Retornada com sucesso." self.logger.info("User={}. Proposição (numero={}) Retornada com sucesso."
.format(username, p.numero_proposicao)) .format(username, p.numero_proposicao))
messages.success(request, _('Proposição Retornada com sucesso.')) messages.success(request, _(
'Proposição Retornada com sucesso.'))
if msg_error: if msg_error:
messages.error(request, msg_error) messages.error(request, msg_error)
@ -884,7 +889,8 @@ class ProposicaoCrud(Crud):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
username = request.user.username username = request.user.username
try: try:
self.logger.debug("User={}. Tentando obter objeto Proposicao com pk={}".format(username, kwargs['pk'])) self.logger.debug("User={}. Tentando obter objeto Proposicao com pk={}".format(
username, kwargs['pk']))
p = Proposicao.objects.get(id=kwargs['pk']) p = Proposicao.objects.get(id=kwargs['pk'])
except Exception as e: except Exception as e:
self.logger.warning("User={}. Erro ao obter proposicao com pk={}. Retornando 404. {}" self.logger.warning("User={}. Erro ao obter proposicao com pk={}. Retornando 404. {}"
@ -915,7 +921,8 @@ class ProposicaoCrud(Crud):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def _action_is_valid(self, request, *args, **kwargs): def _action_is_valid(self, request, *args, **kwargs):
proposicao = Proposicao.objects.filter(id=kwargs['pk']).values_list('data_envio', 'data_recebimento') proposicao = Proposicao.objects.filter(
id=kwargs['pk']).values_list('data_envio', 'data_recebimento')
username = request.user.username username = request.user.username
@ -923,7 +930,8 @@ class ProposicaoCrud(Crud):
if proposicao[0][0] and proposicao[0][1]: if proposicao[0][0] and proposicao[0][1]:
self.logger.warning("User={}. Proposição (id={}) já foi enviada e recebida." self.logger.warning("User={}. Proposição (id={}) já foi enviada e recebida."
"Não pode mais ser excluida.".format(username, kwargs['pk'])) "Não pode mais ser excluida.".format(username, kwargs['pk']))
msg = _('Proposição já foi enviada e recebida. Não pode mais ser excluida.') msg = _(
'Proposição já foi enviada e recebida. Não pode mais ser excluida.')
elif proposicao[0][0] and not proposicao[0][1]: elif proposicao[0][0] and not proposicao[0][1]:
self.logger.warning("""\ self.logger.warning("""\
User={}. Proposição (id={}) foi enviada, mas ainda não recebida pelo protocolo. \ User={}. Proposição (id={}) foi enviada, mas ainda não recebida pelo protocolo. \
@ -976,7 +984,8 @@ class ProposicaoCrud(Crud):
return super().form_valid(form) return super().form_valid(form)
def _action_is_valid(self, request, *args, **kwargs): def _action_is_valid(self, request, *args, **kwargs):
proposicao = Proposicao.objects.filter(id=kwargs['pk']).values_list('data_envio', 'data_recebimento') proposicao = Proposicao.objects.filter(
id=kwargs['pk']).values_list('data_envio', 'data_recebimento')
username = request.user.username username = request.user.username
@ -985,7 +994,8 @@ class ProposicaoCrud(Crud):
if proposicao[0][0] and proposicao[0][1]: if proposicao[0][0] and proposicao[0][1]:
self.logger.warning('User={}. Proposição (id={}) já foi enviada e recebida. ' self.logger.warning('User={}. Proposição (id={}) já foi enviada e recebida. '
'Não pode mais ser editada'.format(username, kwargs['pk'])) 'Não pode mais ser editada'.format(username, kwargs['pk']))
msg = _('Proposição já foi enviada e recebida. Não pode mais ser editada') msg = _(
'Proposição já foi enviada e recebida. Não pode mais ser editada')
elif proposicao[0][0] and not proposicao[0][1]: elif proposicao[0][0] and not proposicao[0][1]:
self.logger.warning("""\ self.logger.warning("""\
User={}. Proposição (id={}) foi enviada, mas ainda não recebida pelo protocolo. \ User={}. Proposição (id={}) foi enviada, mas ainda não recebida pelo protocolo. \
@ -1064,14 +1074,17 @@ class ProposicaoCrud(Crud):
if obj.data_recebimento is None: if obj.data_recebimento is None:
obj.data_recebimento = 'Não recebida' if obj.data_envio else 'Não enviada' obj.data_recebimento = 'Não recebida' if obj.data_envio else 'Não enviada'
else: else:
obj.data_recebimento = timezone.localtime(obj.data_recebimento) obj.data_recebimento = timezone.localtime(
obj.data_recebimento = formats.date_format(obj.data_recebimento, "DATETIME_FORMAT") obj.data_recebimento)
obj.data_recebimento = formats.date_format(
obj.data_recebimento, "DATETIME_FORMAT")
if obj.data_envio is None: if obj.data_envio is None:
obj.data_envio = 'Em elaboração...' obj.data_envio = 'Em elaboração...'
else: else:
obj.data_envio = timezone.localtime(obj.data_envio) obj.data_envio = timezone.localtime(obj.data_envio)
obj.data_envio = formats.date_format(obj.data_envio, "DATETIME_FORMAT") obj.data_envio = formats.date_format(
obj.data_envio, "DATETIME_FORMAT")
return [self._as_row(obj) for obj in object_list] return [self._as_row(obj) for obj in object_list]
@ -1149,7 +1162,8 @@ class RelatoriaCrud(MasterDetailCrud):
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk']) materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
loc_atual = Tramitacao.objects.\ loc_atual = Tramitacao.objects.\
filter(materia=materia).order_by('-data_tramitacao', '-id').first() filter(materia=materia).order_by(
'-data_tramitacao', '-id').first()
if loc_atual is None: if loc_atual is None:
localizacao = -1 localizacao = -1
@ -1353,7 +1367,8 @@ class TramitacaoCrud(MasterDetailCrud):
url = reverse('sapl.materia:tramitacao_list', url = reverse('sapl.materia:tramitacao_list',
kwargs={'pk': materia.id}) kwargs={'pk': materia.id})
ultima_tramitacao = materia.tramitacao_set.order_by('-data_tramitacao', '-id').first() ultima_tramitacao = materia.tramitacao_set.order_by(
'-data_tramitacao', '-id').first()
if tramitacao.pk != ultima_tramitacao.pk: if tramitacao.pk != ultima_tramitacao.pk:
username = request.user.username username = request.user.username
@ -1373,20 +1388,22 @@ class TramitacaoCrud(MasterDetailCrud):
if tramitar_anexadas: if tramitar_anexadas:
mat_anexadas = lista_anexados(materia) mat_anexadas = lista_anexados(materia)
for ma in mat_anexadas: for ma in mat_anexadas:
tram_anexada = ma.tramitacao_set.order_by('-data_tramitacao', '-id').first() tram_anexada = ma.tramitacao_set.order_by(
'-data_tramitacao', '-id').first()
if compara_tramitacoes_mat(tram_anexada, tramitacao): if compara_tramitacoes_mat(tram_anexada, tramitacao):
tramitacoes_deletar.append(tram_anexada) tramitacoes_deletar.append(tram_anexada)
if ma.tramitacao_set.count() == 0: if ma.tramitacao_set.count() == 0:
ma.em_tramitacao = False ma.em_tramitacao = False
ma.save() ma.save()
Tramitacao.objects.filter(id__in=[t.id for t in tramitacoes_deletar]).delete() Tramitacao.objects.filter(
id__in=[t.id for t in tramitacoes_deletar]).delete()
# TODO: otimizar para passar a lista de matérias # TODO: otimizar para passar a lista de matérias
for tramitacao in tramitacoes_deletar: # for tramitacao in tramitacoes_deletar:
post_delete_signal.send(sender=None, # post_delete_signal.send(sender=None,
instance=tramitacao, # instance=tramitacao,
operation='C', # operation='C',
request=self.request) # request=self.request)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
@ -2164,8 +2181,8 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
if request.FILES['arquivo'].size > MAX_DOC_UPLOAD_SIZE: if request.FILES['arquivo'].size > MAX_DOC_UPLOAD_SIZE:
msg = _("O arquivo Anexo de Texto Integral deve ser menor que {0:.1f} MB, \ msg = _("O arquivo Anexo de Texto Integral deve ser menor que {0:.1f} MB, \
o tamanho atual desse arquivo é {1:.1f} MB" \ o tamanho atual desse arquivo é {1:.1f} MB"
.format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (request.FILES['arquivo'].size/1024)/1024)) .format((MAX_DOC_UPLOAD_SIZE / 1024) / 1024, (request.FILES['arquivo'].size / 1024) / 1024))
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
@ -2356,7 +2373,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteView, context = super(PrimeiraTramitacaoEmLoteView,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
@ -2379,7 +2395,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
context['title'] = _('Primeira Tramitação em Lote') context['title'] = _('Primeira Tramitação em Lote')
# Pega somente documentos que não possuem tramitação # Pega somente documentos que não possuem tramitação
context['object_list'] = [obj for obj in context['object_list'] context['object_list'] = [obj for obj in context['object_list']
if obj.tramitacao_set.order_by('-data_tramitacao', '-id').all().count() == 0] if obj.tramitacao_set.order_by('-data_tramitacao', '-id').all().count() == 0]
else: else:
context['title'] = _('Tramitação em Lote') context['title'] = _('Tramitação em Lote')
context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get( context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
@ -2405,33 +2421,33 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
form = TramitacaoEmLoteForm(request.POST, form = TramitacaoEmLoteForm(request.POST,
initial= {'materias': materias_ids, initial={'materias': materias_ids,
'user': user, 'ip':ip, 'user': user, 'ip': ip,
'ultima_edicao': ultima_edicao}) 'ultima_edicao': ultima_edicao})
if form.is_valid(): if form.is_valid():
form.save() form.save()
msg = _('Tramitação completa.') msg = _('Tramitação completa.')
self.logger.info('user=' + user.username + '. Tramitação completa.') self.logger.info('user=' + user.username +
'. Tramitação completa.')
messages.add_message(request, messages.SUCCESS, msg) messages.add_message(request, messages.SUCCESS, msg)
return self.get_success_url() return self.get_success_url()
return self.form_invalid(form) return self.form_invalid(form)
def get_success_url(self): def get_success_url(self):
return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote')) return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
def form_invalid(self, form, *args, **kwargs): def form_invalid(self, form, *args, **kwargs):
for key, erros in form.errors.items(): for key, erros in form.errors.items():
if not key=='__all__': if not key == '__all__':
[messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros] [messages.add_message(
self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
else: else:
[messages.add_message(self.request, messages.ERROR, e) for e in erros] [messages.add_message(self.request, messages.ERROR, e)
return self.get(self.request, kwargs, {'form':form}) for e in erros]
return self.get(self.request, kwargs, {'form': form})
class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView): class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
@ -2724,8 +2740,10 @@ def create_zip_docacessorios(materia):
docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs] docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs]
if not docs_path: if not docs_path:
raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.") raise FileNotFoundError(
logger.info("Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path)) "Não há arquivos PDF cadastrados em documentos acessorios.")
logger.info(
"Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path))
_zipfile = BytesIO() _zipfile = BytesIO()
@ -2737,7 +2755,8 @@ def create_zip_docacessorios(materia):
logger.error(e) logger.error(e)
raise e raise e
external_name = "mat_{}_{}_docacessorios.zip".format(materia.numero, materia.ano) external_name = "mat_{}_{}_docacessorios.zip".format(
materia.numero, materia.ano)
return external_name, _zipfile.getvalue() return external_name, _zipfile.getvalue()
@ -2748,7 +2767,8 @@ def get_zip_docacessorios(request, pk):
data = None data = None
try: try:
external_name, data = create_zip_docacessorios(materia) external_name, data = create_zip_docacessorios(materia)
logger.info("user= {}. Gerou o zip compilado de documento acessorios".format(username)) logger.info(
"user= {}. Gerou o zip compilado de documento acessorios".format(username))
except FileNotFoundError: except FileNotFoundError:
logger.error("user= {}.Não há arquivos cadastrados".format(username)) logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg = _('Não há arquivos cadastrados nesses documentos acessórios.') msg = _('Não há arquivos cadastrados nesses documentos acessórios.')
@ -2787,9 +2807,11 @@ def create_pdf_docacessorios(materia):
# TODO: o for-comprehension abaixo filtra os arquivos não PDF. # TODO: o for-comprehension abaixo filtra os arquivos não PDF.
# TODO: o que fazer com os arquivos não PDF? converter? ignorar? # TODO: o que fazer com os arquivos não PDF? converter? ignorar?
docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs if i.lower().endswith('pdf')] docs_path = [os.path.join(MEDIA_ROOT, i)
for i in docs if i.lower().endswith('pdf')]
if not docs_path: if not docs_path:
raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.") raise FileNotFoundError(
"Não há arquivos PDF cadastrados em documentos acessorios.")
logger.info("Gerando compilado PDF de documentos acessorios com {} documentos" logger.info("Gerando compilado PDF de documentos acessorios com {} documentos"
.format(docs_path)) .format(docs_path))
merged_pdf = '{}/mat_{}_{}_docacessorios.pdf'.format( merged_pdf = '{}/mat_{}_{}_docacessorios.pdf'.format(
@ -2805,7 +2827,8 @@ def create_pdf_docacessorios(materia):
merger.write(data) merger.write(data)
merger.close() merger.close()
external_name = "mat_{}_{}_docacessorios.pdf".format(materia.numero, materia.ano) external_name = "mat_{}_{}_docacessorios.pdf".format(
materia.numero, materia.ano)
return external_name, data.getvalue() return external_name, data.getvalue()
@ -2815,7 +2838,8 @@ def get_pdf_docacessorios(request, pk):
username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username
try: try:
external_name, data = create_pdf_docacessorios(materia) external_name, data = create_pdf_docacessorios(materia)
logger.info("user= {}. Gerou o pdf compilado de documento acessorios".format(username)) logger.info(
"user= {}. Gerou o pdf compilado de documento acessorios".format(username))
except FileNotFoundError: except FileNotFoundError:
logger.error("user= {}.Não há arquivos cadastrados".format(username)) logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg = _('Não há arquivos cadastrados nesses documentos acessórios.') msg = _('Não há arquivos cadastrados nesses documentos acessórios.')
@ -2824,7 +2848,7 @@ def get_pdf_docacessorios(request, pk):
kwargs={'pk': pk})) kwargs={'pk': pk}))
except Exception as e: except Exception as e:
logger.error("user= {}.Um erro inesperado ocorreu na criação do pdf de documentos acessorios: {}" logger.error("user= {}.Um erro inesperado ocorreu na criação do pdf de documentos acessorios: {}"
.format(username,str(e))) .format(username, str(e)))
msg = _('Um erro inesperado ocorreu. Entre em contato com o suporte do SAPL.') msg = _('Um erro inesperado ocorreu. Entre em contato com o suporte do SAPL.')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list', return redirect(reverse('sapl.materia:documentoacessorio_list',
@ -2845,7 +2869,8 @@ def get_pdf_docacessorios(request, pk):
def configEtiquetaMateriaLegislativaCrud(request): def configEtiquetaMateriaLegislativaCrud(request):
config = ConfigEtiquetaMateriaLegislativa.objects.last() config = ConfigEtiquetaMateriaLegislativa.objects.last()
if request.method == "POST": if request.method == "POST":
form = ConfigEtiquetaMateriaLegislativaForms(request.POST, instance=config) form = ConfigEtiquetaMateriaLegislativaForms(
request.POST, instance=config)
if form.is_valid(): if form.is_valid():
config = form.save(commit=False) config = form.save(commit=False)
config.published_date = timezone.now() config.published_date = timezone.now()

95
sapl/protocoloadm/forms.py

@ -1,11 +1,9 @@
import re
import django_filters
import logging import logging
import re
from crispy_forms.bootstrap import InlineRadios, Alert, FormActions from crispy_forms.bootstrap import InlineRadios, Alert, FormActions
from crispy_forms.layout import (Button, Column, Div, Fieldset, HTML, from crispy_forms.layout import (Button, Column, Div, Fieldset, HTML,
Layout, Submit) Layout, Submit)
from django import forms from django import forms
from django.core.exceptions import (MultipleObjectsReturned, from django.core.exceptions import (MultipleObjectsReturned,
ObjectDoesNotExist, ValidationError) ObjectDoesNotExist, ValidationError)
@ -14,9 +12,9 @@ from django.db.models import Max
from django.forms import ModelForm from django.forms import ModelForm
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor, TipoAutor, AppConfig from sapl.base.models import Autor, TipoAutor, AppConfig
from sapl.base.signals import post_save_signal
from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper, from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper,
SaplFormLayout, to_row) SaplFormLayout, to_row)
from sapl.materia.models import (MateriaLegislativa, from sapl.materia.models import (MateriaLegislativa,
@ -176,7 +174,6 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
o = AnoNumeroOrderingFilter(help_text='') o = AnoNumeroOrderingFilter(help_text='')
class Meta(FilterOverridesMetaMixin): class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo model = DocumentoAdministrativo
fields = ['tipo', fields = ['tipo',
@ -203,14 +200,14 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
row2 = to_row( row2 = to_row(
[('numero', 5), [('numero', 5),
('complemento',2), ('complemento', 2),
('ano', 5)]) ('ano', 5)])
row3 = to_row( row3 = to_row(
[('protocolo__numero', 4), [('protocolo__numero', 4),
('numero_externo', 4), ('numero_externo', 4),
('data', 4) ('data', 4)
]) ])
row4 = to_row( row4 = to_row(
[('interessado', 6), [('interessado', 6),
@ -224,28 +221,26 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
]) ])
buttons = FormActions( buttons = FormActions(
*[ *[
HTML(''' HTML('''
<div class="form-check"> <div class="form-check">
<input name="relatorio" type="checkbox" class="form-check-input" id="relatorio"> <input name="relatorio" type="checkbox" class="form-check-input" id="relatorio">
<label class="form-check-label" for="relatorio">Gerar relatório PDF</label> <label class="form-check-label" for="relatorio">Gerar relatório PDF</label>
</div> </div>
''' ) ''')
], ],
Submit('pesquisar', _('Pesquisar'), css_class='float-right', Submit('pesquisar', _('Pesquisar'), css_class='float-right',
onclick='return true;'), onclick='return true;'),
css_class='form-group row justify-content-between' css_class='form-group row justify-content-between',
,
) )
self.form.helper = SaplFormHelper() self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET' self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout( self.form.helper.layout = Layout(
Fieldset(_('Pesquisar Documento'), Fieldset(_('Pesquisar Documento'),
row1, row2, row1, row2,
row3, row4, row3, row4,
row5, buttons,) row5, buttons,)
) )
@ -437,7 +432,7 @@ class ProtocoloDocumentoForm(ModelForm):
Fieldset(_('Identificação de Documento'), Fieldset(_('Identificação de Documento'),
row1, row1,
row2), row2),
fieldset, fieldset,
row4, row4,
row5, row5,
HTML("&nbsp;"), HTML("&nbsp;"),
@ -452,7 +447,6 @@ class ProtocoloDocumentoForm(ModelForm):
self.fields['data_hora_manual'].widget = forms.HiddenInput() self.fields['data_hora_manual'].widget = forms.HiddenInput()
class ProtocoloMateriaForm(ModelForm): class ProtocoloMateriaForm(ModelForm):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -684,7 +678,6 @@ class TramitacaoAdmForm(ModelForm):
'ip': forms.HiddenInput(), 'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()} 'ultima_edicao': forms.HiddenInput()}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(TramitacaoAdmForm, self).__init__(*args, **kwargs) super(TramitacaoAdmForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date() self.fields['data_tramitacao'].initial = timezone.now().date()
@ -782,8 +775,8 @@ class TramitacaoAdmForm(ModelForm):
anexados_list = lista_anexados(documento, False) anexados_list = lista_anexados(documento, False)
for da in anexados_list: for da in anexados_list:
if not da.tramitacaoadministrativo_set.all() \ if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \ or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
da.tramitacao = False if tramitacao.status.indicador == "F" else True da.tramitacao = False if tramitacao.status.indicador == "F" else True
da.save() da.save()
lista_tramitacao.append(TramitacaoAdministrativo( lista_tramitacao.append(TramitacaoAdministrativo(
@ -805,7 +798,6 @@ class TramitacaoAdmForm(ModelForm):
return tramitacao return tramitacao
# Compara se os campos de duas tramitações são iguais, # Compara se os campos de duas tramitações são iguais,
# exceto os campos id, documento_id e timestamp # exceto os campos id, documento_id e timestamp
def compara_tramitacoes_doc(tramitacao1, tramitacao2): def compara_tramitacoes_doc(tramitacao1, tramitacao2):
@ -813,8 +805,10 @@ def compara_tramitacoes_doc(tramitacao1, tramitacao2):
return False return False
lst_items = ['id', 'documento_id', 'timestamp', 'ultima_edicao'] 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] != '_'))] values = [(k, v) for k, v in tramitacao1.__dict__.items()
other_values = [(k,v) for k,v in tramitacao2.__dict__.items() if (k not in lst_items and k[0] != '_')] 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 return values == other_values
@ -873,12 +867,13 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
'tramitação, pois irá conflitar com a Unidade ' 'tramitação, pois irá conflitar com a Unidade '
'Local da tramitação seguinte') 'Local da tramitação seguinte')
# Se não houve qualquer alteração em um dos dados, mantém o usuário e ip # Se não houve qualquer alteração em um dos dados, mantém o usuário e
if not (cd['data_tramitacao'] != obj.data_tramitacao or \ # ip
cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or \ if not (cd['data_tramitacao'] != obj.data_tramitacao or
cd['status'] != obj.status or cd['texto'] != obj.texto or \ cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or
cd['data_encaminhamento'] != obj.data_encaminhamento or \ cd['status'] != obj.status or cd['texto'] != obj.texto or
cd['data_fim_prazo'] != obj.data_fim_prazo): cd['data_encaminhamento'] != obj.data_encaminhamento or
cd['data_fim_prazo'] != obj.data_fim_prazo):
cd['user'] = obj.user cd['user'] = obj.user
cd['ip'] = obj.ip cd['ip'] = obj.ip
cd['ultima_edicao'] = obj.ultima_edicao cd['ultima_edicao'] = obj.ultima_edicao
@ -888,10 +883,10 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
return cd return cd
@transaction.atomic @transaction.atomic
def save(self, commit=True): def save(self, commit=True):
ant_tram_principal = TramitacaoAdministrativo.objects.get(id=self.instance.id) ant_tram_principal = TramitacaoAdministrativo.objects.get(
id=self.instance.id)
nova_tram_principal = super(TramitacaoAdmEditForm, self).save(commit) nova_tram_principal = super(TramitacaoAdmEditForm, self).save(commit)
documento = nova_tram_principal.documento documento = nova_tram_principal.documento
documento.tramitacao = False if nova_tram_principal.status.indicador == "F" else True documento.tramitacao = False if nova_tram_principal.status.indicador == "F" else True
@ -937,7 +932,7 @@ class AnexadoForm(ModelForm):
ano = forms.CharField(label='Ano', required=True) ano = forms.CharField(label='Ano', required=True)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
return super(AnexadoForm, self).__init__(*args, **kwargs) return super(AnexadoForm, self).__init__(*args, **kwargs)
def clean(self): def clean(self):
super(AnexadoForm, self).clean() super(AnexadoForm, self).clean()
@ -951,8 +946,10 @@ class AnexadoForm(ModelForm):
data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao
if data_anexacao > data_desanexacao: if data_anexacao > data_desanexacao:
self.logger.error("Data de anexação posterior à data de desanexação.") self.logger.error(
raise ValidationError(_("Data de anexação posterior à data de desanexação.")) "Data de anexação posterior à data de desanexação.")
raise ValidationError(
_("Data de anexação posterior à data de desanexação."))
try: try:
self.logger.info( self.logger.info(
"Tentando obter objeto DocumentoAdministrativo (numero={}, ano={}, tipo={})." "Tentando obter objeto DocumentoAdministrativo (numero={}, ano={}, tipo={})."
@ -973,7 +970,8 @@ class AnexadoForm(ModelForm):
documento_principal = self.instance.documento_principal documento_principal = self.instance.documento_principal
if documento_principal == documento_anexado: if documento_principal == documento_anexado:
self.logger.error("O documento não pode ser anexado a si mesmo.") 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")) raise ValidationError(
_("O documento não pode ser anexado a si mesmo"))
is_anexado = Anexado.objects.filter(documento_principal=documento_principal, is_anexado = Anexado.objects.filter(documento_principal=documento_principal,
documento_anexado=documento_anexado documento_anexado=documento_anexado
@ -984,7 +982,8 @@ class AnexadoForm(ModelForm):
raise ValidationError(_('Documento já se encontra anexado')) raise ValidationError(_('Documento já se encontra anexado'))
ciclico = False ciclico = False
anexados_anexado = Anexado.objects.filter(documento_principal=documento_anexado) anexados_anexado = Anexado.objects.filter(
documento_principal=documento_anexado)
while(anexados_anexado and not ciclico): while(anexados_anexado and not ciclico):
anexados = [] anexados = []
@ -1000,8 +999,10 @@ class AnexadoForm(ModelForm):
anexados_anexado = anexados anexados_anexado = anexados
if ciclico: if ciclico:
self.logger.error("O documento não pode ser anexado por um de seus anexados.") self.logger.error(
raise ValidationError(_('O documento não pode ser anexado por um de seus anexados')) "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 cleaned_data['documento_anexado'] = documento_anexado
@ -1037,7 +1038,7 @@ class AnexadoEmLoteFilterSet(django_filters.FilterSet):
self.form.helper.form_method = 'GET' self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout( self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Documentos'), Fieldset(_('Pesquisa de Documentos'),
row1, row2, form_actions(label='Pesquisar')) row1, row2, form_actions(label='Pesquisar'))
) )
@ -1092,7 +1093,7 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
'user': forms.HiddenInput(), 'user': forms.HiddenInput(),
'ip': forms.HiddenInput(), 'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput() 'ultima_edicao': forms.HiddenInput()
} }
def clean(self): def clean(self):
super(DocumentoAdministrativoForm, self).clean() super(DocumentoAdministrativoForm, self).clean()
@ -1109,7 +1110,6 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
tipo_documento = int(self.data['tipo']) tipo_documento = int(self.data['tipo'])
ano_documento = int(self.data['ano']) ano_documento = int(self.data['ano'])
# não permite atualizar para numero/ano/tipo existente # não permite atualizar para numero/ano/tipo existente
if self.instance.pk: if self.instance.pk:
mudanca_doc = numero_documento != self.instance.numero \ mudanca_doc = numero_documento != self.instance.numero \
@ -1198,7 +1198,7 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
row1 = to_row( row1 = to_row(
[('tipo', 3), ('numero', 3),('complemento', 3), ('ano', 3)]) [('tipo', 3), ('numero', 3), ('complemento', 3), ('ano', 3)])
row2 = to_row( row2 = to_row(
[('data', 4), ('numero_protocolo', 4), ('ano_protocolo', 4)]) [('data', 4), ('numero_protocolo', 4), ('ano_protocolo', 4)])
@ -1516,7 +1516,6 @@ class TramitacaoEmLoteAdmForm(ModelForm):
'ip': forms.HiddenInput(), 'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()} 'ultima_edicao': forms.HiddenInput()}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteAdmForm, self).__init__(*args, **kwargs) super(TramitacaoEmLoteAdmForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date() self.fields['data_tramitacao'].initial = timezone.now().date()
@ -1666,8 +1665,8 @@ class TramitacaoEmLoteAdmForm(ModelForm):
anexados = lista_anexados(doc, False) anexados = lista_anexados(doc, False)
for da in anexados: for da in anexados:
if not da.tramitacaoadministrativo_set.all() \ if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \ or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
da.tramitacao = False if tramitacao.status.indicador == "F" else True da.tramitacao = False if tramitacao.status.indicador == "F" else True
da.save() da.save()
lista_tramitacao.append(TramitacaoAdministrativo( lista_tramitacao.append(TramitacaoAdministrativo(

83
sapl/protocoloadm/views.py

@ -1,34 +1,35 @@
from datetime import datetime from datetime import datetime
import logging import logging
import re
from random import choice from random import choice
import re
from string import ascii_letters, digits from string import ascii_letters, digits
from braces.views import FormValidMessageMixin from braces.views import FormValidMessageMixin
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse
from django.db import transaction from django.db import transaction
from django.db.models import Max, Q from django.db.models import Max, Q
from django.http import Http404, HttpResponse, JsonResponse from django.http import Http404, HttpResponse, JsonResponse
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.shortcuts import render
from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, CreateView, UpdateView from django.views.generic import ListView, CreateView, UpdateView
from django.views.generic.base import RedirectView, TemplateView from django.views.generic.base import RedirectView, TemplateView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
from django.contrib.admin.views.decorators import staff_member_required
import sapl import sapl
from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.base.models import Autor, CasaLegislativa, AppConfig from sapl.base.models import Autor, CasaLegislativa, AppConfig
from sapl.base.signals import tramitacao_signal, post_delete_signal from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination, from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination,
RP_LIST, RP_DETAIL) RP_LIST, RP_DETAIL)
@ -41,9 +42,6 @@ from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, lista_anexados, get_mime_type_from_file_extension, lista_anexados,
show_results_filter_set, mail_service_configured, from_date_to_datetime_utc) show_results_filter_set, mail_service_configured, from_date_to_datetime_utc)
from django.shortcuts import render
from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm, from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm,
AnularProtocoloAdmForm, compara_tramitacoes_doc, AnularProtocoloAdmForm, compara_tramitacoes_doc,
DesvincularDocumentoForm, DesvincularMateriaForm, DesvincularDocumentoForm, DesvincularMateriaForm,
@ -367,7 +365,8 @@ class DocumentoAdministrativoCrud(Crud):
return self.search_url return self.search_url
def form_valid(self, form): def form_valid(self, form):
form.instance.complemento = re.sub('\s+', '', form.instance.complemento).upper() form.instance.complemento = re.sub(
'\s+', '', form.instance.complemento).upper()
return super().form_valid(form) return super().form_valid(form)
class UpdateView(Crud.UpdateView): class UpdateView(Crud.UpdateView):
@ -384,7 +383,7 @@ class DocumentoAdministrativoCrud(Crud):
atributos = [ atributos = [
'tipo_id', 'ano', 'numero', 'data', 'protocolo_id', 'assunto', 'tipo_id', 'ano', 'numero', 'data', 'protocolo_id', 'assunto',
'interessado', 'tramitacao', 'restrito', 'texto_integral','numero_externo', 'interessado', 'tramitacao', 'restrito', 'texto_integral', 'numero_externo',
'dias_prazo', 'data_fim_prazo', 'observacao' 'dias_prazo', 'data_fim_prazo', 'observacao'
] ]
@ -399,7 +398,8 @@ class DocumentoAdministrativoCrud(Crud):
self.object.save() self.object.save()
break break
form.instance.complemento = re.sub('\s+', '', form.instance.complemento).upper() form.instance.complemento = re.sub(
'\s+', '', form.instance.complemento).upper()
return super().form_valid(form) return super().form_valid(form)
@ -633,13 +633,14 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
timestamp__isnull=False, timestamp__gte=data_inicio_utc, timestamp__isnull=False, timestamp__gte=data_inicio_utc,
timestamp__lte=data_fim_utc timestamp__lte=data_fim_utc
) | Q( ) | Q(
timestamp_data_hora_manual__isnull=False, timestamp_data_hora_manual__isnull=False,
timestamp_data_hora_manual__gte=data_inicio_utc, timestamp_data_hora_manual__gte=data_inicio_utc,
timestamp_data_hora_manual__lte=data_fim_utc, timestamp_data_hora_manual__lte=data_fim_utc,
) )
).aggregate(Max('numero'))['numero__max'] ).aggregate(Max('numero'))['numero__max']
elif numeracao == 'U': elif numeracao == 'U':
numero_max = Protocolo.objects.all().aggregate(Max('numero'))['numero__max'] numero_max = Protocolo.objects.all().aggregate(Max('numero'))[
'numero__max']
protocolo.tipo_processo = '0' # TODO validar o significado protocolo.tipo_processo = '0' # TODO validar o significado
protocolo.anulado = False protocolo.anulado = False
@ -647,7 +648,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo
numero = int(numero_max) if numero_max else 0 numero = int(numero_max) if numero_max else 0
protocolo.numero = ( protocolo.numero = (
(numero + 1 ) if numero and numero >= inicio_numeracao else inicio_numeracao (numero + 1) if numero and numero >= inicio_numeracao else inicio_numeracao
) )
protocolo.ano = timezone.now().year protocolo.ano = timezone.now().year
@ -849,12 +850,13 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
) )
).aggregate(Max('numero'))['numero__max'] ).aggregate(Max('numero'))['numero__max']
elif numeracao == 'U': elif numeracao == 'U':
numero_max = Protocolo.objects.all().aggregate(Max('numero'))['numero__max'] numero_max = Protocolo.objects.all().aggregate(Max('numero'))[
'numero__max']
inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo
numero = int(numero_max) if numero_max else 0 numero = int(numero_max) if numero_max else 0
protocolo.numero = ( protocolo.numero = (
(numero + 1 ) if numero and numero >= inicio_numeracao else inicio_numeracao (numero + 1) if numero and numero >= inicio_numeracao else inicio_numeracao
) )
protocolo.ano = timezone.now().year protocolo.ano = timezone.now().year
@ -1380,11 +1382,11 @@ class TramitacaoAdmCrud(MasterDetailCrud):
id__in=[t.id for t in tramitacoes_deletar]).delete() id__in=[t.id for t in tramitacoes_deletar]).delete()
# TODO: otimizar para passar a lista de matérias # TODO: otimizar para passar a lista de matérias
for tramitacao in tramitacoes_deletar: # for tramitacao in tramitacoes_deletar:
post_delete_signal.send(sender=None, # post_delete_signal.send(sender=None,
instance=tramitacao, # instance=tramitacao,
operation='C', # operation='C',
request=self.request) # request=self.request)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
@ -1642,8 +1644,8 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
form = TramitacaoEmLoteAdmForm(request.POST, form = TramitacaoEmLoteAdmForm(request.POST,
initial= {'documentos': documentos_ids, initial={'documentos': documentos_ids,
'user': user, 'ip':ip, 'user': user, 'ip': ip,
'ultima_edicao': ultima_edicao}) 'ultima_edicao': ultima_edicao})
if form.is_valid(): if form.is_valid():
@ -1724,10 +1726,10 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
'documento_id', flat=True) 'documento_id', flat=True)
def apaga_protocolos(request, ano,numero_protocolo=None): def apaga_protocolos(request, ano, numero_protocolo=None):
kwargs = {'ano__in':ano} kwargs = {'ano__in': ano}
if numero_protocolo: if numero_protocolo:
kwargs.update({'numero__gte':numero_protocolo}) kwargs.update({'numero__gte': numero_protocolo})
all_protocolos = Protocolo.objects.filter(**kwargs) all_protocolos = Protocolo.objects.filter(**kwargs)
@ -1739,12 +1741,12 @@ def apaga_protocolos(request, ano,numero_protocolo=None):
ml.numero_protocolo = None ml.numero_protocolo = None
ml.save() ml.save()
for deleted_object in all_protocolos: # for deleted_object in all_protocolos:
post_delete_signal.send(sender=None, # post_delete_signal.send(sender=None,
instance=deleted_object, # instance=deleted_object,
operation='D', # operation='D',
request=request # request=request
) # )
all_protocolos.delete() all_protocolos.delete()
@ -1752,10 +1754,11 @@ def apaga_protocolos(request, ano,numero_protocolo=None):
def apaga_protocolos_view(request): def apaga_protocolos_view(request):
if request.method == "GET": if request.method == "GET":
if Protocolo.objects.exists(): if Protocolo.objects.exists():
intervalo_data = Protocolo.objects.all().distinct('ano').values_list('ano', flat=True).order_by('-ano') intervalo_data = Protocolo.objects.all().distinct(
'ano').values_list('ano', flat=True).order_by('-ano')
else: else:
intervalo_data = None intervalo_data = None
return render(request,"protocoloadm/deleta_todos_protocolos.html",{'intervalo_data':intervalo_data}) return render(request, "protocoloadm/deleta_todos_protocolos.html", {'intervalo_data': intervalo_data})
elif request.method == "POST": elif request.method == "POST":
password = request.POST.get('senha') password = request.POST.get('senha')
@ -1763,7 +1766,7 @@ def apaga_protocolos_view(request):
if valid: if valid:
anos = request.POST.getlist('ano') anos = request.POST.getlist('ano')
numero_protocolo = request.POST.get('numero_protocolo') numero_protocolo = request.POST.get('numero_protocolo')
apaga_protocolos(request,anos,numero_protocolo) apaga_protocolos(request, anos, numero_protocolo)
return JsonResponse({'type':'success','msg':''}) return JsonResponse({'type': 'success', 'msg': ''})
else: else:
return JsonResponse({'type':'error','msg':'Senha Incorreta'}) return JsonResponse({'type': 'error', 'msg': 'Senha Incorreta'})

Loading…
Cancel
Save