From c2c70134945a45739bd910463c6e24409c9b1075 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Mon, 13 May 2019 09:23:10 -0300 Subject: [PATCH] =?UTF-8?q?Fix=20#2763=20-=20Edita=20e=20remove=20tramitac?= =?UTF-8?q?=C3=B5es=20anexadas=20se=20poss=C3=ADvel=20(#2765)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #2763 * Adiciona testes de tramitação --- sapl/materia/forms.py | 58 +++-- sapl/materia/tests/test_materia.py | 185 +++++++++++++- sapl/materia/views.py | 26 +- sapl/protocoloadm/forms.py | 53 +++- sapl/protocoloadm/tests/test_protocoloadm.py | 252 ++++++++++++++++++- sapl/protocoloadm/views.py | 24 +- sapl/utils.py | 28 ++- 7 files changed, 585 insertions(+), 41 deletions(-) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 831d062cd..0b8a0e451 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -38,14 +38,15 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura, Partido, Parlamentar -from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo +from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo, Anexado from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.utils import (YES_NO_CHOICES, SEPARADOR_HASH_PROPOSICAO, ChoiceWithoutValidationField, MateriaPesquisaOrderingFilter, RangeWidgetOverride, autor_label, autor_modal, gerar_hash_arquivo, models_with_gr_for_model, qs_override_django_filter, - choice_anos_com_materias, FilterOverridesMetaMixin, FileFieldCheckMixin) + choice_anos_com_materias, FilterOverridesMetaMixin, FileFieldCheckMixin, + lista_anexados) from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, DocumentoAcessorio, Numeracao, Proposicao, Relatoria, @@ -555,8 +556,10 @@ class TramitacaoForm(ModelForm): materia = tramitacao.materia materia.em_tramitacao = False if tramitacao.status.indicador == "F" else True materia.save() + lista_tramitacao = [] - for ma in materia.anexadas.all(): + lista_anexadas = lista_anexados(materia) + for ma in lista_anexadas: if not ma.tramitacao_set.all() \ or ma.tramitacao_set.last().unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: ma.em_tramitacao = False if tramitacao.status.indicador == "F" else True @@ -580,19 +583,16 @@ class TramitacaoForm(ModelForm): return tramitacao -def lista_anexadas(materia_principal): - materias_anexadas = [] - anexadas_principal = Anexada.objects.filter(materia_principal=materia_principal) - while anexadas_principal: - anexadas = [] - for anexada in anexadas_principal: - materias_anexadas.append(anexada.materia_anexada) - anexadas_anexada = Anexada.objects.filter(materia_principal=anexada.materia_anexada) - anexadas.extend(anexadas_anexada) - anexadas_principal = anexadas - - return materias_anexadas +# Compara se os campos de duas tramitações são iguais, +# exceto os campos id, documento_id e timestamp +def compara_tramitacoes_mat(tramitacao1, tramitacao2): + if not tramitacao1 or not tramitacao2: + return False + lst_items = ['id', 'materia_id', 'timestamp'] + values = [(k,v) for k,v in tramitacao1.__dict__.items() if ((k not in lst_items) and (k[0] != '_'))] + other_values = [(k,v) for k,v in tramitacao2.__dict__.items() if (k not in lst_items and k[0] != '_')] + return values == other_values class TramitacaoUpdateForm(TramitacaoForm): unidade_tramitacao_local = forms.ModelChoiceField( @@ -670,6 +670,34 @@ class TramitacaoUpdateForm(TramitacaoForm): return cd + @transaction.atomic + def save(self, commit=True): + ant_tram_principal = Tramitacao.objects.get(id=self.instance.id) + nova_tram_principal = super(TramitacaoUpdateForm, self).save(commit) + materia = nova_tram_principal.materia + materia.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True + materia.save() + + lista_anexadas = lista_anexados(materia) + for ma in lista_anexadas: + tram_anexada = ma.tramitacao_set.last() + 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 + tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local + tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento + tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino + tram_anexada.urgente = nova_tram_principal.urgente + tram_anexada.turno = nova_tram_principal.turno + tram_anexada.texto = nova_tram_principal.texto + tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo + tram_anexada.user = nova_tram_principal.user + tram_anexada.ip = nova_tram_principal.ip + tram_anexada.save() + + ma.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True + ma.save() + return nova_tram_principal class LegislacaoCitadaForm(ModelForm): diff --git a/sapl/materia/tests/test_materia.py b/sapl/materia/tests/test_materia.py index 048d528c5..1938d04f4 100644 --- a/sapl/materia/tests/test_materia.py +++ b/sapl/materia/tests/test_materia.py @@ -1,3 +1,4 @@ +from datetime import date from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile @@ -14,15 +15,16 @@ from sapl.materia.models import (Anexada, Autoria, DespachoInicial, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, TipoProposicao, Tramitacao, UnidadeTramitacao) -from sapl.materia.forms import lista_anexadas +from sapl.materia.forms import (TramitacaoForm, compara_tramitacoes_mat, + TramitacaoUpdateForm) from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura -from sapl.utils import models_with_gr_for_model +from sapl.utils import models_with_gr_for_model, lista_anexados @pytest.mark.django_db(transaction=False) -def test_lista_anexadas(): +def test_lista_materias_anexadas(): tipo_materia = mommy.make( TipoMateriaLegislativa, descricao="Tipo_Teste" @@ -69,7 +71,7 @@ def test_lista_anexadas(): data_anexacao="2020-11-05" ) - lista = lista_anexadas(materia_principal) + lista = lista_anexados(materia_principal) assert len(lista) == 2 assert lista[0] == materia_anexada @@ -637,3 +639,178 @@ def test_numeracao_materia_legislativa_por_ano(admin_client): response_content = eval(response.content.decode('ascii')) esperado_outro_ano = eval('{"ano": "2010", "numero": 1}') assert response_content['numero'] == esperado_outro_ano['numero'] + + +@pytest.mark.django_db(transaction=False) +def test_tramitacoes_materias_anexadas(admin_client): + tipo_materia = mommy.make( + TipoMateriaLegislativa, + descricao="Tipo_Teste" + ) + materia_principal = mommy.make( + MateriaLegislativa, + ano=2018, + data_apresentacao="2018-01-04", + tipo=tipo_materia + ) + materia_anexada = mommy.make( + MateriaLegislativa, + ano=2019, + data_apresentacao="2019-05-04", + tipo=tipo_materia + ) + materia_anexada_anexada = mommy.make( + MateriaLegislativa, + ano=2020, + data_apresentacao="2020-01-05", + tipo=tipo_materia + ) + + mommy.make( + Anexada, + materia_principal=materia_principal, + materia_anexada=materia_anexada, + data_anexacao="2019-05-11" + ) + mommy.make( + Anexada, + materia_principal=materia_anexada, + materia_anexada=materia_anexada_anexada, + data_anexacao="2020-11-05" + ) + + + unidade_tramitacao_local_1 = make_unidade_tramitacao(descricao="Teste 1") + unidade_tramitacao_destino_1 = make_unidade_tramitacao(descricao="Teste 2") + unidade_tramitacao_destino_2 = make_unidade_tramitacao(descricao="Teste 3") + + status = mommy.make( + StatusTramitacao, + indicador='R') + + # Teste criação de Tramitacao + form = TramitacaoForm(data={}) + form.data = {'data_tramitacao':date(2019, 5, 6), + 'unidade_tramitacao_local':unidade_tramitacao_local_1.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk, + 'status':status.pk, + 'urgente': False, + 'texto': "Texto de teste"} + form.instance.materia_id=materia_principal.pk + + assert form.is_valid() + + tramitacao_principal = form.save() + tramitacao_anexada = materia_anexada.tramitacao_set.last() + tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last() + + # Verifica se foram criadas as tramitações para as matérias anexadas e anexadas às anexadas + assert materia_principal.tramitacao_set.last() == tramitacao_principal + assert tramitacao_principal.materia.em_tramitacao == (tramitacao_principal.status.indicador != "F") + assert compara_tramitacoes_mat(tramitacao_principal, tramitacao_anexada) + assert MateriaLegislativa.objects.get(id=materia_anexada.pk).em_tramitacao \ + == (tramitacao_anexada.status.indicador != "F") + assert compara_tramitacoes_mat(tramitacao_anexada_anexada, tramitacao_principal) + assert MateriaLegislativa.objects.get(id=materia_anexada_anexada.pk).em_tramitacao \ + == (tramitacao_anexada_anexada.status.indicador != "F") + + + # Teste Edição de Tramitacao + form = TramitacaoUpdateForm(data={}) + # Alterando unidade_tramitacao_destino + form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao, + 'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk, + 'status':tramitacao_principal.status.pk, + 'urgente': tramitacao_principal.urgente, + 'texto': tramitacao_principal.texto} + form.instance = tramitacao_principal + + assert form.is_valid() + tramitacao_principal = form.save() + tramitacao_anexada = materia_anexada.tramitacao_set.last() + tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last() + + assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + assert tramitacao_anexada_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + + + # Teste Remoção de Tramitacao + url = reverse('sapl.materia:tramitacao_delete', + kwargs={'pk': tramitacao_principal.pk}) + response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True) + assert Tramitacao.objects.filter(id=tramitacao_principal.pk).count() == 0 + assert Tramitacao.objects.filter(id=tramitacao_anexada.pk).count() == 0 + assert Tramitacao.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0 + + + # Testes para quando as tramitações das anexadas divergem + form = TramitacaoForm(data={}) + form.data = {'data_tramitacao':date(2019, 5, 6), + 'unidade_tramitacao_local':unidade_tramitacao_local_1.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk, + 'status':status.pk, + 'urgente': False, + 'texto': "Texto de teste"} + form.instance.materia_id=materia_principal.pk + + assert form.is_valid() + + tramitacao_principal = form.save() + tramitacao_anexada = materia_anexada.tramitacao_set.last() + tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last() + + form = TramitacaoUpdateForm(data={}) + # Alterando unidade_tramitacao_destino + form.data = {'data_tramitacao':tramitacao_anexada.data_tramitacao, + 'unidade_tramitacao_local':tramitacao_anexada.unidade_tramitacao_local.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk, + 'status':tramitacao_anexada.status.pk, + 'urgente': tramitacao_anexada.urgente, + 'texto': tramitacao_anexada.texto} + form.instance = tramitacao_anexada + + assert form.is_valid() + + tramitacao_anexada = form.save() + tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last() + + assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_1 + assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + assert tramitacao_anexada_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + + # Editando a tramitação principal, as tramitações anexadas não devem ser editadas + form = TramitacaoUpdateForm(data={}) + # Alterando o texto + form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao, + 'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk, + 'unidade_tramitacao_destino':tramitacao_principal.unidade_tramitacao_destino.pk, + 'status':tramitacao_principal.status.pk, + 'urgente': tramitacao_principal.urgente, + 'texto': "Testando a alteração"} + form.instance = tramitacao_principal + + assert form.is_valid() + tramitacao_principal = form.save() + tramitacao_anexada = materia_anexada.tramitacao_set.last() + tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last() + + assert tramitacao_principal.texto == "Testando a alteração" + assert not tramitacao_anexada.texto == "Testando a alteração" + assert not tramitacao_anexada_anexada.texto == "Testando a alteração" + + # Removendo a tramitação pricipal, as tramitações anexadas não devem ser removidas, pois divergiram + url = reverse('sapl.materia:tramitacao_delete', + kwargs={'pk': tramitacao_principal.pk}) + response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True) + assert Tramitacao.objects.filter(id=tramitacao_principal.pk).count() == 0 + assert Tramitacao.objects.filter(id=tramitacao_anexada.pk).count() == 1 + assert Tramitacao.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 1 + + # Removendo a tramitação anexada, a tramitação anexada à anexada deve ser removida + url = reverse('sapl.materia:tramitacao_delete', + kwargs={'pk': tramitacao_anexada.pk}) + response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True) + assert Tramitacao.objects.filter(id=tramitacao_anexada.pk).count() == 0 + assert Tramitacao.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0 \ No newline at end of file diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 4e927532a..059ec38b2 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -47,8 +47,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, ConfirmarProposicaoForm, DevolverProposicaoForm, LegislacaoCitadaForm, OrgaoForm, ProposicaoForm, TipoProposicaoForm, - TramitacaoForm, TramitacaoUpdateForm, MateriaPesquisaSimplesForm, - lista_anexadas) + TramitacaoForm, TramitacaoUpdateForm, MateriaPesquisaSimplesForm) from sapl.norma.models import LegislacaoCitada from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo @@ -56,7 +55,7 @@ from sapl.settings import MEDIA_ROOT from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO, gerar_hash_arquivo, get_base_url, get_client_ip, get_mime_type_from_file_extension, montar_row_autor, - show_results_filter_set, mail_service_configured) + show_results_filter_set, mail_service_configured, lista_anexados) from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, AnexadaEmLoteFilterSet, @@ -70,7 +69,7 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, filtra_tramitacao_destino, filtra_tramitacao_destino_and_status, filtra_tramitacao_status, - ExcluirTramitacaoEmLote) + ExcluirTramitacaoEmLote, compara_tramitacoes_mat) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, @@ -1299,18 +1298,17 @@ class TramitacaoCrud(MasterDetailCrud): def delete(self, request, *args, **kwargs): tramitacao = Tramitacao.objects.get(id=self.kwargs['pk']) - materia = MateriaLegislativa.objects.get(id=tramitacao.materia.id) + materia = tramitacao.materia url = reverse('sapl.materia:tramitacao_list', - kwargs={'pk': tramitacao.materia.id}) - + kwargs={'pk': materia.id}) + ultima_tramitacao = materia.tramitacao_set.order_by( '-data_tramitacao', '-timestamp', '-id').first() - username = request.user.username - if tramitacao.pk != ultima_tramitacao.pk: + username = request.user.username self.logger.error("user=" + username + ". Não é possível deletar a tramitação de pk={}. " "Somente a última tramitação (pk={}) pode ser deletada!." .format(tramitacao.pk, ultima_tramitacao.pk)) @@ -1318,7 +1316,13 @@ class TramitacaoCrud(MasterDetailCrud): messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(url) else: - tramitacao.delete() + tramitacoes_deletar = [tramitacao.id] + mat_anexadas = lista_anexados(materia) + for ma in mat_anexadas: + tram_anexada = ma.tramitacao_set.last() + if compara_tramitacoes_mat(tram_anexada, tramitacao): + tramitacoes_deletar.append(tram_anexada.id) + Tramitacao.objects.filter(id__in=tramitacoes_deletar).delete() return HttpResponseRedirect(url) class DetailView(MasterDetailCrud.DetailView): @@ -1606,7 +1610,7 @@ class MateriaLegislativaCrud(Crud): if Anexada.objects.filter(materia_principal=self.kwargs['pk']).exists(): materia = MateriaLegislativa.objects.get(pk=self.kwargs['pk']) - anexadas = lista_anexadas(materia) + anexadas = lista_anexados(materia) for anexada in anexadas: anexada.em_tramitacao = True if form.instance.em_tramitacao else False diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 10c5c1c9c..a8630539c 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -24,7 +24,7 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, choice_anos_com_protocolo, choice_force_optional, choice_anos_com_documentoadministrativo, FilterOverridesMetaMixin, choice_anos_com_materias, - FileFieldCheckMixin) + FileFieldCheckMixin, lista_anexados) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, @@ -749,11 +749,17 @@ class TramitacaoAdmForm(ModelForm): def save(self, commit=True): tramitacao = super(TramitacaoAdmForm, self).save(commit) documento = tramitacao.documento + documento.tramitacao = False if tramitacao.status.indicador == "F" else True + documento.save() + lista_tramitacao = [] - for da in documento.anexados.all(): + list_anexados = lista_anexados(documento, False) + for da in list_anexados: if not da.tramitacaoadministrativo_set.all() \ or da.tramitacaoadministrativo_set.last() \ .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: + da.tramitacao = False if tramitacao.status.indicador == "F" else True + da.save() lista_tramitacao.append(TramitacaoAdministrativo( status=tramitacao.status, documento=da, @@ -772,6 +778,19 @@ 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): + if not tramitacao1 or not tramitacao2: + return False + + lst_items = ['id', 'documento_id', 'timestamp'] + values = [(k,v) for k,v in tramitacao1.__dict__.items() if ((k not in lst_items) and (k[0] != '_'))] + other_values = [(k,v) for k,v in tramitacao2.__dict__.items() if (k not in lst_items and k[0] != '_')] + return values == other_values + + class TramitacaoAdmEditForm(TramitacaoAdmForm): unidade_tramitacao_local = forms.ModelChoiceField( @@ -839,6 +858,36 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): return cd + @transaction.atomic + def save(self, commit=True): + # tram_principal = super(TramitacaoAdmEditForm, self).save(commit) + ant_tram_principal = TramitacaoAdministrativo.objects.get(id=self.instance.id) + nova_tram_principal = super(TramitacaoAdmEditForm, self).save(commit) + documento = nova_tram_principal.documento + documento.tramitacao = False if nova_tram_principal.status.indicador == "F" else True + documento.save() + + list_anexados = lista_anexados(documento, False) + for da in list_anexados: + tram_anexada = da.tramitacaoadministrativo_set.last() + if compara_tramitacoes_doc(ant_tram_principal, tram_anexada): + tram_anexada.status = nova_tram_principal.status + tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao + tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local + tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento + tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino + tram_anexada.urgente = nova_tram_principal.urgente + tram_anexada.texto = nova_tram_principal.texto + tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo + tram_anexada.user = nova_tram_principal.user + tram_anexada.ip = nova_tram_principal.ip + tram_anexada.save() + + da.tramitacao = False if nova_tram_principal.status.indicador == "F" else True + da.save() + return nova_tram_principal + + class AnexadoForm(ModelForm): logger = logging.getLogger(__name__) diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index f5b3dae52..ce322a7ba 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -8,16 +8,20 @@ from model_mommy import mommy import pytest from sapl.base.models import AppConfig +from sapl.comissoes.models import Comissao, TipoComissao from sapl.materia.models import UnidadeTramitacao from sapl.protocoloadm.forms import (AnularProtocoloAdmForm, DocumentoAdministrativoForm, MateriaLegislativa, ProtocoloDocumentForm, - ProtocoloMateriaForm) + ProtocoloMateriaForm, TramitacaoAdmForm, + TramitacaoAdmEditForm, + compara_tramitacoes_doc) from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, - TipoMateriaLegislativa, + TipoMateriaLegislativa, Anexado, TramitacaoAdministrativo) +from sapl.utils import lista_anexados @pytest.mark.django_db(transaction=False) @@ -455,3 +459,247 @@ def test_protocolo_materia_invalido(): assert errors['vincular_materia'] == [_('Este campo é obrigatório.')] assert len(errors) == 7 + + +@pytest.mark.django_db(transaction=False) +def test_lista_documentos_anexados(): + tipo_documento = mommy.make( + TipoDocumentoAdministrativo, + descricao="Tipo_Teste" + ) + documento_principal = mommy.make( + DocumentoAdministrativo, + numero=20, + ano=2018, + data="2018-01-04", + tipo=tipo_documento + ) + documento_anexado = mommy.make( + DocumentoAdministrativo, + numero=21, + ano=2019, + data="2019-05-04", + tipo=tipo_documento + ) + documento_anexado_anexado = mommy.make( + DocumentoAdministrativo, + numero=22, + ano=2020, + data="2020-01-05", + tipo=tipo_documento + ) + + mommy.make( + Anexado, + documento_principal=documento_principal, + documento_anexado=documento_anexado, + data_anexacao="2019-05-11" + ) + mommy.make( + Anexado, + documento_principal=documento_anexado, + documento_anexado=documento_anexado_anexado, + data_anexacao="2020-11-05" + ) + + lista = lista_anexados(documento_principal, False) + + assert len(lista) == 2 + assert lista[0] == documento_anexado + assert lista[1] == documento_anexado_anexado + + +@pytest.mark.django_db(transaction=False) +def make_unidade_tramitacao(descricao): + # Cria uma comissão para ser a unidade de tramitação + tipo_comissao = mommy.make(TipoComissao) + comissao = mommy.make(Comissao, + tipo=tipo_comissao, + nome=descricao, + sigla='T', + data_criacao='2016-03-21') + + # Testa a comissão + assert comissao.tipo == tipo_comissao + assert comissao.nome == descricao + + # Cria a unidade + unidade = mommy.make(UnidadeTramitacao, comissao=comissao) + assert unidade.comissao == comissao + + return unidade + + +@pytest.mark.django_db(transaction=False) +def test_tramitacoes_documentos_anexados(admin_client): + tipo_documento = mommy.make( + TipoDocumentoAdministrativo, + descricao="Tipo_Teste" + ) + documento_principal = mommy.make( + DocumentoAdministrativo, + numero=20, + ano=2018, + data="2018-01-04", + tipo=tipo_documento + ) + documento_anexado = mommy.make( + DocumentoAdministrativo, + numero=21, + ano=2019, + data="2019-05-04", + tipo=tipo_documento + ) + documento_anexado_anexado = mommy.make( + DocumentoAdministrativo, + numero=22, + ano=2020, + data="2020-01-05", + tipo=tipo_documento + ) + + mommy.make( + Anexado, + documento_principal=documento_principal, + documento_anexado=documento_anexado, + data_anexacao="2019-05-11" + ) + mommy.make( + Anexado, + documento_principal=documento_anexado, + documento_anexado=documento_anexado_anexado, + data_anexacao="2020-11-05" + ) + + + unidade_tramitacao_local_1 = make_unidade_tramitacao(descricao="Teste 1") + unidade_tramitacao_destino_1 = make_unidade_tramitacao(descricao="Teste 2") + unidade_tramitacao_destino_2 = make_unidade_tramitacao(descricao="Teste 3") + + status = mommy.make( + StatusTramitacaoAdministrativo, + indicador='R') + + # Teste criação de Tramitacao + form = TramitacaoAdmForm(data={}) + form.data = {'data_tramitacao':date(2019, 5, 6), + 'unidade_tramitacao_local':unidade_tramitacao_local_1.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk, + 'status':status.pk, + 'urgente': False, + 'texto': "Texto de teste"} + form.instance.documento_id=documento_principal.pk + + assert form.is_valid() + tramitacao_principal = form.save() + tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last() + tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last() + + # Verifica se foram criadas as tramitações para os documentos anexados e anexados aos anexados + assert documento_principal.tramitacaoadministrativo_set.last() == tramitacao_principal + assert tramitacao_principal.documento.tramitacao == (tramitacao_principal.status.indicador != "F") + assert compara_tramitacoes_doc(tramitacao_principal, tramitacao_anexada) + assert DocumentoAdministrativo.objects.get(id=documento_anexado.pk).tramitacao \ + == (tramitacao_anexada.status.indicador != "F") + assert compara_tramitacoes_doc(tramitacao_anexada_anexada, tramitacao_principal) + assert DocumentoAdministrativo.objects.get(id=documento_anexado_anexado.pk).tramitacao \ + == (tramitacao_anexada_anexada.status.indicador != "F") + + + # Teste Edição de Tramitacao + form = TramitacaoAdmEditForm(data={}) + # Alterando unidade_tramitacao_destino + form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao, + 'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk, + 'status':tramitacao_principal.status.pk, + 'urgente': tramitacao_principal.urgente, + 'texto': tramitacao_principal.texto} + form.instance = tramitacao_principal + + assert form.is_valid() + tramitacao_principal = form.save() + tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last() + tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last() + + assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + assert tramitacao_anexada_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + + + # Teste Remoção de Tramitacao + url = reverse('sapl.protocoloadm:tramitacaoadministrativo_delete', + kwargs={'pk': tramitacao_principal.pk}) + response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True) + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_principal.pk).count() == 0 + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada.pk).count() == 0 + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0 + + + # Testes para quando as tramitações das anexadas divergem + form = TramitacaoAdmForm(data={}) + form.data = {'data_tramitacao':date(2019, 5, 6), + 'unidade_tramitacao_local':unidade_tramitacao_local_1.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk, + 'status':status.pk, + 'urgente': False, + 'texto': "Texto de teste"} + form.instance.documento_id=documento_principal.pk + + assert form.is_valid() + tramitacao_principal = form.save() + tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last() + tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last() + + form = TramitacaoAdmEditForm(data={}) + # Alterando unidade_tramitacao_destino + form.data = {'data_tramitacao':tramitacao_anexada.data_tramitacao, + 'unidade_tramitacao_local':tramitacao_anexada.unidade_tramitacao_local.pk, + 'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk, + 'status':tramitacao_anexada.status.pk, + 'urgente': tramitacao_anexada.urgente, + 'texto': tramitacao_anexada.texto} + form.instance = tramitacao_anexada + + assert form.is_valid() + tramitacao_anexada = form.save() + tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last() + + assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_1 + assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + assert tramitacao_anexada_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2 + + # Editando a tramitação principal, as tramitações anexadas não devem ser editadas + form = TramitacaoAdmEditForm(data={}) + # Alterando o texto + form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao, + 'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk, + 'unidade_tramitacao_destino':tramitacao_principal.unidade_tramitacao_destino.pk, + 'status':tramitacao_principal.status.pk, + 'urgente': tramitacao_principal.urgente, + 'texto': "Testando a alteração"} + form.instance = tramitacao_principal + + assert form.is_valid() + tramitacao_principal = form.save() + tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last() + tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last() + + assert tramitacao_principal.texto == "Testando a alteração" + assert not tramitacao_anexada.texto == "Testando a alteração" + assert not tramitacao_anexada_anexada.texto == "Testando a alteração" + + # Removendo a tramitação pricipal, as tramitações anexadas não devem ser removidas, pois divergiram + url = reverse('sapl.protocoloadm:tramitacaoadministrativo_delete', + kwargs={'pk': tramitacao_principal.pk}) + response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True) + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_principal.pk).count() == 0 + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada.pk).count() == 1 + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 1 + + # Removendo a tramitação anexada, a tramitação anexada à anexada deve ser removida + url = reverse('sapl.protocoloadm:tramitacaoadministrativo_delete', + kwargs={'pk': tramitacao_anexada.pk}) + response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True) + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada.pk).count() == 0 + assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0 diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index a2f8e74b7..eec04836b 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -34,7 +34,7 @@ from sapl.materia.views import gerar_pdf_impressos from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.protocoloadm.models import Protocolo from sapl.utils import (create_barcode, get_base_url, get_client_ip, - get_mime_type_from_file_extension, + get_mime_type_from_file_extension, lista_anexados, show_results_filter_set, mail_service_configured) from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm, @@ -46,7 +46,8 @@ from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm, filtra_tramitacao_adm_destino_and_status, filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status, - AnexadoForm, AnexadoEmLoteFilterSet) + AnexadoForm, AnexadoEmLoteFilterSet, + compara_tramitacoes_doc) from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo, Anexado) @@ -1225,14 +1226,15 @@ class TramitacaoAdmCrud(MasterDetailCrud): class DeleteView(MasterDetailCrud.DeleteView): + logger = logging.getLogger(__name__) + def delete(self, request, *args, **kwargs): tramitacao = TramitacaoAdministrativo.objects.get( id=self.kwargs['pk']) - documento = DocumentoAdministrativo.objects.get( - id=tramitacao.documento.id) + documento = tramitacao.documento url = reverse( 'sapl.protocoloadm:tramitacaoadministrativo_list', - kwargs={'pk': tramitacao.documento.id}) + kwargs={'pk': documento.id}) ultima_tramitacao = \ documento.tramitacaoadministrativo_set.order_by( @@ -1240,11 +1242,21 @@ class TramitacaoAdmCrud(MasterDetailCrud): '-id').first() if tramitacao.pk != ultima_tramitacao.pk: + username = request.user.username + self.logger.error("user=" + username + ". Não é possível deletar a tramitação de pk={}. " + "Somente a última tramitação (pk={}) pode ser deletada!." + .format(tramitacao.pk, ultima_tramitacao.pk)) msg = _('Somente a última tramitação pode ser deletada!') messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(url) else: - tramitacao.delete() + tramitacoes_deletar = [tramitacao.id] + docs_anexados = lista_anexados(documento, False) + for da in docs_anexados: + tram_anexada = da.tramitacaoadministrativo_set.last() + if compara_tramitacoes_doc(tram_anexada, tramitacao): + tramitacoes_deletar.append(tram_anexada.id) + TramitacaoAdministrativo.objects.filter(id__in=tramitacoes_deletar).delete() return HttpResponseRedirect(url) diff --git a/sapl/utils.py b/sapl/utils.py index eb5552c0a..53ab057a9 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -5,7 +5,7 @@ import os import re from unicodedata import normalize as unicodedata_normalize import unicodedata - +import logging from crispy_forms.layout import HTML, Button from django import forms from django.apps import apps @@ -940,15 +940,41 @@ def remover_acentos(string): def mail_service_configured(request=None): + logger = logging.getLogger(__name__) + if settings.EMAIL_RUNNING is None: result = True try: connection = get_connection() connection.open() except Exception as e: + logger.error(str(e)) result = False finally: connection.close() settings.EMAIL_RUNNING = result return settings.EMAIL_RUNNING + + +def lista_anexados(principal, isMateriaLegislativa=True): + anexados_total = [] + if isMateriaLegislativa: #MateriaLegislativa + from sapl.materia.models import Anexada + anexados_iterator = Anexada.objects.filter(materia_principal=principal) + else: #DocAdm + from sapl.protocoloadm.models import Anexado + anexados_iterator = Anexado.objects.filter(documento_principal=principal) + while anexados_iterator: + anexados_tmp = [] + for anx in anexados_iterator: + if isMateriaLegislativa: + anexados_total.append(anx.materia_anexada) + anexados_anexado = Anexada.objects.filter(materia_principal=anx.materia_anexada) + else: + anexados_total.append(anx.documento_anexado) + anexados_anexado = Anexado.objects.filter(documento_principal=anx.documento_anexado) + anexados_tmp.extend(anexados_anexado) + anexados_iterator = anexados_tmp + + return anexados_total