diff --git a/docker-compose.yml b/docker-compose.yml index 3f4eb46b3..5eb35418d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.160-RC0 + image: interlegis/sapl:3.1.160-RC1 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/api/views.py b/sapl/api/views.py index 6f4e9219a..9ddafb9ec 100644 --- a/sapl/api/views.py +++ b/sapl/api/views.py @@ -15,6 +15,7 @@ from django_filters.rest_framework.filterset import FilterSet from django_filters.utils import resolve_field from rest_framework import serializers as rest_serializers from rest_framework.decorators import action +from rest_framework.fields import SerializerMethodField from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet @@ -94,10 +95,15 @@ class SaplApiViewSetConstrutor(): # Define uma classe padrão para serializer caso não tenha sido # criada a classe sapl.api.serializers.{model}Serializer class SaplSerializer(rest_serializers.ModelSerializer): + __str__ = SerializerMethodField() + class Meta: model = _model fields = '__all__' + def get___str__(self, obj): + return str(obj) + # Define uma classe padrão para filtro caso não tenha sido # criada a classe sapl.api.forms.{model}FilterSet class SaplFilterSet(SaplFilterSetMixin): diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 2e292b67d..1e53c78df 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -19,27 +19,25 @@ from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ import django_filters -from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica -from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica +from sapl.audiencia.models import AudienciaPublica from sapl.base.models import Autor, TipoAutor -from sapl.comissoes.models import Reuniao, Comissao -from sapl.comissoes.models import Reuniao, Comissao -from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, - to_row) -from sapl.crispy_layout_mixin import SaplFormHelper -from sapl.materia.models import (MateriaLegislativa, UnidadeTramitacao, StatusTramitacao, - DocumentoAcessorio, TipoMateriaLegislativa) -from sapl.norma.models import (NormaJuridica, NormaEstatisticas) -from sapl.parlamentares.models import SessaoLegislativa, Partido +from sapl.comissoes.models import Reuniao +from sapl.crispy_layout_mixin import (form_actions, to_column, to_row, + SaplFormHelper, SaplFormLayout) +from sapl.materia.models import (DocumentoAcessorio, MateriaEmTramitacao, + MateriaLegislativa, UnidadeTramitacao, + StatusTramitacao) +from sapl.norma.models import NormaJuridica +from sapl.parlamentares.models import Partido, SessaoLegislativa from sapl.protocoloadm.models import DocumentoAdministrativo from sapl.sessao.models import SessaoPlenaria from sapl.settings import MAX_IMAGE_UPLOAD_SIZE -from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, - ChoiceWithoutValidationField, ImageThumbnailFileInput, - RangeWidgetOverride, autor_label, autor_modal, - models_with_gr_for_model, qs_override_django_filter, +from sapl.utils import (autor_label, autor_modal, ChoiceWithoutValidationField, choice_anos_com_normas, choice_anos_com_materias, - FilterOverridesMetaMixin, FileFieldCheckMixin, AnoNumeroOrderingFilter) + FilterOverridesMetaMixin, FileFieldCheckMixin, + AnoNumeroOrderingFilter, ImageThumbnailFileInput, + models_with_gr_for_model, qs_override_django_filter, + RangeWidgetOverride, RANGE_ANOS, YES_NO_CHOICES) from .models import AppConfig, CasaLegislativa @@ -619,6 +617,10 @@ class AutorForm(ModelForm): tipo = cd['tipo'] + if 'nome' in cd and \ + Autor.objects.filter(nome=cd['nome']).exists(): + raise ValidationError("Autor '%s' já existente!" % cd['nome']) + if not tipo.content_type: if 'nome' not in cd or not cd['nome']: self.logger.error('Nome do Autor não informado.') @@ -1236,9 +1238,9 @@ class RelatorioAudienciaFilterSet(django_filters.FilterSet): ) -class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet): +class RelatorioMateriasTramitacaoFilterSet(django_filters.FilterSet): - ano = django_filters.ChoiceFilter(required=True, + materia__ano = django_filters.ChoiceFilter(required=True, label='Ano da Matéria', choices=choice_anos_com_materias) @@ -1252,22 +1254,25 @@ class RelatorioMateriasTramitacaoilterSet(django_filters.FilterSet): @property def qs(self): - parent = super(RelatorioMateriasTramitacaoilterSet, self).qs - return parent.distinct().order_by('-ano', 'tipo', '-numero') + parent = super(RelatorioMateriasTramitacaoFilterSet, self).qs + return parent.distinct().order_by( + '-materia__ano', 'materia__tipo', '-materia__numero' + ) class Meta: - model = MateriaLegislativa - fields = ['ano', 'tipo', 'tramitacao__unidade_tramitacao_destino', + model = MateriaEmTramitacao + fields = ['materia__ano', 'materia__tipo', + 'tramitacao__unidade_tramitacao_destino', 'tramitacao__status'] def __init__(self, *args, **kwargs): - super(RelatorioMateriasTramitacaoilterSet, self).__init__( + super(RelatorioMateriasTramitacaoFilterSet, self).__init__( *args, **kwargs) - self.filters['tipo'].label = 'Tipo de Matéria' + self.filters['materia__tipo'].label = 'Tipo de Matéria' - row1 = to_row([('ano', 12)]) - row2 = to_row([('tipo', 12)]) + row1 = to_row([('materia__ano', 12)]) + row2 = to_row([('materia__tipo', 12)]) row3 = to_row([('tramitacao__unidade_tramitacao_destino', 12)]) row4 = to_row([('tramitacao__status', 12)]) @@ -1797,5 +1802,5 @@ class RelatorioNormasPorAutorFilterSet(django_filters.FilterSet): HTML(autor_label), HTML(autor_modal), row3, - buttons) + form_actions(label='Pesquisar')) ) diff --git a/sapl/base/receivers.py b/sapl/base/receivers.py index b2176be14..f5f19f1f3 100644 --- a/sapl/base/receivers.py +++ b/sapl/base/receivers.py @@ -1,6 +1,5 @@ from django.db.models.signals import post_delete, post_save from django.dispatch import receiver - from sapl.materia.models import Tramitacao from sapl.protocoloadm.models import TramitacaoAdministrativo from sapl.base.signals import tramitacao_signal @@ -30,12 +29,12 @@ def handle_tramitacao_signal(sender, **kwargs): @receiver(post_delete) def status_tramitacao_materia(sender, instance, **kwargs): - if isinstance(sender, TramitacaoAdministrativo): + if sender == Tramitacao: if instance.status.indicador == 'F': materia = instance.materia materia.em_tramitacao = True materia.save() - elif isinstance(sender, TramitacaoAdministrativo): + elif sender == TramitacaoAdministrativo: if instance.status.indicador == 'F': documento = instance.documento documento.tramitacao = True diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 12192ab6f..048778d8d 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -249,8 +249,10 @@ def facebook_url(value): def youtube_id(value): from urllib.parse import urlparse, parse_qs u_pars = urlparse(value) - quer_v = parse_qs(u_pars.query).get('v')[0] - return quer_v + quer_v = parse_qs(u_pars.query).get('v') + if quer_v: + return quer_v[0] + return '' @register.filter diff --git a/sapl/base/tests/test_view_base.py b/sapl/base/tests/test_view_base.py index 6655317b3..75748edd0 100644 --- a/sapl/base/tests/test_view_base.py +++ b/sapl/base/tests/test_view_base.py @@ -24,32 +24,6 @@ from sapl.base.views import (protocolos_duplicados, protocolos_com_materias, bancada_comissao_autor_externo, anexados_ciclicos) -@pytest.mark.django_db(transaction=False) -def test_lista_protocolos_duplicados(): - mommy.make( - Protocolo, - numero=15, - ano=2031 - ) - mommy.make( - Protocolo, - numero=15, - ano=2031 - ) - mommy.make( - Protocolo, - numero=33, - ano=2033 - ) - - lista_protocolos_duplicados = protocolos_duplicados() - - assert len(lista_protocolos_duplicados) == 1 - assert lista_protocolos_duplicados[0][1] == 2 - assert lista_protocolos_duplicados[0][0].numero == 15 - assert lista_protocolos_duplicados[0][0].ano == 2031 - - @pytest.mark.django_db(transaction=False) def test_lista_protocolos_com_materias(): mommy.make( @@ -194,13 +168,13 @@ def test_lista_parlamentares_duplicados(): sexo='M' ) - lista_dict_values_parlamentares_duplicados = parlamentares_duplicados() + lista_dict_parlamentares_duplicados = parlamentares_duplicados() parlamentar_duplicado = list( - lista_dict_values_parlamentares_duplicados[0] + lista_dict_parlamentares_duplicados[0].values() ) parlamentar_duplicado.sort(key=str) - assert len(lista_dict_values_parlamentares_duplicados) == 1 + assert len(lista_dict_parlamentares_duplicados) == 1 assert parlamentar_duplicado == [2, "Nome_Parlamentar_Teste"] diff --git a/sapl/base/views.py b/sapl/base/views.py index 7f26808d2..df5a1c0f7 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -13,7 +13,8 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, Validat from django.core.mail import send_mail from django.core.urlresolvers import reverse, reverse_lazy from django.db import connection -from django.db.models import Count, Q, ProtectedError +from django.db.models import Count, Q, ProtectedError, Max +from django.shortcuts import render from django.http import Http404, HttpResponseRedirect, JsonResponse from django.template import TemplateDoesNotExist from django.template.loader import get_template @@ -39,23 +40,26 @@ from sapl.relatorios.views import (relatorio_materia_em_tramitacao, relatorio_ma from sapl import settings from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica -from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm from sapl.base.models import Autor, TipoAutor -from sapl.comissoes.models import Reuniao, Comissao +from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm +from sapl.comissoes.models import Comissao, Reuniao from sapl.crud.base import CrudAux, make_pagination -from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao, Anexada, - TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao, - DocumentoAcessorio, TipoDocumento) -from sapl.norma.models import (NormaJuridica, TipoNormaJuridica, NormaEstatisticas) -from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato, Filiacao, SessaoLegislativa -from sapl.protocoloadm.models import (Protocolo, TipoDocumentoAdministrativo, - StatusTramitacaoAdministrativo, - DocumentoAdministrativo, Anexado) -from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, - SessaoPlenariaPresenca, Bancada, TipoSessaoPlenaria) -from sapl.utils import (parlamentares_ativos, gerar_hash_arquivo, SEPARADOR_HASH_PROPOSICAO, - show_results_filter_set, mail_service_configured, - intervalos_tem_intersecao, remover_acentos) +from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio, + MateriaEmTramitacao, MateriaLegislativa, Proposicao, + StatusTramitacao, TipoDocumento, + TipoMateriaLegislativa, UnidadeTramitacao, Tramitacao) +from sapl.norma.models import NormaJuridica, TipoNormaJuridica +from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, Parlamentar, + SessaoLegislativa) +from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, Protocolo, + StatusTramitacaoAdministrativo, + 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) + from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, RelatorioAudienciaFilterSet, @@ -63,7 +67,7 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, RelatorioHistoricoTramitacaoFilterSet, RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasPorAutorFilterSet, - RelatorioMateriasTramitacaoilterSet, + RelatorioMateriasTramitacaoFilterSet, RelatorioPresencaSessaoFilterSet, RelatorioReuniaoFilterSet, UsuarioCreateForm, UsuarioEditForm, RelatorioNormasMesFilterSet, @@ -75,19 +79,6 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, from .models import AppConfig, CasaLegislativa -def filtra_url_materias_em_tramitacao(qr, qs, campo_url, local_ou_status): - id_materias = [] - filtro_url = qr[campo_url] - if local_ou_status == 'local': - id_materias = [item.id for item in qs if item.tramitacao_set.order_by( - '-id').first().unidade_tramitacao_destino_id == int(filtro_url)] - elif local_ou_status == 'status': - id_materias = [item.id for item in qs if item.tramitacao_set.order_by( - '-id').first().status_id == int(filtro_url)] - - return qs.filter(em_tramitacao=True, id__in=id_materias) - - def get_casalegislativa(): return CasaLegislativa.objects.first() @@ -731,62 +722,109 @@ class RelatorioAudienciaView(RelatorioMixin, FilterView): class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView): - model = MateriaLegislativa - filterset_class = RelatorioMateriasTramitacaoilterSet + model = MateriaEmTramitacao + filterset_class = RelatorioMateriasTramitacaoFilterSet template_name = 'base/RelatorioMateriasPorTramitacao_filter.html' relatorio = relatorio_materia_em_tramitacao + paginate_by = 100 + + total_resultados_tipos = {} + + def get_filterset_kwargs(self, filterset_class): + data = super().get_filterset_kwargs(filterset_class) + + if data['data']: + qs = data['queryset'] + + ano_materia = data['data']['materia__ano'] + tipo_materia = data['data']['materia__tipo'] + unidade_tramitacao_destino = data['data']['tramitacao__unidade_tramitacao_destino'] + status_tramitacao = data['data']['tramitacao__status'] + + kwargs = {} + if ano_materia: + kwargs['materia__ano'] = ano_materia + if tipo_materia: + kwargs['materia__tipo'] = tipo_materia + if unidade_tramitacao_destino: + kwargs['tramitacao__unidade_tramitacao_destino'] = unidade_tramitacao_destino + if status_tramitacao: + kwargs['tramitacao__status'] = status_tramitacao + qs = qs.filter(**kwargs) + + data['queryset'] = qs + + qtdes = { tipo:0 for tipo in TipoMateriaLegislativa.objects.all() } + for i in qs: + qtdes[i.materia.tipo] += 1 + + # remove as entradas de valor igual a zero + qtdes = {k:v for k,v in qtdes.items() if v > 0} + self.total_resultados_tipos = qtdes + + return data + + def get_queryset(self): + qs = super().get_queryset() + qs = qs.select_related('materia__tipo').filter( + materia__em_tramitacao=True + ).exclude( + tramitacao__status__indicador='F' + ).order_by('-materia__ano', '-materia__numero') + return qs + def get_context_data(self, **kwargs): - context = super(RelatorioMateriasTramitacaoView, - self).get_context_data(**kwargs) + context = super( + RelatorioMateriasTramitacaoView, self + ).get_context_data(**kwargs) context['title'] = _('Matérias em Tramitação') + if not self.filterset.form.is_valid(): return context qr = self.request.GET.copy() - qs = context['object_list'] - qs = qs.filter(em_tramitacao=True) - - if qr.get('tramitacao__unidade_tramitacao_destino'): - qs = filtra_url_materias_em_tramitacao( - qr, qs, 'tramitacao__unidade_tramitacao_destino', 'local') - if qr.get('tramitacao__status'): - qs = filtra_url_materias_em_tramitacao( - qr, qs, 'tramitacao__status', 'status') - li = [li1 for li1 in qs if li1.tramitacao_set.last() and li1.tramitacao_set.last().status.indicador != 'F'] - context['object_list'] = li + context['qtdes'] = self.total_resultados_tipos + context['ano'] = (self.request.GET['materia__ano']) - qtdes = {} - for tipo in TipoMateriaLegislativa.objects.all(): - li = context['object_list'] - qtde = sum(1 for i in li if i.tipo_id==tipo.id) - if qtde > 0: - qtdes[tipo] = qtde - context['qtdes'] = qtdes - context['ano'] = (self.request.GET['ano']) - if self.request.GET['tipo']: - tipo = self.request.GET['tipo'] + if self.request.GET['materia__tipo']: + tipo = self.request.GET['materia__tipo'] context['tipo'] = ( - str(TipoMateriaLegislativa.objects.get(id=tipo))) + str(TipoMateriaLegislativa.objects.get(id=tipo)) + ) else: context['tipo'] = '' + if self.request.GET['tramitacao__status']: tramitacao_status = self.request.GET['tramitacao__status'] context['tramitacao__status'] = ( - str(StatusTramitacao.objects.get(id=tramitacao_status))) + str(StatusTramitacao.objects.get(id=tramitacao_status)) + ) else: context['tramitacao__status'] = '' + if self.request.GET['tramitacao__unidade_tramitacao_destino']: - context['tramitacao__unidade_tramitacao_destino'] = (str(UnidadeTramitacao.objects.get( - id=self.request.GET['tramitacao__unidade_tramitacao_destino']))) + context['tramitacao__unidade_tramitacao_destino'] = ( + str(UnidadeTramitacao.objects.get( + id=self.request.GET['tramitacao__unidade_tramitacao_destino'] + )) + ) else: context['tramitacao__unidade_tramitacao_destino'] = '' + context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' - context['show_results'] = show_results_filter_set(qr) + paginator = context['paginator'] + page_obj = context['page_obj'] + + context['page_range'] = make_pagination( + page_obj.number, paginator.num_pages + ) + context['NO_ENTRIES_MSG'] = 'Nenhum encontrado.' + return context @@ -1471,7 +1509,7 @@ class ListarParlMandatosIntersecaoView(PermissionRequiredMixin, ListView): def parlamentares_duplicados(): - return [parlamentar.values() for parlamentar in Parlamentar.objects.values( + return [parlamentar for parlamentar in Parlamentar.objects.values( 'nome_parlamentar').order_by('nome_parlamentar').annotate(count=Count( 'nome_parlamentar')).filter(count__gt=1)] @@ -1656,14 +1694,10 @@ class ListarProtocolosComMateriasView(PermissionRequiredMixin, ListView): def protocolos_duplicados(): - protocolos = {} - for p in Protocolo.objects.order_by('-ano', 'numero'): - key = "{}/{}".format(p.numero, p.ano) - val = protocolos.get(key, list()) - val.append(p) - protocolos[key] = val - - return [(v[0], len(v)) for (k, v) in protocolos.items() if len(v) > 1] + return [ + protocolo for protocolo in Protocolo.objects.values( + 'numero', 'ano').order_by('-ano', 'numero').annotate(total=Count('numero')).filter(total__gt=1) + ] class ListarProtocolosDuplicadosView(PermissionRequiredMixin, ListView): diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index 5fa132eab..0b5ca756d 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -167,7 +167,7 @@ class ComissaoCrud(Crud): def lista_materias_comissao(comissao_pk): ts = Tramitacao.objects.order_by( - 'materia', '-data_tramitacao', '-id').annotate( + 'materia_id', '-data_tramitacao', '-id').annotate( comissao=F('unidade_tramitacao_destino__comissao')).distinct( 'materia').values_list('materia', 'comissao') diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 671e5bcf1..d27d85f1a 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -195,8 +195,13 @@ class IntegracaoTaView(TemplateView): return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit', kwargs={'ta_id': ta.pk})) else: - return redirect(to=reverse_lazy('sapl.compilacao:ta_text', - kwargs={'ta_id': ta.pk})) + return redirect( + to='%s?%s' % ( + reverse_lazy('sapl.compilacao:ta_text', + kwargs={'ta_id': ta.pk}), + request.META['QUERY_STRING'] + ) + ) class Meta: abstract = True diff --git a/sapl/crud/base.py b/sapl/crud/base.py index 98af2a3bb..18f3d5c29 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -4,13 +4,14 @@ from braces.views import FormMessagesMixin from crispy_forms.bootstrap import FieldWithButtons, StrictButton from crispy_forms.layout import Field, Layout from django import forms +from django.conf import settings from django.conf.urls import url from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.db import models -from django.db.models.fields.related import ForeignKey +from django.db.models.fields.related import ForeignKey, ManyToManyField from django.http.response import Http404 from django.shortcuts import redirect from django.utils.decorators import classonlymethod @@ -27,10 +28,12 @@ from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display from sapl.crispy_layout_mixin import SaplFormHelper from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST) -from sapl.settings import BASE_DIR from sapl.utils import normalize +logger = logging.getLogger(settings.BASE_DIR.name) + + ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ 'list', 'create', 'detail', 'update', 'delete' @@ -122,7 +125,6 @@ class SearchMixin(models.Model): except Exception as e: username = self.request.user.username self.logger.error("user=" + username + ". " + str(e)) - pass else: _self = self for field in fields: @@ -206,6 +208,7 @@ class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin): if not self.model.objects.filter(**params).exists(): raise Http404() + elif self.container_field: container = self.container_field.split('__') @@ -230,14 +233,14 @@ class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin): return super(PermissionRequiredMixin, self).dispatch( request, *args, **kwargs) - @cached_property + @property def container_field(self): if hasattr(self, 'crud') and not hasattr(self.crud, 'container_field'): self.crud.container_field = '' if hasattr(self, 'crud'): return self.crud.container_field - @cached_property + @property def container_field_set(self): if hasattr(self, 'crud') and\ not hasattr(self.crud, 'container_field_set'): @@ -245,7 +248,7 @@ class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin): if hasattr(self, 'crud'): return self.crud.container_field_set - @cached_property + @property def is_contained(self): return self.container_field_set or self.container_field @@ -600,7 +603,7 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView): # print(ordering) except Exception as e: - print(string_concat(_( + logger.error(string_concat(_( 'ERRO: construção da tupla de ordenação.'), str(e))) # print(queryset.query) @@ -1108,12 +1111,14 @@ class MasterDetailCrud(Crud): permission_required = RP_LIST, logger = logging.getLogger(__name__) + def get(self, request, *args, **kwargs): + return Crud.ListView.get(self, request, *args, **kwargs) + @classmethod def get_url_regex(cls): return r'^(?P\d+)/%s$' % cls.model._meta.model_name def get_context_data(self, **kwargs): - obj = self.crud if hasattr(self, 'crud') else self context = CrudListView.get_context_data(self, **kwargs) @@ -1133,7 +1138,12 @@ class MasterDetailCrud(Crud): else: parent_model = getattr( - self.model, obj.parent_field).field.related_model + self.model, obj.parent_field) + if isinstance(parent_model.field, ( + ForeignKey, ManyToManyField)): + parent_model = parent_model.field.related_model + else: + parent_model = parent_model.rel.related_model params = {'pk': kwargs['root_pk']} @@ -1165,6 +1175,9 @@ class MasterDetailCrud(Crud): return qs.filter(**kwargs) + def dispatch(self, request, *args, **kwargs): + return PermissionRequiredMixin.dispatch(self, request, *args, **kwargs) + class CreateView(Crud.CreateView): permission_required = RP_ADD, logger = logging.getLogger(__name__) @@ -1229,8 +1242,12 @@ class MasterDetailCrud(Crud): parent_object = getattr(parent_object, field) else: - parent_model = getattr( - parent_model, obj.parent_field).field.related_model + parent_model = getattr(self.model, obj.parent_field) + if isinstance(parent_model.field, ForeignKey): + parent_model = parent_model.field.related_model + else: + parent_model = parent_model.rel.related_model + parent_object = parent_model.objects.get(**params) context['root_pk'] = parent_object.pk diff --git a/sapl/materia/migrations/0056_popula_materiaemtramitacao.py b/sapl/materia/migrations/0056_popula_materiaemtramitacao.py new file mode 100644 index 000000000..dfa4c0175 --- /dev/null +++ b/sapl/materia/migrations/0056_popula_materiaemtramitacao.py @@ -0,0 +1,23 @@ +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0055_auto_20190816_0943'), + ] + + operations = [ + migrations.RunSQL(""" + create or replace view materia_materiaemtramitacao as + select m.id as id, + m.id as materia_id, + t.id as tramitacao_id + from materia_materialegislativa m + inner join materia_tramitacao t on (m.id = t.materia_id) + where t.id = (select max(id) from materia_tramitacao where materia_id = m.id) + order by m.id DESC + """), + ] \ No newline at end of file diff --git a/sapl/materia/migrations/0057_materiaemtramitacao.py b/sapl/materia/migrations/0057_materiaemtramitacao.py new file mode 100644 index 000000000..95953f50b --- /dev/null +++ b/sapl/materia/migrations/0057_materiaemtramitacao.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-08-27 20:13 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0056_popula_materiaemtramitacao'), + ] + + operations = [ + migrations.CreateModel( + name='MateriaEmTramitacao', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'db_table': 'materia_materiaemtramitacao', + 'managed': False, + }, + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index b641377de..77203e0e4 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -1084,3 +1084,15 @@ class Tramitacao(models.Model): 'materia': self.materia, 'status': self.status, 'data': self.data_tramitacao.strftime("%d/%m/%Y")} + + +class MateriaEmTramitacao(models.Model): + materia = models.ForeignKey(MateriaLegislativa, on_delete=models.DO_NOTHING) + tramitacao = models.ForeignKey(Tramitacao, on_delete=models.DO_NOTHING) + + class Meta: + managed = False + db_table = "materia_materiaemtramitacao" + + def __str__(self): + return '{}/{}'.format(self.materia, self.tramitacao) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 2b5dc5697..94f10f539 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -772,7 +772,7 @@ class ProposicaoCrud(Crud): context['title'] = '%s (%s)' % ( self.object, self.object.autor) - + context['user'] = self.request.user context['proposicao'] = Proposicao.objects.get( pk=self.kwargs['pk'] @@ -782,7 +782,8 @@ class ProposicaoCrud(Crud): def get(self, request, *args, **kwargs): action = request.GET.get('action', '') - username = request.user.username + user = request.user + username = user.username if not action: return Crud.DetailView.get(self, request, *args, **kwargs) @@ -790,7 +791,7 @@ class ProposicaoCrud(Crud): p = Proposicao.objects.get(id=kwargs['pk']) msg_error = '' - if p: + if p and p.autor.user == user: if action == 'send': if p.data_envio and p.data_recebimento: msg_error = _('Proposição já foi enviada e recebida.') diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 859de2850..cae67d2ab 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -302,9 +302,7 @@ class AnularProtocoloAdmForm(ModelForm): class Meta: model = Protocolo - fields = ['numero', - 'ano', - 'justificativa_anulacao', + fields = ['justificativa_anulacao', 'anulado', 'user_anulacao', 'ip_anulacao', diff --git a/sapl/protocoloadm/migrations/0022_deduplica_protocolos.py b/sapl/protocoloadm/migrations/0022_deduplica_protocolos.py new file mode 100644 index 000000000..790030a5f --- /dev/null +++ b/sapl/protocoloadm/migrations/0022_deduplica_protocolos.py @@ -0,0 +1,25 @@ +from __future__ import unicode_literals + +from django.db import migrations + + +def deduplica_protocolos(apps, schema_editor): + from sapl.base.views import protocolos_duplicados + + Protocolo = apps.get_model('protocoloadm', 'Protocolo') + + protocolos = protocolos_duplicados() + for protocolo in protocolos: + protocolo_principal = Protocolo.objects.filter(numero=protocolo['numero'], ano=protocolo['ano']).order_by('-id')[0] + Protocolo.objects.filter(numero=protocolo['numero'], ano=protocolo['ano']).exclude(id=protocolo_principal.id).delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0021_merge_20190429_1531'), + ] + + operations = [ + migrations.RunPython(deduplica_protocolos) + ] diff --git a/sapl/protocoloadm/migrations/0023_auto_20190711_1755.py b/sapl/protocoloadm/migrations/0023_auto_20190711_1755.py new file mode 100644 index 000000000..70620c8f7 --- /dev/null +++ b/sapl/protocoloadm/migrations/0023_auto_20190711_1755.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-07-11 20:55 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0022_deduplica_protocolos'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='protocolo', + unique_together=set([('numero', 'ano')]), + ), + ] diff --git a/sapl/protocoloadm/migrations/0024_merge_20190821_1418.py b/sapl/protocoloadm/migrations/0024_merge_20190821_1418.py new file mode 100644 index 000000000..6bd5eea65 --- /dev/null +++ b/sapl/protocoloadm/migrations/0024_merge_20190821_1418.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-08-21 17:18 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0023_auto_20190711_1755'), + ('protocoloadm', '0023_merge_20190802_1112'), + ] + + operations = [ + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 5f67054a4..4993b84e7 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -120,6 +120,7 @@ class Protocolo(models.Model): permissions = ( ('action_anular_protocolo', _('Permissão para Anular Protocolo')), ) + unique_together = ('numero', 'ano',) def __str__(self): return _('%(numero)s/%(ano)s') % { diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index a1a8b05d4..f8135e1bc 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -34,10 +34,10 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa, Unid from sapl.materia.views import gerar_pdf_impressos from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.protocoloadm.models import Protocolo +from sapl.relatorios.views import relatorio_doc_administrativos from sapl.utils import (create_barcode, get_base_url, get_client_ip, get_mime_type_from_file_extension, lista_anexados, show_results_filter_set, mail_service_configured) -from sapl.relatorios.views import relatorio_doc_administrativos from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm, DocumentoAcessorioAdministrativoForm, @@ -290,7 +290,7 @@ class AcompanhamentoDocumentoView(CreateView): de mensagens e clique no link que nós enviamos para \ confirmar o acompanhamento deste documento.') messages.add_message(request, messages.SUCCESS, msg) - + # Caso esse Acompanhamento já exista # avisa ao usuário que esse documento já está sendo acompanhado else: @@ -302,7 +302,7 @@ class AcompanhamentoDocumentoView(CreateView): return self.render_to_response( {'form': form, 'documento': documento, - }) + }) return HttpResponseRedirect(self.get_success_url()) else: return self.render_to_response( @@ -373,13 +373,13 @@ class DocumentoAdministrativoCrud(Crud): return redirect('/') return super(Crud.DetailView, self).get(args, kwargs) - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - self.layout_display[0]['rows'][-1][0]['text'] = ( - '' % reverse( + def urlize(self, obj, fieldname): + a = '%s' % ( + reverse( 'sapl.protocoloadm:doc_texto_integral', - kwargs={'pk': self.object.pk})) - return context + kwargs={'pk': obj.pk}), + obj.texto_integral.name.split('/')[-1]) + return obj.texto_integral.field.verbose_name, a class DeleteView(Crud.DeleteView): @@ -700,6 +700,13 @@ class ComprovanteProtocoloView(PermissionRequiredMixin, TemplateView): autenticacao = str(protocolo.tipo_processo) + \ data + str(protocolo.numero).zfill(6) + if protocolo.tipo_materia: + materia = MateriaLegislativa.objects.filter( + numero_protocolo=protocolo.numero, + ano=protocolo.ano).first() + if materia: + context['materia'] = materia.numero + context.update({"protocolo": protocolo, "barcode": barcode, "autenticacao": autenticacao}) @@ -910,7 +917,7 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, page_obj = context['page_obj'] context['page_range'] = make_pagination( page_obj.number, paginator.num_pages) - + return context def get(self, request, *args, **kwargs): @@ -935,21 +942,22 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, length = self.object_list.filter(restrito=False).count() else: length = self.object_list.count() - - is_relatorio = url!='' and request.GET.get('relatorio',None) - self.paginate_by = None if is_relatorio else self.paginate_by + + is_relatorio = url != '' and request.GET.get('relatorio', None) + self.paginate_by = None if is_relatorio else self.paginate_by context = self.get_context_data(filter=self.filterset, filter_url=url, numero_res=length ) context['show_results'] = show_results_filter_set( self.request.GET.copy()) - + if is_relatorio: - return relatorio_doc_administrativos(request,context) - else: + return relatorio_doc_administrativos(request, context) + else: return self.render_to_response(context) - + + class AnexadoCrud(MasterDetailCrud): model = Anexado parent_field = 'documento_principal' @@ -987,7 +995,7 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView): def get_context_data(self, **kwargs): context = super( DocumentoAnexadoEmLoteView, self - ).get_context_data(**kwargs) + ).get_context_data(**kwargs) context['root_pk'] = self.kwargs['pk'] @@ -997,17 +1005,17 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView): # Verifica se os campos foram preenchidos if not self.request.GET.get('tipo', " "): - msg =_('Por favor, selecione um tipo de documento.') + msg = _('Por favor, selecione um tipo de documento.') messages.add_message(self.request, messages.ERROR, msg) - + if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "): - msg =_('Por favor, preencha as datas.') + msg = _('Por favor, preencha as datas.') messages.add_message(self.request, messages.ERROR, msg) return context if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "): - msg =_('Por favor, preencha as datas.') + msg = _('Por favor, preencha as datas.') messages.add_message(self.request, messages.ERROR, msg) return context @@ -1019,17 +1027,19 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView): context['object_list'] = [] for obj in context['temp_object_list']: if not obj.pk == int(context['root_pk']): - documento_principal = DocumentoAdministrativo.objects.get(id=context['root_pk']) + documento_principal = DocumentoAdministrativo.objects.get( + id=context['root_pk']) documento_anexado = obj is_anexado = Anexado.objects.filter(documento_principal=documento_principal, documento_anexado=documento_anexado).exists() if not is_anexado: ciclico = False - anexados_anexado = Anexado.objects.filter(documento_principal=documento_anexado) + anexados_anexado = Anexado.objects.filter( + documento_principal=documento_anexado) while anexados_anexado and not ciclico: anexados = [] - + for anexo in anexados_anexado: if documento_principal == anexo.documento_anexado: @@ -1042,18 +1052,18 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView): if not ciclico: context['object_list'].append(obj) - + context['numero_res'] = len(context['object_list']) 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): marcados = request.POST.getlist('documento_id') - + data_anexacao = datetime.strptime( request.POST['data_anexacao'], "%d/%m/%Y" ).date() @@ -1068,22 +1078,22 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView): v_data_desanexacao = data_desanexacao if len(marcados) == 0: - msg =_('Nenhum documento foi selecionado') + msg = _('Nenhum documento foi selecionado') messages.add_message(request, messages.ERROR, msg) - + if data_anexacao > v_data_desanexacao: - msg=_('Data de anexação posterior à data de desanexação.') + msg = _('Data de anexação posterior à data de desanexação.') messages.add_message(request, messages.ERROR, msg) - + return self.get(request, self.kwargs) if data_anexacao > v_data_desanexacao: - msg =_('Data de anexação posterior à data de desanexação.') + msg = _('Data de anexação posterior à data de desanexação.') messages.add_message(request, messages.ERROR, msg) return self.get(request, messages.ERROR, msg) - principal = DocumentoAdministrativo.objects.get(pk = kwargs['pk']) - for documento in DocumentoAdministrativo.objects.filter(id__in = marcados): + principal = DocumentoAdministrativo.objects.get(pk=kwargs['pk']) + for documento in DocumentoAdministrativo.objects.filter(id__in=marcados): anexado = Anexado() anexado.documento_principal = principal anexado.documento_anexado = documento @@ -1094,7 +1104,8 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView): msg = _('Documento(s) anexado(s).') messages.add_message(request, messages.SUCCESS, msg) - success_url = reverse('sapl.protocoloadm:anexado_list', kwargs={'pk': kwargs['pk']}) + success_url = reverse('sapl.protocoloadm:anexado_list', kwargs={ + 'pk': kwargs['pk']}) return HttpResponseRedirect(success_url) @@ -1142,7 +1153,8 @@ class TramitacaoAdmCrud(MasterDetailCrud): '-timestamp', '-id').first() - #TODO: Esta checagem foi inserida na issue #2027, mas é mesmo necessária? + # TODO: Esta checagem foi inserida na issue #2027, mas é mesmo + # necessária? if ultima_tramitacao: if ultima_tramitacao.unidade_tramitacao_destino: context['form'].fields[ @@ -1224,13 +1236,12 @@ class TramitacaoAdmCrud(MasterDetailCrud): MasterDetailCrud.DetailView): template_name = 'protocoloadm/tramitacaoadministrativo_detail.html' - + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['user'] = self.request.user return context - class DeleteView(MasterDetailCrud.DeleteView): logger = logging.getLogger(__name__) @@ -1271,7 +1282,8 @@ class TramitacaoAdmCrud(MasterDetailCrud): if da.tramitacaoadministrativo_set.count() == 0: da.tramitacao = False da.save() - TramitacaoAdministrativo.objects.filter(id__in=tramitacoes_deletar).delete() + TramitacaoAdministrativo.objects.filter( + id__in=tramitacoes_deletar).delete() return HttpResponseRedirect(url) @@ -1464,7 +1476,6 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView): logger = logging.getLogger(__name__) - def get_context_data(self, **kwargs): context = super(PrimeiraTramitacaoEmLoteAdmView, self).get_context_data(**kwargs) @@ -1486,8 +1497,8 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView): 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] + 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( @@ -1509,32 +1520,33 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView): 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}) + form = TramitacaoEmLoteAdmForm(request.POST, + initial={'documentos': documentos_ids, + 'user': user, 'ip': ip}) if form.is_valid(): form.save() msg = _('Tramitação completa.') - self.logger.info('user=' + user.username + '. Tramitação completa.') + self.logger.info('user=' + user.username + + '. Tramitação completa.') messages.add_message(request, messages.SUCCESS, msg) return self.get_success_url() return self.form_invalid(form) - def get_success_url(self): return HttpResponseRedirect(reverse('sapl.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] + if not key == '__all__': + [messages.add_message( + self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros] else: - [messages.add_message(self.request, messages.ERROR, e) for e in erros] - return self.get(self.request, kwargs, {'form':form}) + [messages.add_message(self.request, messages.ERROR, e) + for e in erros] + return self.get(self.request, kwargs, {'form': form}) class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView): @@ -1562,21 +1574,18 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView): 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( @@ -1584,7 +1593,6 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView): 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( diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 4f1b4b515..aa187477d 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -127,6 +127,7 @@ rules_group_materia = { ['can_access_impressos'], __perms_publicas__), (materia.Numeracao, __base__, __perms_publicas__), (materia.Tramitacao, __base__, __perms_publicas__), + (materia.MateriaEmTramitacao, __base__, __perms_publicas__), (norma.LegislacaoCitada, __base__, __perms_publicas__), (norma.AutoriaNorma, __base__, __perms_publicas__), (compilacao.Dispositivo, __base__ + [ diff --git a/sapl/settings.py b/sapl/settings.py index c9764545c..c97f2311a 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*'] LOGIN_REDIRECT_URL = '/' LOGIN_URL = '/login/?next=' -SAPL_VERSION = '3.1.160-RC0' +SAPL_VERSION = '3.1.160-RC1' if DEBUG: EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' diff --git a/sapl/templates/base.html b/sapl/templates/base.html index d9f63f74f..64d296c94 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -179,7 +179,7 @@ Desenvolvido pelo Interlegis em software livre e aberto. - Release: 3.1.160-RC0 + Release: 3.1.160-RC1

diff --git a/sapl/templates/base/RelatorioMateriasPorTramitacao_filter.html b/sapl/templates/base/RelatorioMateriasPorTramitacao_filter.html index 02cad5e43..738e615b8 100644 --- a/sapl/templates/base/RelatorioMateriasPorTramitacao_filter.html +++ b/sapl/templates/base/RelatorioMateriasPorTramitacao_filter.html @@ -44,17 +44,20 @@ - {% for materia in object_list %} + {% for materia_em_tramitacao in object_list %} - - {{materia.tipo.descricao}} {{materia.numero}}/{{materia.ano}} - - {{materia.tramitacao_set.last.unidade_tramitacao_destino}} - {{materia.tramitacao_set.last.status}} + + + {{ materia_em_tramitacao.materia.tipo.descricao }} {{ materia_em_tramitacao.materia.numero }}/{{ materia_em_tramitacao.materia.ano }} + + + {{ materia_em_tramitacao.materia.tramitacao_set.last.unidade_tramitacao_destino }} + {{ materia_em_tramitacao.materia.tramitacao_set.last.status }} {% endfor %} {% endif %} - + {% include 'paginacao.html' %} +
{% endblock base_content %} diff --git a/sapl/templates/base/parlamentares_duplicados.html b/sapl/templates/base/parlamentares_duplicados.html index 0bb86e2ce..a7727f342 100644 --- a/sapl/templates/base/parlamentares_duplicados.html +++ b/sapl/templates/base/parlamentares_duplicados.html @@ -15,12 +15,12 @@ - {% for quantidade, parlamentar in parlamentares_duplicados %} + {% for parlamentar in parlamentares_duplicados %} - {{ parlamentar }} + {{ parlamentar.nome_parlamentar }} - {{ quantidade }} + {{ parlamentar.count }} {% endfor %} diff --git a/sapl/templates/base/protocolos_duplicados.html b/sapl/templates/base/protocolos_duplicados.html index 6a45a0045..be71fc499 100644 --- a/sapl/templates/base/protocolos_duplicados.html +++ b/sapl/templates/base/protocolos_duplicados.html @@ -15,12 +15,14 @@ - {% for protocolo, quantidade in protocolos_duplicados %} + {% for protocolo in protocolos_duplicados %} - {{ protocolo }} + + {{ protocolo.numero }}/{{ protocolo.ano }} + - {{ quantidade }} + {{ protocolo.total }} {% endfor %} diff --git a/sapl/templates/materia/proposicao_detail.html b/sapl/templates/materia/proposicao_detail.html index b35d3de8b..487cc8600 100644 --- a/sapl/templates/materia/proposicao_detail.html +++ b/sapl/templates/materia/proposicao_detail.html @@ -3,204 +3,213 @@ {% load tz %} {% block sub_actions %} {{block.super}} -
- {% if object.texto_articulado.exists %} - {% trans "Texto Eletrônico" %} - {% endif %} - {% if object.texto_original %} - {% trans "Texto Original" %} - {% endif %} -
+ {% if user == object.autor.user %} +
+ {% if object.texto_articulado.exists %} + {% trans "Texto Eletrônico" %} + {% endif %} + {% if object.texto_original %} + {% trans "Texto Original" %} + {% endif %} +
+ {% endif %} {% endblock sub_actions%} {% block editions %} - {% if object.data_envio %} - {% if user == object.autor.user %} - {% block editions_actions_return %} + {% if user == object.autor.user %} + {% if object.data_envio %} + {% block editions_actions_return %} +
+ {% trans "Recibo de Envio" %} + {% if not object.data_recebimento %} + {% trans 'Retornar Proposição Enviada' %} + {% endif %} +
+ {% endblock %} + {% else %} + {% block editions_actions_send %}
- {% trans "Recibo de Envio" %} - {% if not object.data_recebimento %} - {% trans 'Retornar Proposição Enviada' %} - {% endif %} + {% trans 'Enviar' %} +
+ {% endblock %} {% endif %} - {% else %} - {% block editions_actions_send %} - - - {% endblock %} {% endif %} {% endblock editions %} {% block detail_content %} -

{% model_verbose_name 'sapl.materia.models.Proposicao' %}

-
-
-
-

{%field_verbose_name object 'tipo'%}

-
-
{{object.tipo}}
+ {% if user == object.autor.user %} +

{% model_verbose_name 'sapl.materia.models.Proposicao' %}

+
+
+
+

{%field_verbose_name object 'tipo'%}

+
+
{{object.tipo}}
+
-
- {% if object.data_devolucao %} -
- - {% else %} - {% if object.data_envio %} -
-
-

{%field_verbose_name object 'data_envio' %}

-
-
{{object.data_envio}}
+ {% else %} + {% if object.data_envio %} +
+
+

{%field_verbose_name object 'data_envio' %}

+
+
{{object.data_envio}}
+
-
- {% endif %} - {% if object.data_recebimento %} -
-
-

{%field_verbose_name object 'data_recebimento'%}

-
-
{{object.data_recebimento}}
+ {% endif %} + {% if object.data_recebimento %} +
+
+

{%field_verbose_name object 'data_recebimento'%}

+
+
{{object.data_recebimento}}
+
-
- {% elif object.data_envio %} -
- + {% endif %} {% endif %} - {% endif %} -
-
-
-
-

{%field_verbose_name object 'descricao'%}

-
-
{{object.descricao}}
-
-
-
- {% if object.observacao %}
-
-

{%field_verbose_name object 'observacao'%}

+
+

{%field_verbose_name object 'descricao'%}

-
{{object.observacao}}
+
{{object.descricao}}
- {% endif %} -
- {% if object.conteudo_gerado_related %} -
-

{% trans "Conteúdo Gerado" %}

-