From 0cf7cf7254786cbbe6c97fcfd54035285c55bf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Rodrigues?= Date: Wed, 12 Aug 2020 14:29:01 -0300 Subject: [PATCH] =?UTF-8?q?Fix=20#2987=20-=20N=C3=BAmero=20Inicial=20de=20?= =?UTF-8?q?Protocolo=20(#3019)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Retirar campo de numeração manual - Protocolo Doc * Retirar campo de numeração manual - Protocolo Mat * Fix #2987 * Update sapl/protocoloadm/views.py Co-authored-by: Edward <9326037+edwardoliveira@users.noreply.github.com> * Adiciona correções * Fix migrations * Atualiza cód. commit 658f261 Co-authored-by: Edward <9326037+edwardoliveira@users.noreply.github.com> --- sapl/base/forms.py | 1 + ...40_appconfig_inicio_numeracao_protocolo.py | 20 +++ sapl/base/models.py | 5 + sapl/base/views.py | 59 +++++++- sapl/protocoloadm/forms.py | 26 +--- sapl/protocoloadm/tests/test_protocoloadm.py | 4 +- sapl/protocoloadm/views.py | 131 ++++++++---------- sapl/templates/base/layouts.yaml | 2 +- 8 files changed, 148 insertions(+), 100 deletions(-) create mode 100644 sapl/base/migrations/0040_appconfig_inicio_numeracao_protocolo.py diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 388007bf2..88d4081a4 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -1553,6 +1553,7 @@ class ConfiguracoesAppForm(ModelForm): model = AppConfig fields = ['documentos_administrativos', 'sequencia_numeracao_protocolo', + 'inicio_numeracao_protocolo', 'sequencia_numeracao_proposicao', 'esfera_federacao', # 'painel_aberto', # TODO: a ser implementado na versão 3.2 diff --git a/sapl/base/migrations/0040_appconfig_inicio_numeracao_protocolo.py b/sapl/base/migrations/0040_appconfig_inicio_numeracao_protocolo.py new file mode 100644 index 000000000..43839a8e4 --- /dev/null +++ b/sapl/base/migrations/0040_appconfig_inicio_numeracao_protocolo.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.29 on 2020-05-26 17:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0039_auto_20191202_1114'), + ] + + operations = [ + migrations.AddField( + model_name='appconfig', + name='inicio_numeracao_protocolo', + field=models.PositiveIntegerField(default=1, verbose_name='Início da numeração de protocolo'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index 3c8f2753c..4790e5d0f 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -107,6 +107,11 @@ class AppConfig(models.Model): max_length=1, verbose_name=_('Sequência de numeração de protocolos'), choices=SEQUENCIA_NUMERACAO_PROTOCOLO, default='A') + + inicio_numeracao_protocolo = models.PositiveIntegerField( + verbose_name=_('Início da numeração de protocolo'), + default=1 + ) esfera_federacao = models.CharField( max_length=1, diff --git a/sapl/base/views.py b/sapl/base/views.py index 67222cd6c..b2aa7a0e8 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -56,9 +56,9 @@ from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, Protocol TipoDocumentoAdministrativo) from sapl.sessao.models import (Bancada, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoSessaoPlenaria) -from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, - mail_service_configured, parlamentares_ativos, - SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, num_materias_por_tipo) +from sapl.utils import (from_date_to_datetime_utc, gerar_hash_arquivo, intervalos_tem_intersecao, + mail_service_configured, parlamentares_ativos, SEPARADOR_HASH_PROPOSICAO, + show_results_filter_set, num_materias_por_tipo) from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, @@ -2103,6 +2103,59 @@ class AppConfigCrud(CrudAux): kwargs={'pk': app_config.pk})) + class UpdateView(CrudAux.UpdateView): + + form_class = ConfiguracoesAppForm + + def form_valid(self, form): + numeracao = AppConfig.objects.last().sequencia_numeracao_protocolo + numeracao_antiga = AppConfig.objects.last().inicio_numeracao_protocolo + + self.object = form.save() + numeracao_nova = self.object.inicio_numeracao_protocolo + + if numeracao_nova != numeracao_antiga: + if numeracao == 'A': + numero_max = Protocolo.objects.filter( + ano=timezone.now().year + ).aggregate(Max('numero'))['numero__max'] + elif numeracao == 'L': + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year + ).first() + + data_inicio = legislatura.data_inicio + data_fim = legislatura.data_fim + + data_inicio_utc = from_date_to_datetime_utc(data_inicio) + data_fim_utc = from_date_to_datetime_utc(data_fim) + + numero_max = Protocolo.objects.filter( + Q(data__isnull=False, data__gte=data_inicio, data__lte=data_fim) | + Q( + 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'] + elif numeracao == 'U': + numero_max = Protocolo.objects.all().aggregate( + Max('numero') + )['numero__max'] + + ultimo_numero_cadastrado = int(numero_max) if numero_max else 0 + if numeracao_nova <= ultimo_numero_cadastrado and numeracao != 'U': + msg = "O novo início da numeração de protocolo entrará em vigor na " \ + "próxima sequência, pois já existe protocolo cadastrado com " \ + "número superior ou igual ao número inicial definido." + messages.warning(self.request, msg) + + return super().form_valid(form) + class ListView(CrudAux.ListView): def get(self, request, *args, **kwargs): diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 240d61891..a732aed65 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -343,7 +343,7 @@ class AnularProtocoloAdmForm(ModelForm): *args, **kwargs) -class ProtocoloDocumentForm(ModelForm): +class ProtocoloDocumentoForm(ModelForm): tipo_protocolo = forms.ChoiceField(required=True, label=_('Tipo de Protocolo'), @@ -367,9 +367,6 @@ class ProtocoloDocumentForm(ModelForm): observacao = forms.CharField(required=False, widget=forms.Textarea, label=_('Observação')) - numero = forms.IntegerField( - required=False, label=_('Número de Protocolo (opcional)')) - data_hora_manual = forms.ChoiceField( label=_('Informar data e hora manualmente?'), widget=forms.RadioSelect(), @@ -384,7 +381,6 @@ class ProtocoloDocumentForm(ModelForm): 'assunto', 'interessado', 'observacao', - 'numero', 'data', 'hora', ] @@ -426,8 +422,6 @@ class ProtocoloDocumentForm(ModelForm): [('interessado', 12)]) row6 = to_row( [('observacao', 12)]) - row7 = to_row( - [('numero', 12)]) fieldset = Fieldset(_('Protocolo com data e hora informados manualmente'), row3, @@ -447,14 +441,11 @@ class ProtocoloDocumentForm(ModelForm): row4, row5, HTML(" "), - Fieldset(_('Número do Protocolo (Apenas se quiser que a numeração comece ' - 'a partir do número a ser informado)'), - row7, - HTML(" "), + Fieldset(HTML(" "), form_actions(label=_('Protocolar Documento')) ) ) - super(ProtocoloDocumentForm, self).__init__( + super(ProtocoloDocumentoForm, self).__init__( *args, **kwargs) if not config.protocolo_manual: @@ -503,9 +494,6 @@ class ProtocoloMateriaForm(ModelForm): assunto_ementa = forms.CharField(required=True, widget=forms.Textarea, label=_('Ementa')) - numero = forms.IntegerField( - required=False, label=_('Número de Protocolo (opcional)')) - data_hora_manual = forms.ChoiceField( label=_('Informar data e hora manualmente?'), widget=forms.RadioSelect(), @@ -523,7 +511,6 @@ class ProtocoloMateriaForm(ModelForm): 'numero_materia', 'ano_materia', 'vincular_materia', - 'numero', 'data', 'hora', ] @@ -616,8 +603,6 @@ class ProtocoloMateriaForm(ModelForm): [('assunto_ementa', 12)]) row5 = to_row( [('observacao', 12)]) - row6 = to_row( - [('numero', 12)]) fieldset = Fieldset(_('Protocolo com data e hora informados manualmente'), row3, @@ -637,10 +622,7 @@ class ProtocoloMateriaForm(ModelForm): row4, row5, HTML(" "), - Fieldset(_('Número do Protocolo (Apenas se quiser que a numeração comece' - ' a partir do número a ser informado)'), - row6, - HTML(" "), + Fieldset(HTML(" "), form_actions(label=_('Protocolar Matéria'))) ) diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index 1e0ab091b..0857a3d47 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -13,7 +13,7 @@ from sapl.comissoes.models import Comissao, TipoComissao from sapl.materia.models import UnidadeTramitacao from sapl.protocoloadm.forms import (AnularProtocoloAdmForm, DocumentoAdministrativoForm, - MateriaLegislativa, ProtocoloDocumentForm, + MateriaLegislativa, ProtocoloDocumentoForm, ProtocoloMateriaForm, TramitacaoAdmForm, TramitacaoAdmEditForm, compara_tramitacoes_doc, @@ -415,7 +415,7 @@ def test_protocolo_documento_form_invalido(): config = baker.make(AppConfig) - form = ProtocoloDocumentForm( + form = ProtocoloDocumentoForm( data={}, initial={ 'user_data_hora_manual': '', diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 83091c6b9..026b5528f 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -44,23 +44,19 @@ from sapl.utils import (create_barcode, get_base_url, get_client_ip, from django.shortcuts import render -from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm, - DocumentoAcessorioAdministrativoForm, - DocumentoAdministrativoFilterSet, - DocumentoAdministrativoForm, FichaPesquisaAdmForm, FichaSelecionaAdmForm, ProtocoloDocumentForm, - ProtocoloFilterSet, ProtocoloMateriaForm, - TramitacaoAdmEditForm, TramitacaoAdmForm, +from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm, + AnularProtocoloAdmForm, compara_tramitacoes_doc, DesvincularDocumentoForm, DesvincularMateriaForm, - filtra_tramitacao_adm_destino_and_status, - filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status, - AnexadoForm, AnexadoEmLoteFilterSet, - PrimeiraTramitacaoEmLoteAdmFilterSet, - TramitacaoEmLoteAdmForm, - TramitacaoEmLoteAdmFilterSet, - compara_tramitacoes_doc) -from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, + DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, + DocumentoAdministrativoForm, FichaPesquisaAdmForm, FichaSelecionaAdmForm, + filtra_tramitacao_adm_destino, filtra_tramitacao_adm_destino_and_status, + filtra_tramitacao_adm_status, PrimeiraTramitacaoEmLoteAdmFilterSet, + ProtocoloDocumentoForm, ProtocoloFilterSet, ProtocoloMateriaForm, + TramitacaoAdmEditForm, TramitacaoAdmForm, TramitacaoEmLoteAdmForm, + TramitacaoEmLoteAdmFilterSet) +from .models import (Anexado, AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, - TipoDocumentoAdministrativo, TramitacaoAdministrativo, Anexado) + TipoDocumentoAdministrativo, TramitacaoAdministrativo) TipoDocumentoAdministrativoCrud = CrudAux.build( @@ -582,7 +578,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, logger = logging.getLogger(__name__) template_name = "protocoloadm/protocolar_documento.html" - form_class = ProtocoloDocumentForm + form_class = ProtocoloDocumentoForm form_valid_message = _('Protocolo cadastrado com sucesso!') permission_required = ('protocoloadm.add_protocolo', ) @@ -617,12 +613,14 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, return self.render_to_response(self.get_context_data()) if numeracao == 'A': - numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + numero_max = Protocolo.objects.filter(ano=timezone.now().year).aggregate( + Max('numero') + )['numero__max'] elif numeracao == 'L': legislatura = Legislatura.objects.filter( data_inicio__year__lte=timezone.now().year, - data_fim__year__gte=timezone.now().year).first() + data_fim__year__gte=timezone.now().year + ).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim @@ -630,32 +628,28 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, data_inicio_utc = from_date_to_datetime_utc(data_inicio) data_fim_utc = from_date_to_datetime_utc(data_fim) - numero = Protocolo.objects.filter( - Q(data__isnull=False, - data__gte=data_inicio, - data__lte=data_fim) | - Q(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 = Protocolo.objects.filter( + Q(data__isnull=False, data__gte=data_inicio, data__lte=data_fim) | Q( + 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'] elif numeracao == 'U': - numero = Protocolo.objects.all().aggregate(Max('numero')) + numero_max = Protocolo.objects.all().aggregate(Max('numero'))['numero__max'] protocolo.tipo_processo = '0' # TODO validar o significado protocolo.anulado = False - if not protocolo.numero: - protocolo.numero = ( - numero['numero__max'] + 1) if numero['numero__max'] else 1 - elif protocolo.numero < (numero['numero__max'] + 1) if numero['numero__max'] else 0: - msg = _('Número de protocolo deve ser maior que {}'.format( - numero['numero__max'])) - self.logger.error( - "user=" + username + ". Número de protocolo deve ser maior que {}.".format(numero['numero__max'])) - messages.add_message(self.request, messages.ERROR, msg) - return self.render_to_response(self.get_context_data()) + + 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 + ) + protocolo.ano = timezone.now().year protocolo.assunto_ementa = self.request.POST['assunto'] @@ -829,47 +823,40 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): return self.render_to_response(self.get_context_data()) if numeracao == 'A': - numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + numero_max = Protocolo.objects.filter(ano=timezone.now().year).aggregate( + Max('numero') + )['numero__max'] elif numeracao == 'L': legislatura = Legislatura.objects.filter( data_inicio__year__lte=timezone.now().year, - data_fim__year__gte=timezone.now().year).first() + data_fim__year__gte=timezone.now().year + ).first() + data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim data_inicio_utc = from_date_to_datetime_utc(data_inicio) data_fim_utc = from_date_to_datetime_utc(data_fim) - numero = Protocolo.objects.filter( - Q(data__isnull=False, - data__gte=data_inicio, - data__lte=data_fim) | - Q(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 = Protocolo.objects.filter( + Q(data__isnull=False, data__gte=data_inicio, data__lte=data_fim) | Q( + 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'] elif numeracao == 'U': - numero = Protocolo.objects.all().aggregate(Max('numero')) - - if numeracao is None: - numero['numero__max'] = 0 - - if not protocolo.numero: - protocolo.numero = ( - numero['numero__max'] + 1) if numero['numero__max'] else 1 - if numero['numero__max']: - if protocolo.numero < (numero['numero__max'] + 1): - self.logger.error("user=" + username + ". Número de protocolo ({}) é menor que {}" - .format(protocolo.numero, numero['numero__max'])) - msg = _('Número de protocolo deve ser maior que {}'.format( - numero['numero__max'])) - messages.add_message(self.request, messages.ERROR, msg) - return self.render_to_response(self.get_context_data()) + 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 + ) + protocolo.ano = timezone.now().year protocolo.tipo_protocolo = 0 diff --git a/sapl/templates/base/layouts.yaml b/sapl/templates/base/layouts.yaml index b3b0daca0..79d84c4c1 100644 --- a/sapl/templates/base/layouts.yaml +++ b/sapl/templates/base/layouts.yaml @@ -18,7 +18,7 @@ AppConfig: - esfera_federacao {% trans 'Proposições e Protocolo' %}: - - sequencia_numeracao_proposicao sequencia_numeracao_protocolo + - sequencia_numeracao_proposicao sequencia_numeracao_protocolo inicio_numeracao_protocolo - protocolo_manual receber_recibo_proposicao - proposicao_incorporacao_obrigatoria escolher_numero_materia_proposicao