diff --git a/sapl/materia/views.py b/sapl/materia/views.py
index afde0ef64..4119107a5 100644
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -1317,12 +1317,19 @@ class TramitacaoCrud(MasterDetailCrud):
return HttpResponseRedirect(url)
else:
tramitacoes_deletar = [tramitacao.id]
+ if materia.tramitacao_set.count() == 0:
+ materia.em_tramitacao = False
+ materia.save()
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)
+ if ma.tramitacao_set.count() == 0:
+ ma.em_tramitacao = False
+ ma.save()
Tramitacao.objects.filter(id__in=tramitacoes_deletar).delete()
+
return HttpResponseRedirect(url)
class DetailView(MasterDetailCrud.DetailView):
diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py
index a8630539c..b7c92bcc6 100644
--- a/sapl/protocoloadm/forms.py
+++ b/sapl/protocoloadm/forms.py
@@ -1407,3 +1407,252 @@ class FichaSelecionaAdmForm(forms.Form):
form_actions(label='Gerar Impresso')
)
)
+
+
+class PrimeiraTramitacaoEmLoteAdmFilterSet(django_filters.FilterSet):
+
+ class Meta(FilterOverridesMetaMixin):
+ model = DocumentoAdministrativo
+ fields = ['tipo', 'data']
+
+ def __init__(self, *args, **kwargs):
+ super(PrimeiraTramitacaoEmLoteAdmFilterSet, self).__init__(
+ *args, **kwargs)
+
+ self.filters['tipo'].label = 'Tipo de Documento'
+ self.filters['data'].label = 'Data (Inicial - Final)'
+ self.form.fields['tipo'].required = True
+ self.form.fields['data'].required = False
+
+ row1 = to_row([('tipo', 12)])
+ row2 = to_row([('data', 12)])
+
+ self.form.helper = SaplFormHelper()
+ self.form.helper.form_method = 'GET'
+ self.form.helper.layout = Layout(
+ Fieldset(_('Primeira Tramitação'),
+ row1, row2, form_actions(label='Pesquisar')))
+
+
+class TramitacaoEmLoteAdmForm(ModelForm):
+ logger = logging.getLogger(__name__)
+
+ class Meta:
+ model = TramitacaoAdministrativo
+ fields = ['data_tramitacao',
+ 'unidade_tramitacao_local',
+ 'status',
+ 'urgente',
+ 'unidade_tramitacao_destino',
+ 'data_encaminhamento',
+ 'data_fim_prazo',
+ 'texto',
+ 'user',
+ 'ip']
+ widgets = {'user': forms.HiddenInput(),
+ 'ip': forms.HiddenInput()}
+
+
+ def __init__(self, *args, **kwargs):
+ super(TramitacaoEmLoteAdmForm, 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', 6),
+ ('urgente', 6)
+ ])
+ row4 = to_row([
+ ('texto', 12)
+ ])
+
+ documentos_checkbox_HTML = '''
+
+
+ '''
+
+ 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(TramitacaoEmLoteAdmForm, 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
+ documentos = self.initial['documentos']
+ user = self.initial['user'] if 'user' in self.initial else None
+ ip = self.initial['ip'] if 'ip' in self.initial else ''
+ for doc_id in documentos:
+ doc = DocumentoAdministrativo.objects.get(id=doc_id)
+ tramitacao = TramitacaoAdministrativo.objects.create(
+ status=cd['status'],
+ documento=doc,
+ 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'],
+ texto=cd['texto'],
+ data_fim_prazo=cd['data_fim_prazo'],
+ user=user,
+ ip=ip
+ )
+ doc.tramitacao = False if tramitacao.status.indicador == "F" else True
+ doc.save()
+ lista_tramitacao = []
+ 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:
+ da.tramitacao = False if tramitacao.status.indicador == "F" else True
+ da.save()
+ lista_tramitacao.append(TramitacaoAdministrativo(
+ status=tramitacao.status,
+ documento=da,
+ 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,
+ texto=tramitacao.texto,
+ data_fim_prazo=tramitacao.data_fim_prazo,
+ user=tramitacao.user,
+ ip=tramitacao.ip
+ ))
+ TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao)
+
+ return tramitacao
+
+
+class TramitacaoEmLoteAdmFilterSet(django_filters.FilterSet):
+ class Meta(FilterOverridesMetaMixin):
+ model = DocumentoAdministrativo
+ fields = ['tipo', 'data', 'tramitacaoadministrativo__status',
+ 'tramitacaoadministrativo__unidade_tramitacao_destino']
+
+ def __init__(self, *args, **kwargs):
+ super(TramitacaoEmLoteAdmFilterSet, self).__init__(
+ *args, **kwargs)
+
+ self.filters['tipo'].label = _('Tipo de Documento')
+ self.filters['data'].label = _('Data (Inicial - Final)')
+ self.filters['tramitacaoadministrativo__unidade_tramitacao_destino'
+ ].label = _('Unidade Destino (Último Destino)')
+ self.filters['tramitacaoadministrativo__status'].label = _('Status')
+ self.form.fields['tipo'].required = True
+ self.form.fields['data'].required = False
+ self.form.fields['tramitacaoadministrativo__status'].required = True
+ self.form.fields[
+ 'tramitacaoadministrativo__unidade_tramitacao_destino'].required = True
+
+ row1 = to_row([
+ ('tipo', 4),
+ ('tramitacaoadministrativo__unidade_tramitacao_destino', 4),
+ ('tramitacaoadministrativo__status', 4)])
+ row2 = to_row([('data', 12)])
+
+ self.form.helper = SaplFormHelper()
+ self.form.helper.form_method = 'GET'
+ self.form.helper.layout = Layout(
+ Fieldset(_('Tramitação em Lote'),
+ row1, row2, form_actions(label=_('Pesquisar'))))
\ No newline at end of file
diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py
index ce322a7ba..ff7bf06d2 100644
--- a/sapl/protocoloadm/tests/test_protocoloadm.py
+++ b/sapl/protocoloadm/tests/test_protocoloadm.py
@@ -1,10 +1,11 @@
-from datetime import date, timedelta, datetime
+from datetime import date, timedelta
from django.core.urlresolvers import reverse
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from model_mommy import mommy
+from urllib.parse import urlencode
import pytest
from sapl.base.models import AppConfig
@@ -15,7 +16,8 @@ from sapl.protocoloadm.forms import (AnularProtocoloAdmForm,
MateriaLegislativa, ProtocoloDocumentForm,
ProtocoloMateriaForm, TramitacaoAdmForm,
TramitacaoAdmEditForm,
- compara_tramitacoes_doc)
+ compara_tramitacoes_doc,
+ TramitacaoEmLoteAdmForm)
from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo,
@@ -703,3 +705,338 @@ def test_tramitacoes_documentos_anexados(admin_client):
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
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tramitacao_lote_documentos_form(admin_client):
+ tipo_documento = mommy.make(
+ TipoDocumentoAdministrativo,
+ descricao="Tipo_Teste"
+ )
+ documento = mommy.make(
+ DocumentoAdministrativo,
+ numero=20,
+ ano=2018,
+ data="2019-05-16",
+ tipo=tipo_documento
+ )
+
+ unidade_tramitacao_local_1 = make_unidade_tramitacao(descricao="Teste 1")
+ unidade_tramitacao_destino_1 = make_unidade_tramitacao(descricao="Teste 2")
+
+ status = mommy.make(
+ StatusTramitacaoAdministrativo,
+ indicador='R')
+
+ # Form sem campos obrigatórios
+ documentos = []
+ form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
+
+ errors = form.errors
+ assert errors['data_tramitacao'] == ['Este campo é obrigatório.']
+ assert errors['unidade_tramitacao_local'] == ['Este campo é obrigatório.']
+ assert errors['status'] == ['Este campo é obrigatório.']
+ assert errors['unidade_tramitacao_destino'] == ['Este campo é obrigatório.']
+ assert errors['texto'] == ['Este campo é obrigatório.']
+ assert not form.is_valid()
+
+ # Tramitar apenas um documento sem anexados
+ documentos = [documento.id]
+ now = timezone.now().date()
+
+ form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
+ form.data = {'data_tramitacao': now + timedelta(days=5),
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa'}
+
+ assert form.errors['__all__'] == \
+ ["A data de tramitação deve ser menor ou igual a data de hoje!"]
+ assert not form.is_valid()
+
+ form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
+ form.data = {'data_tramitacao': '2019-05-14',
+ 'data_encaminhamento' : '2019-05-09',
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa'}
+
+ assert form.errors['__all__'] == \
+ ["A data de encaminhamento deve ser maior que a data de tramitação!"]
+ assert not form.is_valid()
+
+ form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
+ form.data = {'data_tramitacao': '2019-05-14',
+ 'data_encaminhamento' : '2019-05-15',
+ 'data_fim_prazo': '2019-05-09',
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa'}
+
+ assert form.errors['__all__'] == \
+ ["A data fim de prazo deve ser maior que a data de tramitação!"]
+ assert not form.is_valid()
+
+ form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
+ form.data = {'data_tramitacao': '2019-05-14',
+ 'data_encaminhamento' : '2019-05-15',
+ 'data_fim_prazo': '2019-05-18',
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_local_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa'}
+
+ assert form.errors['__all__'] == \
+ ["Unidade tramitação local deve ser diferente da unidade tramitação destino."]
+ assert not form.is_valid()
+
+ form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
+ form.data = {'data_tramitacao': '2019-05-14',
+ 'data_encaminhamento' : '2019-05-15',
+ 'data_fim_prazo': '2019-05-18',
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa'}
+
+ assert form.is_valid()
+
+
+@pytest.mark.django_db(transaction=False)
+def test_tramitacao_lote_documentos_views(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
+ )
+
+ documento_sem_anexados = mommy.make(
+ DocumentoAdministrativo,
+ numero=23,
+ ano=2020,
+ data="2021-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")
+ unidade_tramitacao_destino_3 = make_unidade_tramitacao(descricao="Teste 4")
+
+ status = mommy.make(
+ StatusTramitacaoAdministrativo,
+ indicador='R')
+
+ url = reverse('sapl.protocoloadm:primeira_tramitacao_em_lote_docadm')
+ url = url + '?' + urlencode({'tipo':tipo_documento.id, 'data_0':'', 'data_1':''})
+
+ response = admin_client.post(url, {'salvar':'salvar'}, follow=True)
+ assert response.status_code == 200
+
+ msgs = [m.message for m in response.context['messages']]
+ assert len(msgs) == 1
+ assert msgs[0] == 'Escolha algum Documento para ser tramitado.'
+
+ documentos = [documento_sem_anexados.id, documento_anexado_anexado.id]
+
+ response = admin_client.post(url, {'documentos': documentos,'salvar':'salvar'}, follow=True)
+ msgs = [m.message for m in response.context['messages']]
+
+ assert 'Data Tramitação: Este campo é obrigatório.' in msgs
+ assert 'Unidade Local: Este campo é obrigatório.' in msgs
+ assert 'Status: Este campo é obrigatório.' in msgs
+ assert 'Unidade Destino: Este campo é obrigatório.' in msgs
+ assert 'Texto da Ação: Este campo é obrigatório.' in msgs
+
+ # Primeira tramitação em lote
+
+ response = admin_client.post(url,
+ {'documentos': documentos,
+ 'data_tramitacao': date(2019, 5, 15),
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa',
+ 'salvar':'salvar'},
+ follow=True)
+
+ assert response.status_code == 200
+
+ assert TramitacaoAdministrativo.objects.all().count() == 2
+ assert documento_sem_anexados.tramitacaoadministrativo_set.all().count() == 1
+ assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 1
+
+ # Segunda tramitação em lote
+
+ url_lote = reverse('sapl.protocoloadm:tramitacao_em_lote_docadm')
+ url_lote = url_lote + '?' + urlencode(
+ {'tipo':tipo_documento.id,
+ 'tramitacaoadministrativo__unidade_tramitacao_destino':unidade_tramitacao_destino_1.id,
+ 'tramitacaoadministrativo__status': status.id,
+ 'data_0':'',
+ 'data_1':''})
+
+ response = admin_client.post(url_lote, {'salvar':'salvar'}, follow=True)
+ assert response.status_code == 200
+
+ assert response.context_data['object_list'].count() == 2
+
+ msgs = [m.message for m in response.context['messages']]
+ assert len(msgs) == 1
+ assert msgs[0] == 'Escolha algum Documento para ser tramitado.'
+
+ response = admin_client.post(url_lote, {'documentos':documentos, 'salvar':'salvar'}, follow=True)
+ assert response.status_code == 200
+
+ msgs = [m.message for m in response.context['messages']]
+
+ assert 'Data Tramitação: Este campo é obrigatório.' in msgs
+ assert 'Unidade Local: Este campo é obrigatório.' in msgs
+ assert 'Status: Este campo é obrigatório.' in msgs
+ assert 'Unidade Destino: Este campo é obrigatório.' in msgs
+ assert 'Texto da Ação: Este campo é obrigatório.' in msgs
+
+ response = admin_client.post(url_lote,
+ {'documentos': documentos,
+ 'data_tramitacao': date(2019, 5, 15),
+ 'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa',
+ 'salvar':'salvar'},
+ follow=True)
+ assert response.status_code == 200
+
+ msgs = [m.message for m in response.context['messages']]
+
+ assert 'Unidade tramitação local deve ser diferente da unidade tramitação destino.' in msgs
+
+ response = admin_client.post(url_lote,
+ {'documentos': documentos,
+ 'data_tramitacao': date(2019, 5, 15),
+ 'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa',
+ 'salvar':'salvar'},
+ follow=True)
+ assert response.status_code == 200
+
+ msgs = [m.message for m in response.context['messages']]
+
+ assert 'Tramitação completa.' in msgs
+
+ assert TramitacaoAdministrativo.objects.all().count() == 4
+ assert documento_sem_anexados.tramitacaoadministrativo_set.all().count() == 2
+ assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 2
+
+ # Tramitar documentos com anexados
+ # O documento anexado ao anexado não deve tramitar junto porque já está com tramitação diferente
+ documentos = [documento_principal.id]
+
+ response = admin_client.post(url,
+ {'documentos': documentos,
+ 'data_tramitacao': date(2019, 5, 15),
+ 'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa',
+ 'salvar':'salvar'},
+ follow=True)
+
+ assert response.status_code == 200
+
+ assert TramitacaoAdministrativo.objects.all().count() == 6
+ assert documento_principal.tramitacaoadministrativo_set.all().count() == 1
+ assert documento_anexado.tramitacaoadministrativo_set.all().count() == 1
+
+ # Segunda tramitação com documentos anexados
+ response = admin_client.post(url_lote,
+ {'documentos': documentos,
+ 'data_tramitacao': date(2019, 5, 15),
+ 'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_2.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa',
+ 'salvar':'salvar'},
+ follow=True)
+ assert response.status_code == 200
+
+ msgs = [m.message for m in response.context['messages']]
+
+ assert 'Tramitação completa.' in msgs
+
+ assert TramitacaoAdministrativo.objects.all().count() == 8
+ assert documento_principal.tramitacaoadministrativo_set.all().count() == 2
+ assert documento_anexado.tramitacaoadministrativo_set.all().count() == 2
+
+ # Terceira tramitação em lote
+ # Agora, o documento anexado ao anexado deve tramitar junto com o documento principal,
+ # pois suas tramitações convergiram
+
+ response = admin_client.post(url_lote,
+ {'documentos': documentos,
+ 'data_tramitacao': date(2019, 5, 15),
+ 'unidade_tramitacao_local': unidade_tramitacao_destino_2.id,
+ 'unidade_tramitacao_destino': unidade_tramitacao_destino_3.id,
+ 'status': status.id,
+ 'urgente': False,
+ 'texto': 'aaaa',
+ 'salvar':'salvar'},
+ follow=True)
+ assert response.status_code == 200
+
+ msgs = [m.message for m in response.context['messages']]
+
+ assert 'Tramitação completa.' in msgs
+
+ assert TramitacaoAdministrativo.objects.all().count() == 11
+ assert documento_principal.tramitacaoadministrativo_set.all().count() == 3
+ assert documento_anexado.tramitacaoadministrativo_set.all().count() == 3
+ assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 3
diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py
index e5925204d..0fca1b76b 100644
--- a/sapl/protocoloadm/urls.py
+++ b/sapl/protocoloadm/urls.py
@@ -22,7 +22,9 @@ from sapl.protocoloadm.views import (AcompanhamentoDocumentoView,
doc_texto_integral,
DesvincularDocumentoView,
DesvincularMateriaView,
- AnexadoCrud, DocumentoAnexadoEmLoteView)
+ AnexadoCrud, DocumentoAnexadoEmLoteView,
+ PrimeiraTramitacaoEmLoteAdmView,
+ TramitacaoEmLoteAdmView)
from .apps import AppConfig
@@ -98,6 +100,12 @@ urlpatterns_protocolo = [
url(r'^protocoloadm/recuperar-materia',
recuperar_materia_protocolo, name='recuperar_materia_protocolo'),
+ url(r'^protocoloadm/primeira-tramitacao-em-lote',
+ PrimeiraTramitacaoEmLoteAdmView.as_view(),
+ name='primeira_tramitacao_em_lote_docadm'),
+
+ url(r'^protocoloadm/tramitacao-em-lote', TramitacaoEmLoteAdmView.as_view(),
+ name='tramitacao_em_lote_docadm'),
]
diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py
index eec04836b..6081be6ef 100755
--- a/sapl/protocoloadm/views.py
+++ b/sapl/protocoloadm/views.py
@@ -29,7 +29,7 @@ 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)
-from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
+from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao
from sapl.materia.views import gerar_pdf_impressos
from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo
@@ -47,6 +47,9 @@ from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm,
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,
DocumentoAdministrativo, StatusTramitacaoAdministrativo,
@@ -1251,12 +1254,19 @@ class TramitacaoAdmCrud(MasterDetailCrud):
return HttpResponseRedirect(url)
else:
tramitacoes_deletar = [tramitacao.id]
+ if documento.tramitacaoadministrativo_set.count() == 0:
+ documento.tramitacao = False
+ documento.save()
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)
+ if da.tramitacaoadministrativo_set.count() == 0:
+ da.tramitacao = False
+ da.save()
TramitacaoAdministrativo.objects.filter(id__in=tramitacoes_deletar).delete()
+
return HttpResponseRedirect(url)
@@ -1437,3 +1447,142 @@ class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
return gerar_pdf_impressos(self.request, context,
'materia/impressos/ficha_adm_pdf.html')
+
+
+class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
+ filterset_class = PrimeiraTramitacaoEmLoteAdmFilterSet
+ template_name = 'protocoloadm/em_lote/tramitacaoadm.html'
+ permission_required = ('materia.add_tramitacao', )
+
+ primeira_tramitacao = True
+
+ logger = logging.getLogger(__name__)
+
+
+ def get_context_data(self, **kwargs):
+ context = super(PrimeiraTramitacaoEmLoteAdmView,
+ self).get_context_data(**kwargs)
+
+ context['subnav_template_name'] = 'protocoloadm/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['object_list'] = context['object_list'].order_by(
+ 'ano', 'numero')
+ qr = self.request.GET.copy()
+
+ form = TramitacaoEmLoteAdmForm()
+ context['form'] = form
+
+ 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.tramitacaoadministrativo_set.all().count() == 0]
+ else:
+ context['title'] = _('Tramitação em Lote')
+ context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
+ id=qr['tramitacaoadministrativo__unidade_tramitacao_destino'])
+
+ context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
+
+ context['show_results'] = show_results_filter_set(qr)
+
+ return context
+
+ def post(self, request, *args, **kwargs):
+ user = request.user
+ ip = get_client_ip(request)
+
+ documentos_ids = request.POST.getlist('documentos')
+ if not documentos_ids:
+ msg = _("Escolha algum Documento para ser tramitado.")
+ messages.add_message(request, messages.ERROR, msg)
+ return self.get(request, self.kwargs)
+
+ form = TramitacaoEmLoteAdmForm(request.POST, initial=
+ {'documentos': documentos_ids,
+ 'user': user, 'ip':ip})
+
+ if form.is_valid():
+ # cd = form.clean()
+ form.save()
+
+ 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()
+
+ return self.form_invalid(form)
+
+
+ def get_success_url(self):
+ return HttpResponseRedirect(reverse('sapl.protocoloadm:primeira_tramitacao_em_lote_docadm'))
+
+
+ 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})
+
+
+class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
+ filterset_class = TramitacaoEmLoteAdmFilterSet
+
+ primeira_tramitacao = False
+
+ def get_context_data(self, **kwargs):
+ context = super(TramitacaoEmLoteAdmView,
+ self).get_context_data(**kwargs)
+
+ qr = self.request.GET.copy()
+
+ context['primeira_tramitacao'] = False
+
+ if ('tramitacao__status' in qr and
+ 'tramitacao__unidade_tramitacao_destino' in qr and
+ qr['tramitacao__status'] and
+ qr['tramitacao__unidade_tramitacao_destino']):
+ lista = self.filtra_tramitacao_destino_and_status(
+ qr['tramitacao__status'],
+ qr['tramitacao__unidade_tramitacao_destino'])
+ context['object_list'] = context['object_list'].filter(
+ id__in=lista).distinct()
+
+ return context
+
+
+ def pega_ultima_tramitacao(self):
+ return TramitacaoAdministrativo.objects.values(
+ 'documento_id').annotate(data_encaminhamento=Max(
+ 'data_encaminhamento'),
+ id=Max('id')).values_list('id', flat=True)
+
+ def filtra_tramitacao_status(self, status):
+ lista = self.pega_ultima_tramitacao()
+ return TramitacaoAdministrativo.objects.filter(
+ id__in=lista,
+ status=status).distinct().values_list('documento_id', flat=True)
+
+
+ def filtra_tramitacao_destino(self, destino):
+ lista = self.pega_ultima_tramitacao()
+ return TramitacaoAdministrativo.objects.filter(
+ id__in=lista,
+ unidade_tramitacao_destino=destino).distinct().values_list(
+ 'documento_id', flat=True)
+
+
+ def filtra_tramitacao_destino_and_status(self, status, destino):
+ lista = self.pega_ultima_tramitacao()
+ return TramitacaoAdministrativo.objects.filter(
+ id__in=lista,
+ status=status,
+ unidade_tramitacao_destino=destino).distinct().values_list(
+ 'documento_id', flat=True)
\ No newline at end of file
diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml
index de556d882..e06638095 100644
--- a/sapl/templates/navbar.yaml
+++ b/sapl/templates/navbar.yaml
@@ -29,8 +29,13 @@
url: sapl.materia:receber-proposicao
- title: {% trans 'Documentos Administrativos' %}
- {% if 'documentos_administrativos'|get_config_attr == 'R' %}check_permission: protocoloadm.list_documentoadministrativo{%endif%}
- url: sapl.protocoloadm:pesq_doc_adm
+ {% if 'documentos_administrativos'|get_config_attr == 'R' %}check_permission: protocoloadm.list_documentoadministrativo {% endif %}
+ children:
+ - title: {% trans 'Pesquisar Documentos Administrativos' %}
+ url: sapl.protocoloadm:pesq_doc_adm
+ - title: {% trans 'Tramitação em Lote' %}
+ url: sapl.protocoloadm:primeira_tramitacao_em_lote_docadm
+ check_permission: sapl.documento:add_tramitacao
- title: {% trans 'Atividade Legislativa' %}
children:
diff --git a/sapl/templates/protocoloadm/em_lote/subnav_em_lote.yaml b/sapl/templates/protocoloadm/em_lote/subnav_em_lote.yaml
new file mode 100644
index 000000000..cf5beb12b
--- /dev/null
+++ b/sapl/templates/protocoloadm/em_lote/subnav_em_lote.yaml
@@ -0,0 +1,5 @@
+{% load i18n common_tags %}
+- title: {% trans 'Primeira Tramitação' %}
+ url: primeira_tramitacao_em_lote_docadm
+- title: {% trans 'Tramitação em Lote' %}
+ url: tramitacao_em_lote_docadm
diff --git a/sapl/templates/protocoloadm/em_lote/tramitacaoadm.html b/sapl/templates/protocoloadm/em_lote/tramitacaoadm.html
new file mode 100644
index 000000000..94796621f
--- /dev/null
+++ b/sapl/templates/protocoloadm/em_lote/tramitacaoadm.html
@@ -0,0 +1,46 @@
+{% extends "crud/detail.html" %}
+{% load i18n crispy_forms_tags %}
+{% block detail_content %}
+
+ {% if not show_results %}
+ {% crispy filter.form %}
+ {% else %}
+ {% if object_list|length > 0 %}
+ {% if object_list|length == 1 %}
+ {% trans 'Pesquisa concluída com sucesso! Foi encontrado 1 documento.'%}
+ {% else %}
+ Foram encontrados {{object_list|length}} documentos.
+ {% endif %}
+ {% crispy form %}
+ {% else %}
+ Nenhum documento encontrado. |
+ {% endif %}
+
+ {% endif%}
+{% endblock detail_content %}
+
+{% block extra_js %}
+
+{% endblock %}