From 5062de933569de11dc95a6e4bd2605223ef05f45 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Wed, 3 Jul 2019 13:39:44 -0300 Subject: [PATCH] =?UTF-8?q?Refatora=20Tramita=C3=A7=C3=A3o=20em=20Lote=20u?= =?UTF-8?q?sando=20Forms=20(#2863)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/materia/forms.py | 197 ++++++++++++++++++ sapl/materia/views.py | 171 ++++----------- sapl/protocoloadm/views.py | 2 +- .../templates/materia/em_lote/tramitacao.html | 140 ++----------- 4 files changed, 256 insertions(+), 254 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 417352b1d..38f3b0182 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1511,6 +1511,203 @@ class TipoProposicaoSelect(Select): return option +class TramitacaoEmLoteForm(ModelForm): + logger = logging.getLogger(__name__) + + class Meta: + model = Tramitacao + fields = ['data_tramitacao', + 'unidade_tramitacao_local', + 'status', + 'urgente', + 'turno', + 'unidade_tramitacao_destino', + 'data_encaminhamento', + 'data_fim_prazo', + 'texto', + 'user', + 'ip'] + widgets = {'user': forms.HiddenInput(), + 'ip': forms.HiddenInput()} + + + def __init__(self, *args, **kwargs): + super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs) + self.fields['data_tramitacao'].initial = timezone.now().date() + ust = UnidadeTramitacao.objects.select_related().all() + unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut) + for ut in ust if ut.comissao and ut.comissao.ativa] + unidade_tramitacao_destino.extend( + [(ut.pk, ut) for ut in ust if ut.orgao]) + unidade_tramitacao_destino.extend( + [(ut.pk, ut) for ut in ust if ut.parlamentar]) + self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino + self.fields['urgente'].label = "Urgente? *" + + row1 = to_row([ + ('data_tramitacao', 4), + ('data_encaminhamento', 4), + ('data_fim_prazo', 4) + ]) + row2 = to_row([ + ('unidade_tramitacao_local', 6), + ('unidade_tramitacao_destino', 6), + ]) + row3 = to_row([ + ('status', 4), + ('urgente', 4), + ('turno', 4) + ]) + row4 = to_row([ + ('texto', 12) + ]) + + documentos_checkbox_HTML = ''' + +
+ Selecione as matérias para tramitação: + +
+
+ +
+
+ + + + + {% for materia in object_list %} + + + + {% endfor %} + +
Matéria
+ + + {{materia.tipo.sigla}} {{materia.tipo.descricao}} {{materia.numero}}/{{materia.ano}} + +
+
+ ''' + + self.helper = SaplFormHelper() + self.helper.layout = Layout( + Fieldset( + 'Detalhes da tramitação:', + row1, row2, row3, row4, + HTML(documentos_checkbox_HTML), + form_actions(label='Salvar') + ) + ) + + + def clean(self): + cleaned_data = super(TramitacaoEmLoteForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + if 'data_encaminhamento' in cleaned_data: + data_enc_form = cleaned_data['data_encaminhamento'] + if 'data_fim_prazo' in cleaned_data: + data_prazo_form = cleaned_data['data_fim_prazo'] + if 'data_tramitacao' in cleaned_data: + data_tram_form = cleaned_data['data_tramitacao'] + + if not self.instance.data_tramitacao: + + if cleaned_data['data_tramitacao'] > timezone.now().date(): + self.logger.error('A data de tramitação ({}) deve ser ' + 'menor ou igual a data de hoje ({})!' + .format(cleaned_data['data_tramitacao'], timezone.now().date())) + msg = _( + 'A data de tramitação deve ser ' + + 'menor ou igual a data de hoje!') + raise ValidationError(msg) + + if data_enc_form: + if data_enc_form < data_tram_form: + self.logger.error('A data de encaminhamento ({}) deve ser ' + 'maior que a data de tramitação ({})!' + .format(data_enc_form, data_tram_form)) + msg = _('A data de encaminhamento deve ser ' + + 'maior que a data de tramitação!') + raise ValidationError(msg) + + if data_prazo_form: + if data_prazo_form < data_tram_form: + self.logger.error('A data fim de prazo ({}) deve ser ' + 'maior que a data de tramitação ({})!' + .format(data_prazo_form, data_tram_form)) + msg = _('A data fim de prazo deve ser ' + + 'maior que a data de tramitação!') + raise ValidationError(msg) + + if cleaned_data['unidade_tramitacao_local'] == cleaned_data['unidade_tramitacao_destino']: + msg = _('Unidade tramitação local deve ser diferente da unidade tramitação destino.') + self.logger.error('Unidade tramitação local ({}) deve ser diferente da unidade tramitação destino' + .format(cleaned_data['unidade_tramitacao_local'])) + raise ValidationError(msg) + + return cleaned_data + + @transaction.atomic + def save(self, commit=True): + cd = self.cleaned_data + materias = self.initial['materias'] + user = self.initial['user'] if 'user' in self.initial else None + ip = self.initial['ip'] if 'ip' in self.initial else '' + tramitar_anexadas = AppConfig.attr('tramitacao_materia') + for mat_id in materias: + mat = MateriaLegislativa.objects.get(id=mat_id) + tramitacao = Tramitacao.objects.create( + status=cd['status'], + materia=mat, + data_tramitacao=cd['data_tramitacao'], + unidade_tramitacao_local=cd['unidade_tramitacao_local'], + unidade_tramitacao_destino=cd['unidade_tramitacao_destino'], + data_encaminhamento=cd['data_encaminhamento'], + urgente=cd['urgente'], + turno=cd['turno'], + texto=cd['texto'], + data_fim_prazo=cd['data_fim_prazo'], + user=user, + ip=ip + ) + mat.em_tramitacao = False if tramitacao.status.indicador == "F" else True + mat.save() + + if tramitar_anexadas: + lista_tramitacao = [] + anexadas = lista_anexados(mat) + for ml in anexadas: + if not ml.tramitacao_set.all() \ + or ml.tramitacao_set.last() \ + .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: + ml.em_tramitacao = False if tramitacao.status.indicador == "F" else True + ml.save() + lista_tramitacao.append(Tramitacao( + status=tramitacao.status, + materia=ml, + data_tramitacao=tramitacao.data_tramitacao, + unidade_tramitacao_local=tramitacao.unidade_tramitacao_local, + data_encaminhamento=tramitacao.data_encaminhamento, + unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino, + urgente=tramitacao.urgente, + turno=tramitacao.turno, + texto=tramitacao.texto, + data_fim_prazo=tramitacao.data_fim_prazo, + user=tramitacao.user, + ip=tramitacao.ip + )) + Tramitacao.objects.bulk_create(lista_tramitacao) + + return tramitacao + + class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm): logger = logging.getLogger(__name__) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 739f4c486..7e64c6dd0 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -69,7 +69,8 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, filtra_tramitacao_status, - ExcluirTramitacaoEmLote, compara_tramitacoes_mat) + ExcluirTramitacaoEmLote, compara_tramitacoes_mat, + TramitacaoEmLoteForm) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -2254,39 +2255,34 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): logger = logging.getLogger(__name__) + def get_context_data(self, **kwargs): context = super(PrimeiraTramitacaoEmLoteView, self).get_context_data(**kwargs) context['subnav_template_name'] = 'materia/em_lote/subnav_em_lote.yaml' + context['primeira_tramitacao'] = self.primeira_tramitacao # Verifica se os campos foram preenchidos if not self.filterset.form.is_valid(): return context - context['title'] = _('Primeira Tramitação em Lote') - + context['object_list'] = context['object_list'].order_by( + 'ano', 'numero') qr = self.request.GET.copy() - context['unidade_destino'] = UnidadeTramitacao.objects.all() - context['status_tramitacao'] = StatusTramitacao.objects.all() - context['turnos_tramitacao'] = Tramitacao.TURNO_CHOICES - context['urgente_tramitacao'] = YES_NO_CHOICES - context['unidade_local'] = UnidadeTramitacao.objects.all() - context['primeira_tramitacao'] = True + form = TramitacaoEmLoteForm() + context['form'] = form - # Pega somente matéria que não possuem tramitação - if (type(self.__dict__['filterset']).__name__ == - 'PrimeiraTramitacaoEmLoteFilterSet'): - context['object_list'] = context['object_list'].filter( - tramitacao__isnull=True) + if self.primeira_tramitacao: + 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.all().count() == 0] else: context['title'] = _('Tramitação em Lote') - context['unidade_local'] = [UnidadeTramitacao.objects.get( - id=qr['tramitacao__unidade_tramitacao_destino'])] - - context['object_list'] = context['object_list'].order_by( - 'ano', 'numero') + context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get( + id=qr['tramitacao__unidade_tramitacao_destino']) context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' @@ -2295,127 +2291,42 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): return context def post(self, request, *args, **kwargs): + user = request.user + ip = get_client_ip(request) - marcadas = request.POST.getlist('materia_id') - - tz = timezone.get_current_timezone() - - username = request.user.username - - if len(marcadas) == 0: - msg = _('Nenhuma máteria foi selecionada.') + materias_ids = request.POST.getlist('materias') + if not materias_ids: + msg = _("Escolha alguma matéria para ser tramitada.") messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - obrigatorios = {'data_tramitacao': 'Data da Tramitação', - 'unidade_tramitacao_local': 'Unidade Local', - 'unidade_tramitacao_destino': 'Unidade Destino', - 'status': 'Status', - 'urgente': 'Urgente', - 'texto': 'Texto da Ação'} - for field, nome in obrigatorios.items(): - if not request.POST[field]: - msg = _('Campo {} deve ser preenchido.'.format(nome)) - messages.add_message(request, messages.ERROR, msg) - return self.get(request, self.kwargs) - if not request.POST['data_encaminhamento']: - data_encaminhamento = None - else: - try: - data_encaminhamento = tz.localize(datetime.strptime( - request.POST['data_encaminhamento'], "%d/%m/%Y")) - except ValueError: - msg = _('Formato da data de encaminhamento incorreto.') - messages.add_message(request, messages.ERROR, msg) - return self.get(request, self.kwargs) + form = TramitacaoEmLoteForm(request.POST, + initial= {'materias': materias_ids, + 'user': user, 'ip':ip}) - if request.POST['data_fim_prazo'] == '': - data_fim_prazo = None - else: - try: - data_fim_prazo = tz.localize(datetime.strptime( - request.POST['data_fim_prazo'], "%d/%m/%Y")) - except ValueError: - msg = _('Formato da data fim do prazo incorreto.') - messages.add_message(request, messages.ERROR, msg) - return self.get(request, self.kwargs) + if form.is_valid(): + form.save() - # issue https://github.com/interlegis/sapl/issues/1123 - # TODO: usar Form - urgente = request.POST['urgente'] == 'True' - flag_error = False + msg = _('Tramitação completa.') + self.logger.info('user=' + user.username + '. Tramitação completa.') + messages.add_message(request, messages.SUCCESS, msg) + return self.get_success_url() - materias_principais = [m for m in MateriaLegislativa.objects.filter(id__in=marcadas)] - tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia') - materias_anexadas = [] - if tramitar_anexadas: - for materia in materias_principais: - materias_anexadas = materias_anexadas + lista_anexados(materia) + return self.form_invalid(form) - materias = set(materias_principais + materias_anexadas) + + def get_success_url(self): + return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote')) - for materia in materias: - try: - data_tramitacao = tz.localize(datetime.strptime( - request.POST['data_tramitacao'], "%d/%m/%Y")) - except ValueError: - msg = _('Formato da data da tramitação incorreto.') - messages.add_message(request, messages.ERROR, msg) - return self.get(request, self.kwargs) - user = request.user - ip = get_client_ip(request) - t = Tramitacao( - materia=materia, - data_tramitacao=data_tramitacao, - data_encaminhamento=data_encaminhamento, - data_fim_prazo=data_fim_prazo, - unidade_tramitacao_local_id=request.POST[ - 'unidade_tramitacao_local'], - unidade_tramitacao_destino_id=request.POST[ - 'unidade_tramitacao_destino'], - urgente=urgente, - status_id=request.POST['status'], - turno=request.POST['turno'], - texto=request.POST['texto'], - user=user, - ip=ip - ) - t.save() - try: - self.logger.debug("user=" + username + - ". Tentando enviar tramitação.") - tramitacao_signal.send(sender=Tramitacao, - post=t, - request=self.request) + 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] + else: + [messages.add_message(self.request, messages.ERROR, e) for e in erros] + return self.get(self.request, kwargs, {'form':form}) - except Exception as e: - self.logger.error('user=' + username + '. Tramitação criada , mas e-mail de acompanhamento ' - 'de matéria não enviado. Há problemas na configuração ' - 'do e-mail. ' + str(e)) - flag_error = True - if flag_error: - msg = _('Tramitação criada, mas e-mail de acompanhamento ' - 'de matéria não enviado. A não configuração do servidor de e-mail ' - 'impede o envio de aviso de tramitação') - messages.add_message(self.request, messages.WARNING, msg) - - status = StatusTramitacao.objects.get(id=request.POST['status']) - - for materia in materias: - if status.indicador == 'F': - materia.em_tramitacao = False - elif self.primeira_tramitacao: - materia.em_tramitacao = True - materia.save() - - msg = _('Tramitação completa. ' + "Foram tramitadas " + str(len(materias)) + " matéria(s).") - self.logger.info('user=' + username + '. Tramitação completa.') - messages.add_message(request, messages.SUCCESS, msg) - - if self.primeira_tramitacao: - return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote')) - return HttpResponseRedirect(reverse('sapl.materia:tramitacao_em_lote')) class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView): filterset_class = TramitacaoEmLoteFilterSet @@ -2428,7 +2339,7 @@ class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView): qr = self.request.GET.copy() - context['primeira_tramitacao'] = False + context['primeira_tramitacao'] = self.primeira_tramitacao if ('tramitacao__status' in qr and 'tramitacao__unidade_tramitacao_destino' in qr and diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index b5af92621..775cb13f8 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -1545,7 +1545,7 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView): qr = self.request.GET.copy() - context['primeira_tramitacao'] = False + context['primeira_tramitacao'] = self.primeira_tramitacao if ('tramitacao__status' in qr and 'tramitacao__unidade_tramitacao_destino' in qr and diff --git a/sapl/templates/materia/em_lote/tramitacao.html b/sapl/templates/materia/em_lote/tramitacao.html index 5cc4a0b90..1c68274e6 100644 --- a/sapl/templates/materia/em_lote/tramitacao.html +++ b/sapl/templates/materia/em_lote/tramitacao.html @@ -1,134 +1,28 @@ {% extends "crud/detail.html" %} {% load i18n crispy_forms_tags %} -{% block actions %}{% endblock %} {% block detail_content %} - {% if not show_results %} - {% crispy filter.form %} - {% endif %} - - {% if show_results %} - {% if object_list|length > 0 %} - {% if object_list|length == 1 %} -

{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}

- {% else %} -

Foram encontradas {{object_list|length}} matérias.

- {% endif %} -
- {% csrf_token %} -
- 1. Detalhes da tramitação: - -
-
- - -
- -
- - -
- -
- - -
-
- -
-
- - -
- -
- - -
-
- -
-
- - -
- -
- - -
- -
- - -
-
- -
-
- - -
-
-
- -


- -
- 2. Selecione as matérias para tramitação: - -
-
- -
-
- - - - - {% for materia in object_list %} - - - - - {% endfor %} - -
Matéria
- - - {{materia.tipo.sigla}} {{materia.tipo.descricao}} {{materia.numero}}/{{materia.ano}} - -
-
- -
+ {% if not show_results %} + {% crispy filter.form %} {% else %} -

Nenhuma matéria encontrada.

- {% endif %} - {% endif %} + {% if object_list|length > 0 %} + {% if object_list|length == 1 %} +

{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}

+ {% else %} +

Foram encontradas {{object_list|length}} matérias.

+ {% endif %} + {% crispy form %} + {% else %} +

Nenhuma matéria encontrada.

+ {% endif %} + + {% endif%} {% endblock detail_content %} + {% block extra_js %}