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
from django.conf import settings
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.utils import timezone
from sapl.base.email_utils import do_envia_email_tramitacao
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.protocoloadm.models import TramitacaoAdministrativo
from sapl.utils import get_base_url
@ -46,28 +48,53 @@ def status_tramitacao_materia(sender, instance, **kwargs):
documento.save()
@receiver(post_delete_signal)
@receiver(post_save_signal)
def audit_log(sender, **kwargs):
logger = logging.getLogger(__name__)
def audit_log_function(sender, **kwargs):
try:
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')
operation = kwargs.get('operation')
user = kwargs.get('request').user
model_name = instance.__class__.__name__
app_name = instance._meta.app_label
object_id = instance.id
data = serializers.serialize('json', [instance])
if instance._meta.model == AuditLog:
return
if len(data) > AuditLog.MAX_DATA_LENGTH:
data = data[:AuditLog.MAX_DATA_LENGTH]
logger = logging.getLogger(__name__)
if user:
username = user.username
else:
username = ''
u = None
pilha_de_execucao = inspect.stack()
for i in pilha_de_execucao:
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:
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,
operation=operation,
model_name=model_name,
@ -78,3 +105,14 @@ def audit_log(sender, **kwargs):
except Exception as e:
logger.error('Error saving auditing log object')
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_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.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 SaplFormHelper
from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
@ -626,37 +625,8 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
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,
FormMessagesMixin, AuditLogMixin, CreateView):
FormMessagesMixin, CreateView):
permission_required = (RP_ADD,)
logger = logging.getLogger(__name__)
@ -874,7 +844,7 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
class CrudUpdateView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, AuditLogMixin, UpdateView):
FormMessagesMixin, UpdateView):
permission_required = (RP_CHANGE,)
logger = logging.getLogger(__name__)
@ -905,7 +875,7 @@ class CrudUpdateView(PermissionRequiredContainerCrudMixin,
class CrudDeleteView(PermissionRequiredContainerCrudMixin,
FormMessagesMixin, AuditLogMixin, DeleteView):
FormMessagesMixin, DeleteView):
permission_required = (RP_DELETE,)
logger = logging.getLogger(__name__)

57
sapl/materia/forms.py

@ -1,30 +1,28 @@
import django_filters
import logging
import os
import sapl
from crispy_forms.bootstrap import Alert, InlineRadios
from crispy_forms.layout import (Button, Field, Fieldset, HTML, Layout, Row)
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.files.base import File
from django.urls import reverse
from django.db import models, transaction
from django.db.models import F, Max, Q
from django.forms import ModelChoiceField, ModelForm, widgets
from django.forms.forms import Form
from django.forms.models import ModelMultipleChoiceField
from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select
from django.urls import reverse
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
import django_filters
import sapl
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.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PRIVATE)
@ -34,7 +32,7 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto,
MateriaLegislativa, Orgao,
RegimeTramitacao, StatusTramitacao,
TipoDocumento, TipoProposicao,
UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa)
UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
from sapl.parlamentares.models import Legislatura, Partido, Parlamentar
@ -211,8 +209,10 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
if protocolo:
if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists():
self.logger.warning("Protocolo %s/%s não existe" % (protocolo, ano))
raise ValidationError(_('Protocolo %s/%s não existe' % (protocolo, ano)))
self.logger.warning(
"Protocolo %s/%s não existe" % (protocolo, ano))
raise ValidationError(
_('Protocolo %s/%s não existe' % (protocolo, ano)))
if protocolo_antigo != protocolo:
exist_materia = MateriaLegislativa.objects.filter(
@ -525,7 +525,8 @@ class TramitacaoForm(ModelForm):
if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.warning('A data de tramitação informada ({}) não é menor ou igual a data de hoje!'
.format(cleaned_data['data_tramitacao']))
msg = _('A data de tramitação deve ser menor ou igual a data de hoje!')
msg = _(
'A data de tramitação deve ser menor ou igual a data de hoje!')
raise ValidationError(msg)
if (ultima_tramitacao and
@ -539,9 +540,10 @@ class TramitacaoForm(ModelForm):
if data_enc_form:
if data_enc_form < data_tram_form:
msg = _('A data de encaminhamento deve ser maior que a data de tramitação!')
msg = _(
'A data de encaminhamento deve ser maior que a data de tramitação!')
self.logger.warning("A data de encaminhamento ({}) deve ser maior que a data de tramitação! ({})"
.format(data_enc_form, data_tram_form))
.format(data_enc_form, data_tram_form))
raise ValidationError(msg)
if data_prazo_form:
@ -669,13 +671,14 @@ class TramitacaoUpdateForm(TramitacaoForm):
'tramitação, pois irá conflitar com a Unidade '
'Local da tramitação seguinte')
if not (cd['data_tramitacao'] != obj.data_tramitacao or \
cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or \
cd['status'] != obj.status or cd['texto'] != obj.texto or \
cd['data_encaminhamento'] != obj.data_encaminhamento or \
cd['data_fim_prazo'] != obj.data_fim_prazo or cd['urgente'] != str(obj.urgente) or \
cd['turno'] != obj.turno):
### Se não ocorreram alterações, o usuário, ip, data e hora da última edição (real) são mantidos
if not (cd['data_tramitacao'] != obj.data_tramitacao or
cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or
cd['status'] != obj.status or cd['texto'] != obj.texto or
cd['data_encaminhamento'] != obj.data_encaminhamento or
cd['data_fim_prazo'] != obj.data_fim_prazo or cd['urgente'] != str(obj.urgente) or
cd['turno'] != obj.turno):
# Se não ocorreram alterações, o usuário, ip, data e hora da última
# edição (real) são mantidos
cd['user'] = obj.user
cd['ip'] = obj.ip
cd['ultima_edicao'] = obj.ultima_edicao
@ -698,7 +701,8 @@ class TramitacaoUpdateForm(TramitacaoForm):
if tramitar_anexadas:
anexadas_list = lista_anexados(materia)
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):
tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
@ -907,7 +911,8 @@ class AnexadaForm(ModelForm):
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.")
self.logger.warning(
"A matéria a ser anexada não existe no cadastro de matérias legislativas.")
raise ValidationError(msg)
materia_principal = self.instance.materia_principal
@ -1118,7 +1123,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
),
Fieldset(_('Origem externa'),
row10, row11
),
),
Fieldset(_('Pesquisa Avançada'),
row3,
HTML(autor_label),
@ -1645,7 +1650,6 @@ class TramitacaoEmLoteForm(ModelForm):
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date()
@ -1746,7 +1750,8 @@ class TramitacaoEmLoteForm(ModelForm):
if data_enc_form < data_tram_form:
self.logger.warning('A data de encaminhamento ({}) deve ser maior que a data de tramitação ({})!'
.format(data_enc_form, data_tram_form))
msg = _('A data de encaminhamento deve ser maior que a data de tramitação!')
msg = _(
'A data de encaminhamento deve ser maior que a data de tramitação!')
raise ValidationError(msg)
if data_prazo_form:
@ -2555,7 +2560,8 @@ class ConfirmarProposicaoForm(ProposicaoForm):
data_fim__year__gte=timezone.now().year).first()
ano_inicio = legislatura.data_inicio.year
ano_fim = legislatura.data_fim.year
nm = Protocolo.objects.filter(ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero'))
nm = Protocolo.objects.filter(
ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero'))
else:
# numeracao == 'U' ou não informada
nm = Protocolo.objects.all().aggregate(Max('numero'))
@ -2923,9 +2929,8 @@ class MateriaPesquisaSimplesForm(forms.Form):
return cleaned_data
class ConfigEtiquetaMateriaLegislativaForms(ModelForm):
class Meta:
model = ConfigEtiquetaMateriaLegislativa
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 logging
import os
import sapl
from random import choice
import shutil
from string import ascii_letters, digits
import tempfile
import weasyprint
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
from io import BytesIO
from PyPDF4 import PdfFileReader, PdfFileMerger
from crispy_forms.layout import HTML
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError
from django.urls import reverse
from django.db.models import Max, Q
from django.http import HttpResponse, JsonResponse
from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.shortcuts import render
from django.template import loader, RequestContext
from django.urls import reverse
from django.utils import formats, timezone
from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView
from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView
from django.shortcuts import render
from django_filters.views import FilterView
import weasyprint
import sapl
from sapl.base.email_utils import do_envia_email_confirmacao
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.compilacao.models import STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE
from sapl.compilacao.views import IntegracaoTaView
@ -51,7 +48,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm
ConfirmarProposicaoForm, DevolverProposicaoForm,
DespachoInicialCreateForm, LegislacaoCitadaForm,
MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm,
TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm,ConfigEtiquetaMateriaLegislativaForms)
TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm, ConfigEtiquetaMateriaLegislativaForms)
from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura
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,
get_client_ip, get_mime_type_from_file_extension, lista_anexados,
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,
AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet,
@ -75,7 +72,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, De
DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao,
Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa)
Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa)
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@ -812,7 +809,8 @@ class ProposicaoCrud(Crud):
elif p.data_envio:
msg_error = _('Proposição já foi enviada.')
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:
if p.texto_articulado.exists():
ta = p.texto_articulado.first()
@ -820,7 +818,8 @@ class ProposicaoCrud(Crud):
ta.editing_locked = True
ta.save()
receber_recibo = BaseAppConfig.attr('receber_recibo_proposicao')
receber_recibo = BaseAppConfig.attr(
'receber_recibo_proposicao')
if not receber_recibo:
ta = p.texto_articulado.first()
@ -830,7 +829,8 @@ class ProposicaoCrud(Crud):
p.data_envio = timezone.now()
p.save()
messages.success(request, _('Proposição enviada com sucesso.'))
messages.success(request, _(
'Proposição enviada com sucesso.'))
try:
self.logger.debug("User={}. Tentando obter número do objeto MateriaLegislativa "
"com atributos tipo={} e ano={}."
@ -845,13 +845,16 @@ class ProposicaoCrud(Crud):
"número que pode não corresponder com a realidade"
.format(p.tipo, numero, p.ano)))
except ValueError as e:
self.logger.warning("User=" + username + ". " + str(e))
self.logger.warning(
"User=" + username + ". " + str(e))
pass
except AttributeError as e:
self.logger.warning("User=" + username + ". " + str(e))
self.logger.warning(
"User=" + username + ". " + str(e))
pass
except TypeError as e:
self.logger.warning("User=" + username + ". " + str(e))
self.logger.warning(
"User=" + username + ". " + str(e))
pass
elif action == 'return':
@ -862,7 +865,8 @@ class ProposicaoCrud(Crud):
elif p.data_recebimento:
self.logger.warning("User={}. Proposição (numero={}) já foi recebida, "
"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:
p.data_envio = None
p.save()
@ -873,7 +877,8 @@ class ProposicaoCrud(Crud):
ta.save()
self.logger.info("User={}. Proposição (numero={}) Retornada com sucesso."
.format(username, p.numero_proposicao))
messages.success(request, _('Proposição Retornada com sucesso.'))
messages.success(request, _(
'Proposição Retornada com sucesso.'))
if msg_error:
messages.error(request, msg_error)
@ -884,7 +889,8 @@ class ProposicaoCrud(Crud):
def dispatch(self, request, *args, **kwargs):
username = request.user.username
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'])
except Exception as e:
self.logger.warning("User={}. Erro ao obter proposicao com pk={}. Retornando 404. {}"
@ -915,7 +921,8 @@ class ProposicaoCrud(Crud):
logger = logging.getLogger(__name__)
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
@ -923,7 +930,8 @@ class ProposicaoCrud(Crud):
if proposicao[0][0] and proposicao[0][1]:
self.logger.warning("User={}. Proposição (id={}) já foi enviada e recebida."
"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]:
self.logger.warning("""\
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)
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
@ -985,7 +994,8 @@ class ProposicaoCrud(Crud):
if proposicao[0][0] and proposicao[0][1]:
self.logger.warning('User={}. Proposição (id={}) já foi enviada e recebida. '
'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]:
self.logger.warning("""\
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:
obj.data_recebimento = 'Não recebida' if obj.data_envio else 'Não enviada'
else:
obj.data_recebimento = timezone.localtime(obj.data_recebimento)
obj.data_recebimento = formats.date_format(obj.data_recebimento, "DATETIME_FORMAT")
obj.data_recebimento = timezone.localtime(
obj.data_recebimento)
obj.data_recebimento = formats.date_format(
obj.data_recebimento, "DATETIME_FORMAT")
if obj.data_envio is None:
obj.data_envio = 'Em elaboração...'
else:
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]
@ -1149,7 +1162,8 @@ class RelatoriaCrud(MasterDetailCrud):
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
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:
localizacao = -1
@ -1353,7 +1367,8 @@ class TramitacaoCrud(MasterDetailCrud):
url = reverse('sapl.materia:tramitacao_list',
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:
username = request.user.username
@ -1373,20 +1388,22 @@ class TramitacaoCrud(MasterDetailCrud):
if tramitar_anexadas:
mat_anexadas = lista_anexados(materia)
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):
tramitacoes_deletar.append(tram_anexada)
if ma.tramitacao_set.count() == 0:
ma.em_tramitacao = False
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
for tramitacao in tramitacoes_deletar:
post_delete_signal.send(sender=None,
instance=tramitacao,
operation='C',
request=self.request)
# for tramitacao in tramitacoes_deletar:
# post_delete_signal.send(sender=None,
# instance=tramitacao,
# operation='C',
# request=self.request)
return HttpResponseRedirect(url)
@ -2164,8 +2181,8 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
if request.FILES['arquivo'].size > MAX_DOC_UPLOAD_SIZE:
msg = _("O arquivo Anexo de Texto Integral deve ser menor que {0:.1f} MB, \
o tamanho atual desse arquivo é {1:.1f} MB" \
.format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (request.FILES['arquivo'].size/1024)/1024))
o tamanho atual desse arquivo é {1:.1f} MB"
.format((MAX_DOC_UPLOAD_SIZE / 1024) / 1024, (request.FILES['arquivo'].size / 1024) / 1024))
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
@ -2356,7 +2373,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteView,
self).get_context_data(**kwargs)
@ -2379,7 +2395,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
context['title'] = _('Primeira Tramitação em Lote')
# Pega somente documentos que não possuem tramitação
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:
context['title'] = _('Tramitação em Lote')
context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
@ -2405,33 +2421,33 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs)
form = TramitacaoEmLoteForm(request.POST,
initial= {'materias': materias_ids,
'user': user, 'ip':ip,
'ultima_edicao': ultima_edicao})
initial={'materias': materias_ids,
'user': user, 'ip': ip,
'ultima_edicao': ultima_edicao})
if form.is_valid():
form.save()
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)
return self.get_success_url()
return self.form_invalid(form)
def get_success_url(self):
return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
def form_invalid(self, form, *args, **kwargs):
for key, erros in form.errors.items():
if not key=='__all__':
[messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
if not key == '__all__':
[messages.add_message(
self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
else:
[messages.add_message(self.request, messages.ERROR, e) for e in erros]
return self.get(self.request, kwargs, {'form':form})
[messages.add_message(self.request, messages.ERROR, e)
for e in erros]
return self.get(self.request, kwargs, {'form': form})
class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
@ -2724,8 +2740,10 @@ def create_zip_docacessorios(materia):
docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs]
if not docs_path:
raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.")
logger.info("Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path))
raise FileNotFoundError(
"Não há arquivos PDF cadastrados em documentos acessorios.")
logger.info(
"Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path))
_zipfile = BytesIO()
@ -2737,7 +2755,8 @@ def create_zip_docacessorios(materia):
logger.error(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()
@ -2748,7 +2767,8 @@ def get_zip_docacessorios(request, pk):
data = None
try:
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:
logger.error("user= {}.Não há arquivos cadastrados".format(username))
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 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:
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"
.format(docs_path))
merged_pdf = '{}/mat_{}_{}_docacessorios.pdf'.format(
@ -2805,7 +2827,8 @@ def create_pdf_docacessorios(materia):
merger.write(data)
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()
@ -2815,7 +2838,8 @@ def get_pdf_docacessorios(request, pk):
username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username
try:
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:
logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg = _('Não há arquivos cadastrados nesses documentos acessórios.')
@ -2824,7 +2848,7 @@ def get_pdf_docacessorios(request, pk):
kwargs={'pk': pk}))
except Exception as e:
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.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
@ -2845,7 +2869,8 @@ def get_pdf_docacessorios(request, pk):
def configEtiquetaMateriaLegislativaCrud(request):
config = ConfigEtiquetaMateriaLegislativa.objects.last()
if request.method == "POST":
form = ConfigEtiquetaMateriaLegislativaForms(request.POST, instance=config)
form = ConfigEtiquetaMateriaLegislativaForms(
request.POST, instance=config)
if form.is_valid():
config = form.save(commit=False)
config.published_date = timezone.now()

95
sapl/protocoloadm/forms.py

@ -1,11 +1,9 @@
import re
import django_filters
import logging
import re
from crispy_forms.bootstrap import InlineRadios, Alert, FormActions
from crispy_forms.layout import (Button, Column, Div, Fieldset, HTML,
Layout, Submit)
from django import forms
from django.core.exceptions import (MultipleObjectsReturned,
ObjectDoesNotExist, ValidationError)
@ -14,9 +12,9 @@ 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.base.signals import post_save_signal
from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper,
SaplFormLayout, to_row)
from sapl.materia.models import (MateriaLegislativa,
@ -176,7 +174,6 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
o = AnoNumeroOrderingFilter(help_text='')
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
fields = ['tipo',
@ -203,14 +200,14 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
row2 = to_row(
[('numero', 5),
('complemento',2),
('complemento', 2),
('ano', 5)])
row3 = to_row(
[('protocolo__numero', 4),
('numero_externo', 4),
('data', 4)
])
])
row4 = to_row(
[('interessado', 6),
@ -224,28 +221,26 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
])
buttons = FormActions(
*[
HTML('''
*[
HTML('''
<div class="form-check">
<input name="relatorio" type="checkbox" class="form-check-input" id="relatorio">
<label class="form-check-label" for="relatorio">Gerar relatório PDF</label>
</div>
''' )
],
''')
],
Submit('pesquisar', _('Pesquisar'), css_class='float-right',
onclick='return true;'),
css_class='form-group row justify-content-between'
,
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,)
row1, row2,
row3, row4,
row5, buttons,)
)
@ -437,7 +432,7 @@ class ProtocoloDocumentoForm(ModelForm):
Fieldset(_('Identificação de Documento'),
row1,
row2),
fieldset,
fieldset,
row4,
row5,
HTML("&nbsp;"),
@ -452,7 +447,6 @@ class ProtocoloDocumentoForm(ModelForm):
self.fields['data_hora_manual'].widget = forms.HiddenInput()
class ProtocoloMateriaForm(ModelForm):
logger = logging.getLogger(__name__)
@ -684,7 +678,6 @@ class TramitacaoAdmForm(ModelForm):
'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()
@ -782,8 +775,8 @@ class TramitacaoAdmForm(ModelForm):
anexados_list = lista_anexados(documento, False)
for da in anexados_list:
if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
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(
@ -805,7 +798,6 @@ class TramitacaoAdmForm(ModelForm):
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):
@ -813,8 +805,10 @@ def compara_tramitacoes_doc(tramitacao1, 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] != '_')]
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
@ -873,12 +867,13 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
'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):
# 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
@ -888,10 +883,10 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
return cd
@transaction.atomic
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)
documento = nova_tram_principal.documento
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)
def __init__(self, *args, **kwargs):
return super(AnexadoForm, self).__init__(*args, **kwargs)
return super(AnexadoForm, self).__init__(*args, **kwargs)
def clean(self):
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
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."))
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={})."
@ -973,7 +970,8 @@ class AnexadoForm(ModelForm):
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"))
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
@ -984,7 +982,8 @@ class AnexadoForm(ModelForm):
raise ValidationError(_('Documento já se encontra anexado'))
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):
anexados = []
@ -1000,8 +999,10 @@ class AnexadoForm(ModelForm):
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'))
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
@ -1037,7 +1038,7 @@ class AnexadoEmLoteFilterSet(django_filters.FilterSet):
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
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(),
'ip': forms.HiddenInput(),
'ultima_edicao': forms.HiddenInput()
}
}
def clean(self):
super(DocumentoAdministrativoForm, self).clean()
@ -1109,7 +1110,6 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
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 \
@ -1198,7 +1198,7 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
def __init__(self, *args, **kwargs):
row1 = to_row(
[('tipo', 3), ('numero', 3),('complemento', 3), ('ano', 3)])
[('tipo', 3), ('numero', 3), ('complemento', 3), ('ano', 3)])
row2 = to_row(
[('data', 4), ('numero_protocolo', 4), ('ano_protocolo', 4)])
@ -1516,7 +1516,6 @@ class TramitacaoEmLoteAdmForm(ModelForm):
'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()
@ -1666,8 +1665,8 @@ class TramitacaoEmLoteAdmForm(ModelForm):
anexados = lista_anexados(doc, False)
for da in anexados:
if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
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(

83
sapl/protocoloadm/views.py

@ -1,34 +1,35 @@
from datetime import datetime
import logging
import re
from random import choice
import re
from string import ascii_letters, digits
from braces.views import FormValidMessageMixin
from django.conf import settings
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.mixins import PermissionRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse
from django.db import transaction
from django.db.models import Max, Q
from django.http import Http404, HttpResponse, JsonResponse
from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect
from django.shortcuts import render
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, CreateView, UpdateView
from django.views.generic.base import RedirectView, TemplateView
from django.views.generic.edit import FormView
from django_filters.views import FilterView
from django.contrib.admin.views.decorators import staff_member_required
import sapl
from sapl.base.email_utils import do_envia_email_confirmacao
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.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination,
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,
show_results_filter_set, mail_service_configured, from_date_to_datetime_utc)
from django.shortcuts import render
from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm,
AnularProtocoloAdmForm, compara_tramitacoes_doc,
DesvincularDocumentoForm, DesvincularMateriaForm,
@ -367,7 +365,8 @@ class DocumentoAdministrativoCrud(Crud):
return self.search_url
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)
class UpdateView(Crud.UpdateView):
@ -384,7 +383,7 @@ class DocumentoAdministrativoCrud(Crud):
atributos = [
'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'
]
@ -399,7 +398,8 @@ class DocumentoAdministrativoCrud(Crud):
self.object.save()
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)
@ -633,13 +633,14 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
timestamp__isnull=False, timestamp__gte=data_inicio_utc,
timestamp__lte=data_fim_utc
) | Q(
timestamp_data_hora_manual__isnull=False,
timestamp_data_hora_manual__gte=data_inicio_utc,
timestamp_data_hora_manual__lte=data_fim_utc,
)
).aggregate(Max('numero'))['numero__max']
timestamp_data_hora_manual__isnull=False,
timestamp_data_hora_manual__gte=data_inicio_utc,
timestamp_data_hora_manual__lte=data_fim_utc,
)
).aggregate(Max('numero'))['numero__max']
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.anulado = False
@ -647,7 +648,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo
numero = int(numero_max) if numero_max else 0
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
@ -849,12 +850,13 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
)
).aggregate(Max('numero'))['numero__max']
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
numero = int(numero_max) if numero_max else 0
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
@ -1380,11 +1382,11 @@ class TramitacaoAdmCrud(MasterDetailCrud):
id__in=[t.id for t in tramitacoes_deletar]).delete()
# TODO: otimizar para passar a lista de matérias
for tramitacao in tramitacoes_deletar:
post_delete_signal.send(sender=None,
instance=tramitacao,
operation='C',
request=self.request)
# for tramitacao in tramitacoes_deletar:
# post_delete_signal.send(sender=None,
# instance=tramitacao,
# operation='C',
# request=self.request)
return HttpResponseRedirect(url)
@ -1642,8 +1644,8 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs)
form = TramitacaoEmLoteAdmForm(request.POST,
initial= {'documentos': documentos_ids,
'user': user, 'ip':ip,
initial={'documentos': documentos_ids,
'user': user, 'ip': ip,
'ultima_edicao': ultima_edicao})
if form.is_valid():
@ -1724,10 +1726,10 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
'documento_id', flat=True)
def apaga_protocolos(request, ano,numero_protocolo=None):
kwargs = {'ano__in':ano}
def apaga_protocolos(request, ano, numero_protocolo=None):
kwargs = {'ano__in': ano}
if numero_protocolo:
kwargs.update({'numero__gte':numero_protocolo})
kwargs.update({'numero__gte': numero_protocolo})
all_protocolos = Protocolo.objects.filter(**kwargs)
@ -1739,12 +1741,12 @@ def apaga_protocolos(request, ano,numero_protocolo=None):
ml.numero_protocolo = None
ml.save()
for deleted_object in all_protocolos:
post_delete_signal.send(sender=None,
instance=deleted_object,
operation='D',
request=request
)
# for deleted_object in all_protocolos:
# post_delete_signal.send(sender=None,
# instance=deleted_object,
# operation='D',
# request=request
# )
all_protocolos.delete()
@ -1752,10 +1754,11 @@ def apaga_protocolos(request, ano,numero_protocolo=None):
def apaga_protocolos_view(request):
if request.method == "GET":
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:
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":
password = request.POST.get('senha')
@ -1763,7 +1766,7 @@ def apaga_protocolos_view(request):
if valid:
anos = request.POST.getlist('ano')
numero_protocolo = request.POST.get('numero_protocolo')
apaga_protocolos(request,anos,numero_protocolo)
return JsonResponse({'type':'success','msg':''})
apaga_protocolos(request, anos, numero_protocolo)
return JsonResponse({'type': 'success', 'msg': ''})
else:
return JsonResponse({'type':'error','msg':'Senha Incorreta'})
return JsonResponse({'type': 'error', 'msg': 'Senha Incorreta'})

Loading…
Cancel
Save