diff --git a/compilacao/models.py b/compilacao/models.py index 9fc246519..70cb373fd 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -122,7 +122,7 @@ class TextoArticulado(TimestampedMixin): if self.content_object: return str(self.content_object) else: - return _('Texto Articulado nº %(numero)s de %(data)s') % { + return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo_ta, 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")} diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index 61e7353b2..ed8eb757d 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -156,4 +156,9 @@ def nomenclatura_heranca(d, ignore_ultimo=0, ignore_primeiro=0): @register.simple_tag def verbose_name(instance, field_name): - return instance._meta.get_field(field_name).verbose_name.title() + return instance._meta.get_field(field_name).verbose_name + + +@register.filter +def urldetail_content_type(obj): + return '%s:detail' % obj.content_type.model diff --git a/compilacao/urls.py b/compilacao/urls.py index 933fcfebb..af134f869 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -11,7 +11,6 @@ urlpatterns_compilacao = [ url(r'^(?P[0-9]+)/delete$', views.TaDeleteView.as_view(), name='ta_delete'), - url(r'^(?P[0-9]+)/text$', views.TextView.as_view(), name='ta_text'), url(r'^(?P[0-9]+)/text/vigencia/(?P.+)/$', @@ -20,10 +19,17 @@ urlpatterns_compilacao = [ url(r'^(?P[0-9]+)/text/edit', views.TextEditView.as_view(), name='ta_text_edit'), - url(r'^(?P[0-9]+)/text/(?P[0-9]+)/$', views.DispositivoView.as_view(), name='dispositivo'), + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/refresh', + views.DispositivoEditView.as_view(), name='dispositivo_edit'), + + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/actions', + views.ActionsEditView.as_view(), name='dispositivo_actions'), + + + url(r'^(?P[0-9]+)/text/' '(?P[0-9]+)/nota/create$', views.NotasCreateView.as_view(), name='nota_create'), @@ -56,13 +62,3 @@ urlpatterns_compilacao = [ urlpatterns = [ url(r'^ta/', include(urlpatterns_compilacao)), ] - - -""" - url(r'^(?P[0-9]+)/compilacao/(?P[0-9]+)/refresh', - views.DispositivoEditView.as_view(), name='dispositivo_edit'), - - url(r'^(?P[0-9]+)/compilacao/(?P[0-9]+)/actions', - views.ActionsEditView.as_view(), name='dispositivo_actions'), - -""" diff --git a/compilacao/views.py b/compilacao/views.py index 65f8ebb03..1d45ef15e 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1,13 +1,16 @@ +import sys from collections import OrderedDict from datetime import datetime, timedelta from braces.views import FormMessagesMixin from django.contrib.auth.decorators import login_required +from django.contrib.contenttypes.models import ContentType from django.core.signing import Signer from django.core.urlresolvers import reverse, reverse_lazy from django.db.models import Q -from django.http.response import HttpResponse, HttpResponseRedirect -from django.shortcuts import get_object_or_404 +from django.http.response import (HttpResponse, HttpResponseRedirect, + JsonResponse) +from django.shortcuts import get_object_or_404, redirect from django.utils.dateparse import parse_date from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ @@ -20,7 +23,7 @@ from compilacao import forms, utils from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, TextoArticulado, TipoDispositivo, TipoNota, - Vide) + TipoTextoArticulado, Vide) DISPOSITIVO_SELECT_RELATED = ( 'tipo_dispositivo', @@ -55,7 +58,13 @@ class TaDetailView(DetailView): @property def title(self): - return self.get_object() + if self.object.content_object: + return _( + 'Metadados para o Texto Articulado da %s - %s') % ( + self.get_object().content_object._meta.verbose_name_plural, + self.get_object().content_object) + else: + return self.get_object() class TaCreateView(FormMessagesMixin, CreateView): @@ -81,6 +90,10 @@ class TaUpdateView(UpdateView): def get_success_url(self): return reverse_lazy('ta_detail', kwargs={'pk': self.kwargs['pk']}) + @property + def cancel_url(self): + return reverse_lazy('ta_detail', kwargs={'pk': self.kwargs['pk']}) + class TaDeleteView(DeleteView): model = TextoArticulado @@ -97,6 +110,64 @@ class TaDeleteView(DeleteView): return reverse_lazy('ta_list') +class IntegracaoTaView(TemplateView): + + def get(self, *args, **kwargs): + item = get_object_or_404(self.model, pk=kwargs['pk']) + related_object_type = ContentType.objects.get_for_model(item) + + ta = TextoArticulado.objects.filter( + object_id=item.pk, + content_type=related_object_type) + + if not ta.exists(): + ta = TextoArticulado() + tipo_ta = TipoTextoArticulado.objects.filter( + model=item.__class__.__name__.lower())[:1] + if tipo_ta.exists(): + ta.tipo_ta = tipo_ta[0] + ta.content_object = item + else: + ta = ta[0] + + if hasattr(item, 'ementa') and item.ementa: + ta.ementa = item.ementa + else: + ta.ementa = 'Integração com %s sem ementa.' % item + + if hasattr(item, 'observacao') and item.observacao: + ta.observacao = item.observacao + else: + ta.observacao = 'Integração com %s sem observacao.' % item + + if hasattr(item, 'numero') and item.numero: + ta.numero = item.numero + else: + ta.numero = int('%s%s%s' % ( + int(datetime.now().year), + int(datetime.now().month), + int(datetime.now().day))) + + if hasattr(item, 'ano') and item.ano: + ta.ano = item.ano + else: + ta.ano = datetime.now().year + + if hasattr(item, 'data_apresentacao'): + ta.data = item.data_apresentacao + elif hasattr(item, 'data'): + ta.data = item.data + else: + ta.data = datetime.now() + + ta.save() + + return redirect(to=reverse_lazy('ta_text', kwargs={'ta_id': ta.pk})) + + class Meta: + abstract = True + + class TextView(ListView): template_name = 'compilacao/text_list.html' @@ -110,6 +181,45 @@ class TextView(ListView): inicio_vigencia = None fim_vigencia = None + def get(self, request, *args, **kwargs): + ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) + self.title = ta + if ta.content_object: + item = ta.content_object + self.title = item + if hasattr(item, 'ementa') and item.ementa: + ta.ementa = item.ementa + else: + ta.ementa = 'Integração com %s sem ementa.' % item + + if hasattr(item, 'observacao') and item.observacao: + ta.observacao = item.observacao + else: + ta.observacao = 'Integração com %s sem observacao.' % item + + if hasattr(item, 'numero') and item.numero: + ta.numero = item.numero + else: + ta.numero = int('%s%s%s' % ( + int(datetime.now().year), + int(datetime.now().month), + int(datetime.now().day))) + + if hasattr(item, 'ano') and item.ano: + ta.ano = item.ano + else: + ta.ano = datetime.now().year + + if hasattr(item, 'data_apresentacao'): + ta.data = item.data_apresentacao + elif hasattr(item, 'data'): + ta.data = item.data + else: + ta.data = datetime.now() + ta.save() + + return super(TextView, self).get(request, *args, **kwargs) + def get_context_data(self, **kwargs): context = super(TextView, self).get_context_data(**kwargs) @@ -288,7 +398,6 @@ class DispositivoView(TextView): class TextEditView(TextView): - template_name = 'compilacao/text_edit.html' flag_alteradora = -1 @@ -383,6 +492,692 @@ class TextEditView(TextView): request.session['perfil_estrutural'] = perfis[0].pk +class DispositivoEditView(TextEditView): + template_name = 'compilacao/text_edit_bloco.html' + + def post(self, request, *args, **kwargs): + + d = Dispositivo.objects.get( + pk=self.kwargs['dispositivo_id']) + + texto = request.POST['texto'] + + if d.texto != '': + d.texto = texto + d.save() + return self.get(request, *args, **kwargs) + d.texto = texto.strip() + d.save() + + if texto != '': + dnext = Dispositivo.objects.filter( + ta_id=d.ta_id, + ordem__gt=d.ordem, + texto='', + tipo_dispositivo__dispositivo_de_articulacao=False)[:1] + + if not dnext.exists(): + dnext = [] + dnext[0] = d + else: + + if dnext[0].nivel > d.nivel: + pais = [d.pk, ] + else: + if dnext[0].dispositivo_pai_id == d.dispositivo_pai_id: + pais = [dnext[0].dispositivo_pai_id, ] + else: + pais = [ + dnext[0].dispositivo_pai_id, + d.dispositivo_pai_id] + data = {'pk': dnext[0].pk, 'pai': pais} + else: + data = {'pk': d.pk, 'pai': [d.pk, ]} + + return JsonResponse(data, safe=False) + + def get_queryset_perfil_estrutural(self): + perfis = PerfilEstruturalTextoArticulado.objects.all() + return perfis + + def get(self, request, *args, **kwargs): + + try: + if 'perfil_pk' in request.GET: + self.set_perfil_in_session( + request, request.GET['perfil_pk']) + elif 'perfil_estrutural' not in request.session: + self.set_perfil_in_session(request=request) + + self.object_list = self.get_queryset() + + self.perfil_estrutural_list = self.get_queryset_perfil_estrutural() + + context = self.get_context_data( + object_list=self.object_list, + perfil_estrutural_list=self.perfil_estrutural_list + ) + except Exception as e: + print(e) + + return self.render_to_response(context) + + def get_queryset(self): + self.flag_alteradora = -1 + self.flag_nivel_ini = 0 + self.flag_nivel_old = -1 + + try: + self.pk_edit = int(self.request.GET['edit']) + except: + self.pk_edit = 0 + self.pk_view = int(self.kwargs['dispositivo_id']) + + try: + if self.pk_edit == self.pk_view: + bloco = Dispositivo.objects.get( + pk=self.kwargs['dispositivo_id']) + else: + bloco = Dispositivo.objects.get( + pk=self.kwargs['dispositivo_id']) + except Dispositivo.DoesNotExist: + return [] + + self.flag_nivel_old = bloco.nivel - 1 + self.flag_nivel_ini = bloco.nivel + + if self.pk_edit == self.pk_view: + return [bloco, ] + + proximo_bloco = Dispositivo.objects.filter( + ordem__gt=bloco.ordem, + nivel__lte=bloco.nivel, + ta_id=self.kwargs['ta_id'])[:1] + + if proximo_bloco.count() == 0: + itens = Dispositivo.objects.filter( + ordem__gte=bloco.ordem, + ta_id=self.kwargs['ta_id'] + ).select_related(*DISPOSITIVO_SELECT_RELATED) + else: + itens = Dispositivo.objects.filter( + ordem__gte=bloco.ordem, + ordem__lt=proximo_bloco[0].ordem, + ta_id=self.kwargs['ta_id'] + ).select_related(*DISPOSITIVO_SELECT_RELATED) + return itens + + def select_provaveis_inserts(self, request=None): + + try: + + if request and 'perfil_estrutural' not in request.session: + self.set_perfil_in_session(request) + + perfil_pk = request.session['perfil_estrutural'] + + # Não salvar d_base + if self.pk_edit == 0: + base = Dispositivo.objects.get(pk=self.pk_view) + else: + base = Dispositivo.objects.get(pk=self.pk_edit) + + prox_possivel = Dispositivo.objects.filter( + ordem__gt=base.ordem, + nivel__lte=base.nivel, + ta_id=base.ta_id)[:1] + + if prox_possivel.exists(): + prox_possivel = prox_possivel[0] + else: + prox_possivel = None + + result = [{'tipo_insert': 'Inserir Depois', + 'icone': '↷ ', + 'action': 'add_next', + 'itens': []}, + {'tipo_insert': 'Inserir Dentro', + 'icone': '⇲ ', + 'action': 'add_in', + 'itens': []}, + {'tipo_insert': 'Inserir Antes', + 'icone': '↶ ', + 'action': 'add_prior', + 'itens': []} + ] + + # Possíveis inserções sequenciais já existentes + parents = base.get_parents() + parents.insert(0, base) + nivel = sys.maxsize + for dp in parents: + + if dp.nivel >= nivel: + continue + + if dp.is_relative_auto_insert(perfil_pk): + continue + + if prox_possivel and \ + dp.tipo_dispositivo != base.tipo_dispositivo and\ + dp.nivel < prox_possivel.nivel and\ + not prox_possivel.tipo_dispositivo.permitido_inserir_in( + dp.tipo_dispositivo, + perfil_pk=perfil_pk): + + if dp.tipo_dispositivo != prox_possivel.tipo_dispositivo: + continue + + nivel = dp.nivel + + # um do mesmo para inserção antes + if dp == base: + result[2]['itens'].append({ + 'class_css': dp.tipo_dispositivo.class_css, + 'tipo_pk': dp.tipo_dispositivo.pk, + 'variacao': 0, + 'provavel': '%s (%s)' % ( + dp.rotulo_padrao(local_insert=1), + dp.tipo_dispositivo.nome,), + 'dispositivo_base': base.pk}) + + if dp.dispositivo_pai: + flag_pv = dp.tipo_dispositivo.permitido_variacao( + dp.dispositivo_pai.tipo_dispositivo, + perfil_pk=perfil_pk) + else: + flag_pv = False + + r = [] + flag_direcao = 1 + flag_variacao = 0 + while True: + if dp.dispositivo0 == 0: + local_insert = 1 + else: + local_insert = 0 + + rt = dp.transform_in_next(flag_direcao) + if not rt[0]: + break + flag_variacao += rt[1] + r.append({'class_css': dp.tipo_dispositivo.class_css, + 'tipo_pk': dp.tipo_dispositivo.pk, + 'variacao': flag_variacao, + 'provavel': '%s (%s)' % ( + dp.rotulo_padrao(local_insert), + dp.tipo_dispositivo.nome,), + 'dispositivo_base': base.pk}) + + flag_direcao = -1 + + r.reverse() + + if not flag_pv: + r = [r[0], ] + + if len(r) > 0 and dp.tipo_dispositivo.formato_variacao0 == \ + TipoDispositivo.FNCN: + r = [r[0], ] + + if dp.tipo_dispositivo == base.tipo_dispositivo: + result[0]['itens'] += r + else: + result[0]['itens'] += r + result[2]['itens'] += r + + if nivel == 0: + break + + # tipo do dispositivo base + tipb = base.tipo_dispositivo + + for paradentro in [1, 0]: + if paradentro: + # Outros Tipos de Dispositivos PARA DENTRO + otds = TipoDispositivo.objects.order_by( + '-contagem_continua', 'id').all() + else: + # Outros Tipos de Dispositivos PARA FORA + classes_ja_inseridas = [] + for c in result[0]['itens']: + if c['class_css'] not in classes_ja_inseridas: + classes_ja_inseridas.append(c['class_css']) + for c in result[1]['itens']: + if c['class_css'] not in classes_ja_inseridas: + classes_ja_inseridas.append(c['class_css']) + otds = TipoDispositivo.objects.order_by( + '-contagem_continua', 'id').all().exclude( + class_css__in=classes_ja_inseridas) + + for td in otds: + + if paradentro and not td.permitido_inserir_in( + tipb, + include_relative_autos=False, + perfil_pk=perfil_pk): + continue + + base.tipo_dispositivo = td + + if not paradentro: + + flag_insercao = False + for possivelpai in parents: + if td.permitido_inserir_in( + possivelpai.tipo_dispositivo, + include_relative_autos=False, + perfil_pk=perfil_pk): + flag_insercao = True + break + + if not flag_insercao: + continue + + if possivelpai.is_relative_auto_insert(perfil_pk): + continue + + if prox_possivel: + if prox_possivel.nivel == base.nivel: + if prox_possivel.tipo_dispositivo != td and\ + not prox_possivel.tipo_dispositivo.\ + permitido_inserir_in( + td, perfil_pk=perfil_pk): + continue + else: + if possivelpai.tipo_dispositivo != \ + prox_possivel.tipo_dispositivo and\ + not prox_possivel.tipo_dispositivo.\ + permitido_inserir_in( + possivelpai.tipo_dispositivo, + perfil_pk=perfil_pk) and \ + possivelpai.nivel < \ + prox_possivel.nivel: + continue + base.dispositivo_pai = possivelpai + Dispositivo.set_numero_for_add_in( + possivelpai, base, td) + else: + Dispositivo.set_numero_for_add_in(base, base, td) + + r = [{'class_css': td.class_css, + 'tipo_pk': td.pk, + 'variacao': 0, + 'provavel': '%s (%s)' % ( + base.rotulo_padrao(1, paradentro), + td.nome,), + 'dispositivo_base': base.pk}] + + if paradentro == 1: + """if (tipb.class_css == 'caput' and + td.class_css == 'paragrafo'): + result[0]['itens'].insert(0, r[0]) + else:""" + result[1]['itens'] += r + else: + result[2]['itens'] += r + result[0]['itens'] += r + + # if len(result[0]['itens']) < len(result[1]['itens']): + # r = result[0] + # result.remove(result[0]) + # result.insert(1, r) + + # remover temporariamente a opção inserir antes + # confirmar falta de necessidade + if len(result) > 2: + result.pop() + + except Exception as e: + print(e) + + return result + + +class ActionsEditMixin(object): + + def render_to_json_response(self, context, **response_kwargs): + + action = getattr(self, context['action']) + return JsonResponse(action(context), safe=False) + + def delete_item_dispositivo(self, context): + return self.delete_bloco_dispositivo(context) + + def delete_bloco_dispositivo(self, context): + base = Dispositivo.objects.get(pk=context['dispositivo_id']) + + base_anterior = Dispositivo.objects.order_by('-ordem').filter( + ta_id=base.ta_id, + ordem__lt=base.ordem + )[:1] + base.delete() + + if base_anterior.exists(): + if base_anterior[0].dispositivo_pai_id: + data = {'pk': base_anterior[0].pk, 'pai': [ + base_anterior[0].dispositivo_pai_id, ]} + else: + data = {'pk': base_anterior[0].pk, 'pai': [-1, ]} + return data + else: + return {} + + def add_prior(self, context): + return {} + + def add_in(self, context): + return self.add_next(context, local_add='add_in') + + def add_next(self, context, local_add='add_next'): + try: + base = Dispositivo.objects.get(pk=context['dispositivo_id']) + tipo = TipoDispositivo.objects.get(pk=context['tipo_pk']) + variacao = int(context['variacao']) + parents = [base, ] + base.get_parents() + + tipos_dp_auto_insert = tipo.filhos_permitidos.filter( + filho_de_insercao_automatica=True, + perfil_id=context['perfil_pk']) + + count_auto_insert = 0 + for tipoauto in tipos_dp_auto_insert: + qtdp = tipoauto.quantidade_permitida + if qtdp >= 0: + qtdp -= Dispositivo.objects.filter( + ta_id=base.ta_id, + tipo_dispositivo_id=tipoauto.filho_permitido.pk + ).count() + if qtdp > 0: + count_auto_insert += 1 + else: + count_auto_insert += 1 + + dp_irmao = None + dp_pai = None + for dp in parents: + if dp.tipo_dispositivo == tipo: + dp_irmao = dp + break + if tipo.permitido_inserir_in( + dp.tipo_dispositivo, + perfil_pk=context['perfil_pk']): + dp_pai = dp + break + dp_pai = dp + + if dp_irmao is not None: + dp = Dispositivo.new_instance_based_on(dp_irmao, tipo) + dp.transform_in_next(variacao) + else: + # Inserção sem precedente + dp = Dispositivo.new_instance_based_on(dp_pai, tipo) + dp.dispositivo_pai = dp_pai + dp.nivel += 1 + + if tipo.contagem_continua: + ultimo_irmao = Dispositivo.objects.order_by( + '-ordem').filter( + ordem__lte=base.ordem, + tipo_dispositivo_id=tipo.pk, + ta_id=base.ta_id)[:1] + + if not ultimo_irmao.exists(): + dp.set_numero_completo([1, 0, 0, 0, 0, 0, ]) + else: + ultimo_irmao = ultimo_irmao[0] + dp.set_numero_completo( + ultimo_irmao.get_numero_completo()) + dp.transform_in_next() + else: + if ';' in tipo.rotulo_prefixo_texto: + dp.set_numero_completo([0, 0, 0, 0, 0, 0, ]) + else: + dp.set_numero_completo([1, 0, 0, 0, 0, 0, ]) + + # verificar se existe restrição de quantidade de itens + if dp.dispositivo_pai: + pp = dp.tipo_dispositivo.possiveis_pais.filter( + pai_id=dp.dispositivo_pai.tipo_dispositivo_id, + perfil_id=context['perfil_pk']) + + if pp.exists() and pp[0].quantidade_permitida >= 0: + qtd_existente = Dispositivo.objects.filter( + ta_id=dp.ta_id, + tipo_dispositivo_id=dp.tipo_dispositivo_id).count() + + if qtd_existente >= pp[0].quantidade_permitida: + return {'pk': base.pk, + 'pai': [base.dispositivo_pai.pk, ], + 'alert': str(_('Limite de inserções de ' + 'dispositivos deste tipo ' + 'foi excedido.')) + } + + ordem = base.criar_espaco( + espaco_a_criar=1 + count_auto_insert, local=local_add) + + dp.rotulo = dp.rotulo_padrao() + dp.ordem = ordem + dp.incrementar_irmaos(variacao, [local_add, ]) + + dp.clean() + dp.save() + + dp_auto_insert = None + + # Inserção automática + if count_auto_insert: + dp_pk = dp.pk + dp.nivel += 1 + for tipoauto in tipos_dp_auto_insert: + dp.dispositivo_pai_id = dp_pk + dp.pk = None + dp.tipo_dispositivo = tipoauto.filho_permitido + if ';' in dp.tipo_dispositivo.rotulo_prefixo_texto: + dp.set_numero_completo([0, 0, 0, 0, 0, 0, ]) + else: + dp.set_numero_completo([1, 0, 0, 0, 0, 0, ]) + dp.rotulo = dp.rotulo_padrao() + dp.texto = '' + dp.ordem = dp.ordem + Dispositivo.INTERVALO_ORDEM + dp.clean() + dp.save() + dp_auto_insert = dp + dp = Dispositivo.objects.get(pk=dp_pk) + + ''' Reenquadrar todos os dispositivos que possuem pai + antes da inserção atual e que são inferiores a dp, + redirecionando para o novo pai''' + + nivel = sys.maxsize + flag_niveis = False + + if not dp.tipo_dispositivo.dispositivo_de_alteracao: + possiveis_filhos = Dispositivo.objects.filter( + ordem__gt=dp.ordem, + ta_id=dp.ta_id) + + for filho in possiveis_filhos: + + if filho.nivel > nivel: + continue + + if filho.dispositivo_pai.ordem >= dp.ordem: + continue + + nivel = filho.nivel + + if not filho.tipo_dispositivo.permitido_inserir_in( + dp.tipo_dispositivo, + perfil_pk=context['perfil_pk']): + continue + + filho.dispositivo_pai = dp + filho.clean() + filho.save() + flag_niveis = True + + if flag_niveis: + dp.organizar_niveis() + + numtipos = {} + + ''' Renumerar filhos imediatos que + não possuam contagem continua''' + + if flag_niveis: + filhos = Dispositivo.objects.filter( + dispositivo_pai_id=dp.pk) + + for filho in filhos: + + if filho.tipo_dispositivo.contagem_continua: + continue + + if filho.tipo_dispositivo.class_css in numtipos: + if filho.dispositivo_substituido is None: + numtipos[filho.tipo_dispositivo.class_css] += 1 + else: + t = filho.tipo_dispositivo + prefixo = t.rotulo_prefixo_texto.split(';') + if len(prefixo) > 1: + count_irmaos_m_tipo = Dispositivo.objects.filter( + ~Q(pk=filho.pk), + tipo_dispositivo=t, + dispositivo_pai=filho.dispositivo_pai)[:1] + + if count_irmaos_m_tipo.exists(): + numtipos[filho.tipo_dispositivo.class_css] = 1 + else: + numtipos[filho.tipo_dispositivo.class_css] = 0 + else: + numtipos[filho.tipo_dispositivo.class_css] = 1 + + filho.dispositivo0 = numtipos[ + filho.tipo_dispositivo.class_css] + + filho.rotulo = filho.rotulo_padrao() + filho.clean() + filho.save() + + ''' Renumerar dispositivos de + contagem continua, caso a inserção seja uma articulação''' + + numtipos = {} + if dp.nivel == 0: + + proxima_articulacao = Dispositivo.objects.filter( + ordem__gt=dp.ordem, + nivel=0, + ta_id=dp.ta_id)[:1] + + if not proxima_articulacao.exists(): + filhos_continuos = list(Dispositivo.objects.filter( + ordem__gt=dp.ordem, + ta_id=dp.ta_id, + tipo_dispositivo__contagem_continua=True)) + else: + filhos_continuos = list(Dispositivo.objects.filter( + Q(ordem__gt=dp.ordem) & + Q(ordem__lt=proxima_articulacao[0].ordem), + ta_id=dp.ta_id, + tipo_dispositivo__contagem_continua=True)) + + for filho in filhos_continuos: + + if filho.tipo_dispositivo.class_css in numtipos: + if filho.dispositivo_substituido is None: + numtipos[filho.tipo_dispositivo.class_css] += 1 + else: + t = filho.tipo_dispositivo + prefixo = t.rotulo_prefixo_texto.split(';') + if len(prefixo) > 1: + count_irmaos_m_tipo = Dispositivo.objects.filter( + ~Q(pk=filho.pk), + tipo_dispositivo=t, + dispositivo_pai=filho.dispositivo_pai)[:1] + + if count_irmaos_m_tipo.exists(): + numtipos[filho.tipo_dispositivo.class_css] = 1 + else: + numtipos[filho.tipo_dispositivo.class_css] = 0 + else: + numtipos[filho.tipo_dispositivo.class_css] = 1 + + filho.dispositivo0 = numtipos[ + filho.tipo_dispositivo.class_css] + + filho.rotulo = filho.rotulo_padrao() + filho.clean() + filho.save() + + except Exception as e: + print(e) + + if dp_auto_insert is None: + data = self.get_json_for_refresh(dp) + else: + data = self.get_json_for_refresh(dp=dp, dpauto=dp_auto_insert) + + return data + + def get_json_for_refresh(self, dp, dpauto=None): + + if dp.tipo_dispositivo.contagem_continua: + pais = [] + if dp.dispositivo_pai is None: + data = {'pk': dp.pk, 'pai': [-1, ]} + else: + pkfilho = dp.pk + dp = dp.dispositivo_pai + + proxima_articulacao = dp.get_proximo_nivel_zero() + + if proxima_articulacao is not None: + parents = Dispositivo.objects.filter( + ta_id=dp.ta_id, + ordem__gte=dp.ordem, + ordem__lt=proxima_articulacao.ordem, + nivel__lte=dp.nivel) + else: + parents = Dispositivo.objects.filter( + ta_id=dp.ta_id, + ordem__gte=dp.ordem, + nivel__lte=dp.nivel) + + nivel = sys.maxsize + for p in parents: + if p.nivel > nivel: + continue + pais.append(p.pk) + nivel = p.nivel + data = { + 'pk': pkfilho if not dpauto else dpauto.pk, 'pai': pais} + else: + data = {'pk': dp.pk if not dpauto else dpauto.pk, 'pai': [ + dp.dispositivo_pai.pk, ]} + + return data + + +class ActionsEditView(ActionsEditMixin, TemplateView): + + def render_to_response(self, context, **response_kwargs): + context['action'] = self.request.GET['action'] + + if 'tipo_pk' in self.request.GET: + context['tipo_pk'] = self.request.GET['tipo_pk'] + + if 'variacao' in self.request.GET: + context['variacao'] = self.request.GET['variacao'] + + if 'perfil_estrutural' in self.request.session: + context['perfil_pk'] = self.request.session['perfil_estrutural'] + + return self.render_to_json_response(context, **response_kwargs) + + class DispositivoSuccessUrlMixin(object): def get_success_url(self): diff --git a/compilacao/views2.py b/compilacao/views2.py index 33a90fd01..ab71973be 100644 --- a/compilacao/views2.py +++ b/compilacao/views2.py @@ -1,23 +1,8 @@ -from collections import OrderedDict -from datetime import datetime, timedelta -from os.path import sys - -from django.core.signing import Signer -from django.db.models import Q -from django.http.response import JsonResponse -from django.shortcuts import render -from django.utils.dateparse import parse_date from django.utils.translation import ugettext_lazy as _ -from django.views.generic.base import TemplateView -from django.views.generic.edit import FormMixin -from django.views.generic.list import ListView -from compilacao import forms -from compilacao.models import (Dispositivo, Nota, - PerfilEstruturalTextoArticulado, - TextoArticulado, TipoDispositivo, TipoNota, - TipoPublicacao, TipoVide, VeiculoPublicacao, - Vide) +from compilacao.models import (PerfilEstruturalTextoArticulado, + TipoDispositivo, TipoNota, TipoPublicacao, + TipoVide, VeiculoPublicacao) from sapl.crud import build_crud DISPOSITIVO_SELECT_RELATED = ( @@ -109,1025 +94,3 @@ tipo_dispositivo_crud = build_crud( ], ]) - - -class CompilacaoView(ListView): - template_name = 'compilacao/index.html' - - flag_alteradora = -1 - - flag_nivel_ini = 0 - flag_nivel_old = -1 - - itens_de_vigencia = {} - - inicio_vigencia = None - fim_vigencia = None - - def get_context_data(self, **kwargs): - context = super(CompilacaoView, self).get_context_data(**kwargs) - - cita = Vide.objects.filter( - Q(dispositivo_base__ta_id=self.kwargs['ta_id'])).\ - select_related( - 'dispositivo_ref', - 'dispositivo_ref__ta', - 'dispositivo_ref__dispositivo_pai', - 'dispositivo_ref__dispositivo_pai__ta', 'tipo') - - context['cita'] = {} - for c in cita: - if str(c.dispositivo_base_id) not in context['cita']: - context['cita'][str(c.dispositivo_base_id)] = [] - context['cita'][str(c.dispositivo_base_id)].append(c) - - citado = Vide.objects.filter( - Q(dispositivo_ref__ta_id=self.kwargs['ta_id'])).\ - select_related( - 'dispositivo_base', - 'dispositivo_base__ta', - 'dispositivo_base__dispositivo_pai', - 'dispositivo_base__dispositivo_pai__ta', 'tipo') - - context['citado'] = {} - for c in citado: - if str(c.dispositivo_ref_id) not in context['citado']: - context['citado'][str(c.dispositivo_ref_id)] = [] - context['citado'][str(c.dispositivo_ref_id)].append(c) - - notas = Nota.objects.filter( - dispositivo__ta_id=self.kwargs['ta_id']).select_related( - 'owner', 'tipo') - - context['notas'] = {} - for n in notas: - if str(n.dispositivo_id) not in context['notas']: - context['notas'][str(n.dispositivo_id)] = [] - context['notas'][str(n.dispositivo_id)].append(n) - return context - - def get_queryset(self): - self.flag_alteradora = -1 - self.flag_nivel_ini = 0 - self.flag_nivel_old = -1 - - self.inicio_vigencia = None - self.fim_vigencia = None - if 'sign' in self.kwargs: - signer = Signer() - try: - string = signer.unsign(self.kwargs['sign']).split(',') - self.inicio_vigencia = parse_date(string[0]) - self.fim_vigencia = parse_date(string[1]) - except: - return{} - - return Dispositivo.objects.filter( - inicio_vigencia__lte=self.fim_vigencia, - ordem__gt=0, - ta_id=self.kwargs['ta_id'], - ).select_related(*DISPOSITIVO_SELECT_RELATED) - else: - - r = Dispositivo.objects.filter( - ordem__gt=0, - ta_id=self.kwargs['ta_id'], - ).select_related( - 'tipo_dispositivo', - 'ta_publicado', - 'ta', - 'dispositivo_atualizador', - 'dispositivo_atualizador__dispositivo_pai', - 'dispositivo_atualizador__dispositivo_pai__ta', - 'dispositivo_atualizador__dispositivo_pai__ta__tipo', - 'dispositivo_pai', - 'dispositivo_pai__tipo_dispositivo') - - return r - - def get_vigencias(self): - itens = Dispositivo.objects.filter( - ta_id=self.kwargs['ta_id'], - ).order_by( - 'inicio_vigencia' - ).distinct( - 'inicio_vigencia' - ).select_related( - 'ta_publicado', - 'ta', - 'ta_publicado__tipo', - 'ta__tipo',) - - ajuste_datas_vigencia = [] - - for item in itens: - ajuste_datas_vigencia.append(item) - - lenLista = len(ajuste_datas_vigencia) - for i in range(lenLista): - if i + 1 < lenLista: - ajuste_datas_vigencia[ - i].fim_vigencia = ajuste_datas_vigencia[ - i + 1].inicio_vigencia - timedelta(days=1) - else: - ajuste_datas_vigencia[i].fim_vigencia = None - - self.itens_de_vigencia = {} - - idx = -1 - length = len(ajuste_datas_vigencia) - for item in ajuste_datas_vigencia: - idx += 1 - if idx == 0: - self.itens_de_vigencia[0] = [item, ] - continue - - if idx + 1 < length: - ano = item.ta_publicado.ano - if ano in self.itens_de_vigencia: - self.itens_de_vigencia[ano].append(item) - else: - self.itens_de_vigencia[ano] = [item, ] - else: - self.itens_de_vigencia[9999] = [item, ] - - if len(self.itens_de_vigencia.keys()) <= 1: - return {} - - self.itens_de_vigencia = OrderedDict( - sorted(self.itens_de_vigencia.items(), key=lambda t: t[0])) - - return self.itens_de_vigencia - - def get_ta(self): - return TextoArticulado.objects.select_related('tipo').get( - pk=self.kwargs['ta_id']) - - def is_ta_alterador(self): - if self.flag_alteradora == -1: - self.flag_alteradora = Dispositivo.objects.select_related( - 'dispositivos_alterados_pelo_texto_articulado_set' - ).filter(ta_id=self.kwargs['ta_id']).count() - return self.flag_alteradora > 0 - - -class DispositivoView(CompilacaoView): - # template_name = 'compilacao/index.html' - template_name = 'compilacao/index_bloco.html' - - def get_queryset(self): - self.flag_alteradora = -1 - self.flag_nivel_ini = 0 - self.flag_nivel_old = -1 - - try: - bloco = Dispositivo.objects.get(pk=self.kwargs['dispositivo_id']) - except Dispositivo.DoesNotExist: - return [] - - self.flag_nivel_old = bloco.nivel - 1 - self.flag_nivel_ini = bloco.nivel - - proximo_bloco = Dispositivo.objects.filter( - ordem__gt=bloco.ordem, - nivel__lte=bloco.nivel, - ta_id=self.kwargs['ta_id'])[:1] - - if proximo_bloco.count() == 0: - itens = Dispositivo.objects.filter( - ordem__gte=bloco.ordem, - ta_id=self.kwargs['ta_id'] - ).select_related(*DISPOSITIVO_SELECT_RELATED) - else: - itens = Dispositivo.objects.filter( - ordem__gte=bloco.ordem, - ordem__lt=proximo_bloco[0].ordem, - ta_id=self.kwargs['ta_id'] - ).select_related(*DISPOSITIVO_SELECT_RELATED) - return itens - - -def handle_uploaded_file(f, outfilepath): - with open(outfilepath, 'wb+') as destination: - for chunk in f.chunks(): - destination.write(chunk) - - -class CompilacaoEditView(CompilacaoView, FormMixin): - - template_name = 'compilacao/edit.html' - - flag_alteradora = -1 - - flag_nivel_ini = 0 - flag_nivel_old = -1 - - pk_edit = 0 - pk_view = 0 - - def post(self, request, *args, **kwargs): - form = forms.UpLoadImportFileForm(request.POST, request.FILES) - message = "Arquivo Submetido com sucesso" - - self.object_list = self.get_queryset() - - if form.is_valid(): - try: - f = request.FILES['import_file'] - outfilepath = '/tmp/' + f.name - handle_uploaded_file(f, outfilepath) - - # p = Parser() - # p.parser(outfilepath) - - except Exception as e: - print(e) - - context = self.get_context_data( - object_list=self.object_list, - form=form, - message=message, - view=self, - parser_list=[]) - return render(request, self.template_name, context) - else: - context = self.get_context_data( - object_list=self.object_list, - form=form, - message=form.errors, - view=self) - return self.form_invalid(context) - - return self.render_to_response({'form': form}) - - def form_invalid(self, context): - return self.render_to_response(context) - - def get(self, request, *args, **kwargs): - - self.object_list = self.get_queryset() - form_class = forms.UpLoadImportFileForm - self.form = self.get_form(form_class) - context = self.get_context_data( - object_list=self.object_list, - form=self.form) - - return self.render_to_response(context) - - def get_queryset(self): - self.pk_edit = 0 - self.pk_view = 0 - - self.flag_alteradora = -1 - self.flag_nivel_ini = 0 - self.flag_nivel_old = -1 - - result = Dispositivo.objects.filter( - ta_id=self.kwargs['ta_id'] - ).select_related(*DISPOSITIVO_SELECT_RELATED) - - if not result.exists(): - - ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) - - td = TipoDispositivo.objects.filter(class_css='articulacao')[0] - a = Dispositivo() - a.nivel = 0 - a.ordem = Dispositivo.INTERVALO_ORDEM - a.ordem_bloco_atualizador = 0 - a.set_numero_completo([1, 0, 0, 0, 0, 0, ]) - a.ta = ta - a.tipo_dispositivo = td - a.inicio_vigencia = ta.data_publicacao - a.inicio_eficacia = ta.data_publicacao - a.timestamp = datetime.now() - a.save() - - td = TipoDispositivo.objects.filter(class_css='ementa')[0] - e = Dispositivo() - e.nivel = 1 - e.ordem = a.ordem + Dispositivo.INTERVALO_ORDEM - e.ordem_bloco_atualizador = 0 - e.set_numero_completo([1, 0, 0, 0, 0, 0, ]) - e.ta = ta - e.tipo_dispositivo = td - e.inicio_vigencia = ta.data_publicacao - e.inicio_eficacia = ta.data_publicacao - e.timestamp = datetime.now() - e.texto = ta.ementa - e.dispositivo_pai = a - e.save() - - a.pk = None - a.nivel = 0 - a.ordem = e.ordem + Dispositivo.INTERVALO_ORDEM - a.ordem_bloco_atualizador = 0 - a.set_numero_completo([2, 0, 0, 0, 0, 0, ]) - a.timestamp = datetime.now() - a.save() - - result = Dispositivo.objects.filter( - ta_id=self.kwargs['ta_id'] - ).select_related(*DISPOSITIVO_SELECT_RELATED) - - return result - - def set_perfil_in_session(self, request=None, perfil_id=0): - if not request: - return None - - if perfil_id: - perfil = PerfilEstruturalTextoArticulado.objects.get( - pk=perfil_id) - request.session['perfil_estrutural'] = perfil.pk - else: - perfis = PerfilEstruturalTextoArticulado.objects.filter( - padrao=True)[:1] - - if not perfis.exists(): - request.session.pop('perfil_estrutural') - else: - request.session['perfil_estrutural'] = perfis[0].pk - - -class DispositivoEditView(CompilacaoEditView): - template_name = 'compilacao/edit_bloco.html' - - def post(self, request, *args, **kwargs): - - d = Dispositivo.objects.get( - pk=self.kwargs['dispositivo_id']) - - texto = request.POST['texto'] - - if d.texto != '': - d.texto = texto - d.save() - return self.get(request, *args, **kwargs) - d.texto = texto.strip() - d.save() - - if texto != '': - dnext = Dispositivo.objects.filter( - ta_id=d.ta_id, - ordem__gt=d.ordem, - texto='', - tipo_dispositivo__dispositivo_de_articulacao=False)[:1] - - if not dnext.exists(): - return self.get(request, *args, **kwargs) - - if dnext[0].nivel > d.nivel: - pais = [d.pk, ] - else: - if dnext[0].dispositivo_pai_id == d.dispositivo_pai_id: - pais = [dnext[0].dispositivo_pai_id, ] - else: - pais = [ - dnext[0].dispositivo_pai_id, d.dispositivo_pai_id, ] - data = {'pk': dnext[0].pk, 'pai': pais} - else: - data = {'pk': d.pk, 'pai': [d.pk, ]} - - return JsonResponse(data, safe=False) - - def get_queryset_perfil_estrutural(self): - perfis = PerfilEstruturalTextoArticulado.objects.all() - return perfis - - def get(self, request, *args, **kwargs): - - try: - if 'perfil_pk' in request.GET: - self.set_perfil_in_session( - request, request.GET['perfil_pk']) - elif 'perfil_estrutural' not in request.session: - self.set_perfil_in_session(request=request) - - self.object_list = self.get_queryset() - - self.perfil_estrutural_list = self.get_queryset_perfil_estrutural() - - context = self.get_context_data( - object_list=self.object_list, - perfil_estrutural_list=self.perfil_estrutural_list - ) - except Exception as e: - print(e) - - return self.render_to_response(context) - - def get_queryset(self): - self.flag_alteradora = -1 - self.flag_nivel_ini = 0 - self.flag_nivel_old = -1 - - try: - self.pk_edit = int(self.request.GET['edit']) - except: - self.pk_edit = 0 - self.pk_view = int(self.kwargs['dispositivo_id']) - - try: - if self.pk_edit == self.pk_view: - bloco = Dispositivo.objects.get( - pk=self.kwargs['dispositivo_id']) - else: - bloco = Dispositivo.objects.get( - pk=self.kwargs['dispositivo_id']) - except Dispositivo.DoesNotExist: - return [] - - self.flag_nivel_old = bloco.nivel - 1 - self.flag_nivel_ini = bloco.nivel - - if self.pk_edit == self.pk_view: - return [bloco, ] - - proximo_bloco = Dispositivo.objects.filter( - ordem__gt=bloco.ordem, - nivel__lte=bloco.nivel, - ta_id=self.kwargs['ta_id'])[:1] - - if proximo_bloco.count() == 0: - itens = Dispositivo.objects.filter( - ordem__gte=bloco.ordem, - ta_id=self.kwargs['ta_id'] - ).select_related(*DISPOSITIVO_SELECT_RELATED) - else: - itens = Dispositivo.objects.filter( - ordem__gte=bloco.ordem, - ordem__lt=proximo_bloco[0].ordem, - ta_id=self.kwargs['ta_id'] - ).select_related(*DISPOSITIVO_SELECT_RELATED) - return itens - - def select_provaveis_inserts(self, request=None): - - try: - - if request and 'perfil_estrutural' not in request.session: - self.set_perfil_in_session(request) - - perfil_pk = request.session['perfil_estrutural'] - - # Não salvar d_base - if self.pk_edit == 0: - base = Dispositivo.objects.get(pk=self.pk_view) - else: - base = Dispositivo.objects.get(pk=self.pk_edit) - - prox_possivel = Dispositivo.objects.filter( - ordem__gt=base.ordem, - nivel__lte=base.nivel, - ta_id=base.ta_id)[:1] - - if prox_possivel.exists(): - prox_possivel = prox_possivel[0] - else: - prox_possivel = None - - result = [{'tipo_insert': 'Inserir Depois', - 'icone': '↷ ', - 'action': 'add_next', - 'itens': []}, - {'tipo_insert': 'Inserir Dentro', - 'icone': '⇲ ', - 'action': 'add_in', - 'itens': []}, - {'tipo_insert': 'Inserir Antes', - 'icone': '↶ ', - 'action': 'add_prior', - 'itens': []} - ] - - # Possíveis inserções sequenciais já existentes - parents = base.get_parents() - parents.insert(0, base) - nivel = sys.maxsize - for dp in parents: - - if dp.nivel >= nivel: - continue - - if dp.is_relative_auto_insert(perfil_pk): - continue - - if prox_possivel and \ - dp.tipo_dispositivo != base.tipo_dispositivo and\ - dp.nivel < prox_possivel.nivel and\ - not prox_possivel.tipo_dispositivo.permitido_inserir_in( - dp.tipo_dispositivo, - perfil_pk=perfil_pk): - - if dp.tipo_dispositivo != prox_possivel.tipo_dispositivo: - continue - - nivel = dp.nivel - - # um do mesmo para inserção antes - if dp == base: - result[2]['itens'].append({ - 'class_css': dp.tipo_dispositivo.class_css, - 'tipo_pk': dp.tipo_dispositivo.pk, - 'variacao': 0, - 'provavel': '%s (%s)' % ( - dp.rotulo_padrao(local_insert=1), - dp.tipo_dispositivo.nome,), - 'dispositivo_base': base.pk}) - - if dp.dispositivo_pai: - flag_pv = dp.tipo_dispositivo.permitido_variacao( - dp.dispositivo_pai.tipo_dispositivo, - perfil_pk=perfil_pk) - else: - flag_pv = False - - r = [] - flag_direcao = 1 - flag_variacao = 0 - while True: - if dp.dispositivo0 == 0: - local_insert = 1 - else: - local_insert = 0 - - rt = dp.transform_in_next(flag_direcao) - if not rt[0]: - break - flag_variacao += rt[1] - r.append({'class_css': dp.tipo_dispositivo.class_css, - 'tipo_pk': dp.tipo_dispositivo.pk, - 'variacao': flag_variacao, - 'provavel': '%s (%s)' % ( - dp.rotulo_padrao(local_insert), - dp.tipo_dispositivo.nome,), - 'dispositivo_base': base.pk}) - - flag_direcao = -1 - - r.reverse() - - if not flag_pv: - r = [r[0], ] - - if len(r) > 0 and dp.tipo_dispositivo.formato_variacao0 == \ - TipoDispositivo.FNCN: - r = [r[0], ] - - if dp.tipo_dispositivo == base.tipo_dispositivo: - result[0]['itens'] += r - else: - result[0]['itens'] += r - result[2]['itens'] += r - - if nivel == 0: - break - - # tipo do dispositivo base - tipb = base.tipo_dispositivo - - for paradentro in [1, 0]: - if paradentro: - # Outros Tipos de Dispositivos PARA DENTRO - otds = TipoDispositivo.objects.order_by( - '-contagem_continua', 'id').all() - else: - # Outros Tipos de Dispositivos PARA FORA - classes_ja_inseridas = [] - for c in result[0]['itens']: - if c['class_css'] not in classes_ja_inseridas: - classes_ja_inseridas.append(c['class_css']) - for c in result[1]['itens']: - if c['class_css'] not in classes_ja_inseridas: - classes_ja_inseridas.append(c['class_css']) - otds = TipoDispositivo.objects.order_by( - '-contagem_continua', 'id').all().exclude( - class_css__in=classes_ja_inseridas) - - for td in otds: - - if paradentro and not td.permitido_inserir_in( - tipb, - include_relative_autos=False, - perfil_pk=perfil_pk): - continue - - base.tipo_dispositivo = td - - if not paradentro: - - flag_insercao = False - for possivelpai in parents: - if td.permitido_inserir_in( - possivelpai.tipo_dispositivo, - include_relative_autos=False, - perfil_pk=perfil_pk): - flag_insercao = True - break - - if not flag_insercao: - continue - - if possivelpai.is_relative_auto_insert(perfil_pk): - continue - - if prox_possivel: - if prox_possivel.nivel == base.nivel: - if prox_possivel.tipo_dispositivo != td and\ - not prox_possivel.tipo_dispositivo.\ - permitido_inserir_in( - td, perfil_pk=perfil_pk): - continue - else: - if possivelpai.tipo_dispositivo != \ - prox_possivel.tipo_dispositivo and\ - not prox_possivel.tipo_dispositivo.\ - permitido_inserir_in( - possivelpai.tipo_dispositivo, - perfil_pk=perfil_pk) and \ - possivelpai.nivel < \ - prox_possivel.nivel: - continue - base.dispositivo_pai = possivelpai - Dispositivo.set_numero_for_add_in( - possivelpai, base, td) - else: - Dispositivo.set_numero_for_add_in(base, base, td) - - r = [{'class_css': td.class_css, - 'tipo_pk': td.pk, - 'variacao': 0, - 'provavel': '%s (%s)' % ( - base.rotulo_padrao(1, paradentro), - td.nome,), - 'dispositivo_base': base.pk}] - - if paradentro == 1: - """if (tipb.class_css == 'caput' and - td.class_css == 'paragrafo'): - result[0]['itens'].insert(0, r[0]) - else:""" - result[1]['itens'] += r - else: - result[2]['itens'] += r - result[0]['itens'] += r - - # if len(result[0]['itens']) < len(result[1]['itens']): - # r = result[0] - # result.remove(result[0]) - # result.insert(1, r) - - # remover temporariamente a opção inserir antes - # confirmar falta de necessidade - if len(result) > 2: - result.pop() - - except Exception as e: - print(e) - - return result - - -class ActionsEditMixin(object): - - def render_to_json_response(self, context, **response_kwargs): - - action = getattr(self, context['action']) - return JsonResponse(action(context), safe=False) - - def delete_item_dispositivo(self, context): - return self.delete_bloco_dispositivo(context) - - def delete_bloco_dispositivo(self, context): - base = Dispositivo.objects.get(pk=context['dispositivo_id']) - - base_anterior = Dispositivo.objects.order_by('-ordem').filter( - ta_id=base.ta_id, - ordem__lt=base.ordem - )[:1] - base.delete() - - if base_anterior.exists(): - if base_anterior[0].dispositivo_pai_id: - data = {'pk': base_anterior[0].pk, 'pai': [ - base_anterior[0].dispositivo_pai_id, ]} - else: - data = {'pk': base_anterior[0].pk, 'pai': [-1, ]} - return data - else: - return {} - - def add_prior(self, context): - return {} - - def add_in(self, context): - return self.add_next(context, local_add='add_in') - - def add_next(self, context, local_add='add_next'): - try: - base = Dispositivo.objects.get(pk=context['dispositivo_id']) - tipo = TipoDispositivo.objects.get(pk=context['tipo_pk']) - variacao = int(context['variacao']) - parents = [base, ] + base.get_parents() - - tipos_dp_auto_insert = tipo.filhos_permitidos.filter( - filho_de_insercao_automatica=True, - perfil_id=context['perfil_pk']) - - count_auto_insert = 0 - for tipoauto in tipos_dp_auto_insert: - qtdp = tipoauto.quantidade_permitida - if qtdp >= 0: - qtdp -= Dispositivo.objects.filter( - ta_id=base.ta_id, - tipo_dispositivo_id=tipoauto.filho_permitido.pk - ).count() - if qtdp > 0: - count_auto_insert += 1 - else: - count_auto_insert += 1 - - dp_irmao = None - dp_pai = None - for dp in parents: - if dp.tipo_dispositivo == tipo: - dp_irmao = dp - break - if tipo.permitido_inserir_in( - dp.tipo_dispositivo, - perfil_pk=context['perfil_pk']): - dp_pai = dp - break - dp_pai = dp - - if dp_irmao is not None: - dp = Dispositivo.new_instance_based_on(dp_irmao, tipo) - dp.transform_in_next(variacao) - else: - # Inserção sem precedente - dp = Dispositivo.new_instance_based_on(dp_pai, tipo) - dp.dispositivo_pai = dp_pai - dp.nivel += 1 - - if tipo.contagem_continua: - ultimo_irmao = Dispositivo.objects.order_by( - '-ordem').filter( - ordem__lte=base.ordem, - tipo_dispositivo_id=tipo.pk, - ta_id=base.ta_id)[:1] - - if not ultimo_irmao.exists(): - dp.set_numero_completo([1, 0, 0, 0, 0, 0, ]) - else: - ultimo_irmao = ultimo_irmao[0] - dp.set_numero_completo( - ultimo_irmao.get_numero_completo()) - dp.transform_in_next() - else: - if ';' in tipo.rotulo_prefixo_texto: - dp.set_numero_completo([0, 0, 0, 0, 0, 0, ]) - else: - dp.set_numero_completo([1, 0, 0, 0, 0, 0, ]) - - # verificar se existe restrição de quantidade de itens - if dp.dispositivo_pai: - pp = dp.tipo_dispositivo.possiveis_pais.filter( - pai_id=dp.dispositivo_pai.tipo_dispositivo_id, - perfil_id=context['perfil_pk']) - - if pp.exists() and pp[0].quantidade_permitida >= 0: - qtd_existente = Dispositivo.objects.filter( - ta_id=dp.ta_id, - tipo_dispositivo_id=dp.tipo_dispositivo_id).count() - - if qtd_existente >= pp[0].quantidade_permitida: - return {'pk': base.pk, - 'pai': [base.dispositivo_pai.pk, ], - 'alert': str(_('Limite de inserções de ' - 'dispositivos deste tipo ' - 'foi excedido.')) - } - - ordem = base.criar_espaco( - espaco_a_criar=1 + count_auto_insert, local=local_add) - - dp.rotulo = dp.rotulo_padrao() - dp.ordem = ordem - dp.incrementar_irmaos(variacao, [local_add, ]) - - dp.clean() - dp.save() - - dp_auto_insert = None - - # Inserção automática - if count_auto_insert: - dp_pk = dp.pk - dp.nivel += 1 - for tipoauto in tipos_dp_auto_insert: - dp.dispositivo_pai_id = dp_pk - dp.pk = None - dp.tipo_dispositivo = tipoauto.filho_permitido - if ';' in dp.tipo_dispositivo.rotulo_prefixo_texto: - dp.set_numero_completo([0, 0, 0, 0, 0, 0, ]) - else: - dp.set_numero_completo([1, 0, 0, 0, 0, 0, ]) - dp.rotulo = dp.rotulo_padrao() - dp.texto = '' - dp.ordem = dp.ordem + Dispositivo.INTERVALO_ORDEM - dp.clean() - dp.save() - dp_auto_insert = dp - dp = Dispositivo.objects.get(pk=dp_pk) - - ''' Reenquadrar todos os dispositivos que possuem pai - antes da inserção atual e que são inferiores a dp, - redirecionando para o novo pai''' - - nivel = sys.maxsize - flag_niveis = False - - if not dp.tipo_dispositivo.dispositivo_de_alteracao: - possiveis_filhos = Dispositivo.objects.filter( - ordem__gt=dp.ordem, - ta_id=dp.ta_id) - - for filho in possiveis_filhos: - - if filho.nivel > nivel: - continue - - if filho.dispositivo_pai.ordem >= dp.ordem: - continue - - nivel = filho.nivel - - if not filho.tipo_dispositivo.permitido_inserir_in( - dp.tipo_dispositivo, - perfil_pk=context['perfil_pk']): - continue - - filho.dispositivo_pai = dp - filho.clean() - filho.save() - flag_niveis = True - - if flag_niveis: - dp.organizar_niveis() - - numtipos = {} - - ''' Renumerar filhos imediatos que - não possuam contagem continua''' - - if flag_niveis: - filhos = Dispositivo.objects.filter( - dispositivo_pai_id=dp.pk) - - for filho in filhos: - - if filho.tipo_dispositivo.contagem_continua: - continue - - if filho.tipo_dispositivo.class_css in numtipos: - if filho.dispositivo_substituido is None: - numtipos[filho.tipo_dispositivo.class_css] += 1 - else: - t = filho.tipo_dispositivo - prefixo = t.rotulo_prefixo_texto.split(';') - if len(prefixo) > 1: - count_irmaos_m_tipo = Dispositivo.objects.filter( - ~Q(pk=filho.pk), - tipo_dispositivo=t, - dispositivo_pai=filho.dispositivo_pai)[:1] - - if count_irmaos_m_tipo.exists(): - numtipos[filho.tipo_dispositivo.class_css] = 1 - else: - numtipos[filho.tipo_dispositivo.class_css] = 0 - else: - numtipos[filho.tipo_dispositivo.class_css] = 1 - - filho.dispositivo0 = numtipos[ - filho.tipo_dispositivo.class_css] - - filho.rotulo = filho.rotulo_padrao() - filho.clean() - filho.save() - - ''' Renumerar dispositivos de - contagem continua, caso a inserção seja uma articulação''' - - numtipos = {} - if dp.nivel == 0: - - proxima_articulacao = Dispositivo.objects.filter( - ordem__gt=dp.ordem, - nivel=0, - ta_id=dp.ta_id)[:1] - - if not proxima_articulacao.exists(): - filhos_continuos = list(Dispositivo.objects.filter( - ordem__gt=dp.ordem, - ta_id=dp.ta_id, - tipo_dispositivo__contagem_continua=True)) - else: - filhos_continuos = list(Dispositivo.objects.filter( - Q(ordem__gt=dp.ordem) & - Q(ordem__lt=proxima_articulacao[0].ordem), - ta_id=dp.ta_id, - tipo_dispositivo__contagem_continua=True)) - - for filho in filhos_continuos: - - if filho.tipo_dispositivo.class_css in numtipos: - if filho.dispositivo_substituido is None: - numtipos[filho.tipo_dispositivo.class_css] += 1 - else: - t = filho.tipo_dispositivo - prefixo = t.rotulo_prefixo_texto.split(';') - if len(prefixo) > 1: - count_irmaos_m_tipo = Dispositivo.objects.filter( - ~Q(pk=filho.pk), - tipo_dispositivo=t, - dispositivo_pai=filho.dispositivo_pai)[:1] - - if count_irmaos_m_tipo.exists(): - numtipos[filho.tipo_dispositivo.class_css] = 1 - else: - numtipos[filho.tipo_dispositivo.class_css] = 0 - else: - numtipos[filho.tipo_dispositivo.class_css] = 1 - - filho.dispositivo0 = numtipos[ - filho.tipo_dispositivo.class_css] - - filho.rotulo = filho.rotulo_padrao() - filho.clean() - filho.save() - - except Exception as e: - print(e) - - if dp_auto_insert is None: - data = self.get_json_for_refresh(dp) - else: - data = self.get_json_for_refresh(dp=dp, dpauto=dp_auto_insert) - - return data - - def get_json_for_refresh(self, dp, dpauto=None): - - if dp.tipo_dispositivo.contagem_continua: - pais = [] - if dp.dispositivo_pai is None: - data = {'pk': dp.pk, 'pai': [-1, ]} - else: - pkfilho = dp.pk - dp = dp.dispositivo_pai - - proxima_articulacao = dp.get_proximo_nivel_zero() - - if proxima_articulacao is not None: - parents = Dispositivo.objects.filter( - ta_id=dp.ta_id, - ordem__gte=dp.ordem, - ordem__lt=proxima_articulacao.ordem, - nivel__lte=dp.nivel) - else: - parents = Dispositivo.objects.filter( - ta_id=dp.ta_id, - ordem__gte=dp.ordem, - nivel__lte=dp.nivel) - - nivel = sys.maxsize - for p in parents: - if p.nivel > nivel: - continue - pais.append(p.pk) - nivel = p.nivel - data = { - 'pk': pkfilho if not dpauto else dpauto.pk, 'pai': pais} - else: - data = {'pk': dp.pk if not dpauto else dpauto.pk, 'pai': [ - dp.dispositivo_pai.pk, ]} - - return data - - -class ActionsEditView(ActionsEditMixin, TemplateView): - - def render_to_response(self, context, **response_kwargs): - context['action'] = self.request.GET['action'] - - if 'tipo_pk' in self.request.GET: - context['tipo_pk'] = self.request.GET['tipo_pk'] - - if 'variacao' in self.request.GET: - context['variacao'] = self.request.GET['variacao'] - - if 'perfil_estrutural' in self.request.session: - context['perfil_pk'] = self.request.session['perfil_estrutural'] - - return self.render_to_json_response(context, **response_kwargs) diff --git a/materia/views.py b/materia/views.py index aa21a2375..11f4f054e 100644 --- a/materia/views.py +++ b/materia/views.py @@ -4,21 +4,20 @@ from re import sub from crispy_forms.helper import FormHelper from crispy_forms.layout import ButtonHolder, Column, Fieldset, Layout, Submit from django import forms -from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist -from django.core.urlresolvers import reverse, reverse_lazy +from django.core.urlresolvers import reverse from django.forms import ModelForm -from django.shortcuts import get_object_or_404, redirect +from django.shortcuts import redirect from django.utils.html import strip_tags from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.views.generic import ListView from django.views.generic.edit import FormMixin -from vanilla import GenericView +from vanilla.views import GenericView import sapl from comissoes.models import Comissao, Composicao -from compilacao.models import TextoArticulado, TipoTextoArticulado +from compilacao.views import IntegracaoTaView from norma.models import LegislacaoCitada, NormaJuridica, TipoNormaJuridica from parlamentares.models import Parlamentar from sapl.crud import build_crud @@ -2022,33 +2021,5 @@ class PesquisaMateriaListView(FormMixin, ListView): return context -class MateriaTaView(GenericView): - - def get(self, *args, **kwargs): - materia = get_object_or_404(MateriaLegislativa, pk=kwargs['pk']) - related_object_type = ContentType.objects.get_for_model(materia) - - ta = TextoArticulado.objects.filter( - object_id=materia.pk, - content_type=related_object_type) - - if not ta.exists(): - tipo_ta = TipoTextoArticulado.objects.filter( - model=materia.__class__.__name__.lower())[:1] - - ta = TextoArticulado() - - if tipo_ta.exists(): - ta.tipo_ta = tipo_ta[0] - - ta.ementa = materia.ementa - ta.numero = materia.numero - ta.ano = materia.ano - ta.data = materia.data_apresentacao - ta.content_object = materia - ta.save() - - else: - ta = ta[0] - - return redirect(to=reverse_lazy('ta_text', kwargs={'ta_id': ta.pk})) +class MateriaTaView(IntegracaoTaView): + model = MateriaLegislativa diff --git a/norma/models.py b/norma/models.py index 66aefee18..e1e0ec710 100644 --- a/norma/models.py +++ b/norma/models.py @@ -72,7 +72,7 @@ class NormaJuridica(models.Model): null=True, upload_to=texto_upload_path, verbose_name=_('Texto Integral')) - tipo = models.ForeignKey(TipoNormaJuridica, verbose_name=_('Tipo')) + tipo = models.ForeignKey(TipoNormaJuridica, verbose_name=_('Tipo da Norma Juridica')) materia = models.ForeignKey(MateriaLegislativa, blank=True, null=True) numero = models.PositiveIntegerField(verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano')) diff --git a/norma/views.py b/norma/views.py index 90717e21a..655b8e89a 100644 --- a/norma/views.py +++ b/norma/views.py @@ -4,19 +4,16 @@ from re import sub from crispy_forms.helper import FormHelper from crispy_forms.layout import ButtonHolder, Fieldset, Layout, Submit from django import forms -from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist -from django.core.urlresolvers import reverse_lazy from django.forms import ModelForm -from django.shortcuts import get_object_or_404, redirect from django.utils.html import strip_tags from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.views.generic.edit import FormMixin -from vanilla import GenericView +from vanilla.views import GenericView import sapl -from compilacao.models import TextoArticulado, TipoTextoArticulado +from compilacao.views import IntegracaoTaView from materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.crud import build_crud @@ -224,33 +221,5 @@ class NormaIncluirView(FormMixin, GenericView): return self.form_invalid(form) -class NormaTaView(GenericView): - - def get(self, *args, **kwargs): - norma = get_object_or_404(NormaJuridica, pk=kwargs['pk']) - related_object_type = ContentType.objects.get_for_model(norma) - - ta = TextoArticulado.objects.filter( - object_id=norma.pk, - content_type=related_object_type) - - if not ta.exists(): - tipo_ta = TipoTextoArticulado.objects.filter( - model=norma.__class__.__name__.lower())[:1] - - ta = TextoArticulado() - - if tipo_ta.exists(): - ta.tipo_ta = tipo_ta[0] - - ta.ementa = norma.ementa - ta.numero = norma.numero - ta.ano = norma.ano - ta.data = norma.data - ta.content_object = norma - ta.save() - - else: - ta = ta[0] - - return redirect(to=reverse_lazy('ta_text', kwargs={'ta_id': ta.pk})) +class NormaTaView(IntegracaoTaView): + model = NormaJuridica diff --git a/static/js/compilacao_edit.js b/static/js/compilacao_edit.js index 307b8d491..44ad142ba 100644 --- a/static/js/compilacao_edit.js +++ b/static/js/compilacao_edit.js @@ -167,7 +167,7 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, if (flag_actions_vibible == null || flag_actions_vibible) { $('#dpt'+pk_edit).addClass('dpt-selected'); $('html, body').animate({ - scrollTop: $('#dpt' + pk_edit ).offset().top - window.innerHeight / 10 + scrollTop: $('#dpt' + pk_edit ).offset().top - window.innerHeight / 9 }, 0); } } diff --git a/static/styles/app.scss b/static/styles/app.scss index 286488098..cd874a6a0 100644 --- a/static/styles/app.scss +++ b/static/styles/app.scss @@ -25,8 +25,8 @@ $top-bar-dropdown-radius: $global-radius; } } -// Restyles to foundation top bar menu, in order to behave aesthetically different -/* +// Restyles to foundation top bar menu, in order to behave aesthetically different +/* XXX Is there a better way to implement these styles using best practices without the need to override this much of foundation? Or at least avoid too much nesting and @@ -38,7 +38,7 @@ $top-bar-dropdown-radius: $global-radius; .has-dropdown { // Default values for dropdowns, while also being hidden. .dropdown { - // Border-radius for the first and last dropdown items. We don't style the parent dropdown, as the items overflows it. + // Border-radius for the first and last dropdown items. We don't style the parent dropdown, as the items overflows it. @include radius(rem-calc($top-bar-dropdown-radius)); // Second child here actually targets the first item, since Foundation JS injects a hidden li before it for a mobile back button. > li:nth-child(2), > li:nth-child(2) > a { @@ -50,8 +50,8 @@ $top-bar-dropdown-radius: $global-radius; box-shadow: 0 10px 18px rgba(0, 0, 0, 0.19), 0 2px 6px rgba(0, 0, 0, 0.23); // For the transition effect. - opacity: 0; - // Show the dropdown accurately while it animates. + opacity: 0; + // Show the dropdown accurately while it animates. width: auto; // This will allow the triangle pip to be visible above the dropdown. overflow: visible; @@ -68,14 +68,14 @@ $top-bar-dropdown-radius: $global-radius; position: absolute; top: rem-calc(-12px); left: rem-calc(15px); - } - // This bridges the gap between the top bar and a dropdown. + } + // This bridges the gap between the top bar and a dropdown. &::after { content: ""; position: absolute; z-index: -1; left: 0; - top: rem-calc(-25px); + top: rem-calc(-25px); height: rem-calc(25px); width: 100%; // This transition is for hover-on. @@ -94,7 +94,7 @@ $top-bar-dropdown-radius: $global-radius; pointer-events: auto; // Animating with a beautiful cubic-bezier curve, or Google's "Swift out" easing :) transition: transform 0.3s cubic-bezier(0.55,0,0.1,1), - opacity 0.3s cubic-bezier(0.55,0,0.1,1), + opacity 0.3s cubic-bezier(0.55,0,0.1,1), // Here we make sure the clipping is set before any other transition. clip 0s 0s; // Don't forget to properly animate our bridge, so it keeps only between our gap. @@ -107,6 +107,8 @@ $top-bar-dropdown-radius: $global-radius; } } + + // Our app // - - - - - - - - - - - - - - - - - - - - - - - - - @@ -158,7 +160,7 @@ color: $primary-color; .fadein { -webkit-animation: fadeIn 0.25s ease-in-out; -moz-animation: fadeIn 0.25s ease-in-out; --o-animation: fadeIn 0.25s ease-in-out; +-o-animation: fadeIn 0.25s ease-in-out; } .container { @@ -181,7 +183,7 @@ color: #444444; display: table-row; box-sizing: content-box; } - + /* XXX find a better way to fix main layout box-sizing */ .page__row > .container > *{ box-sizing: border-box; @@ -196,6 +198,12 @@ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 1px 4px rgba(0, 0, 0, 0.23); max-width: 960px; } +.sub-nav { + dt a, dd a, li a { + color: white !important; + } +} + .icon-bar { vertical-align: top; @@ -301,7 +309,7 @@ text-align: center; .footer__block--about { padding-left: 0; - max-width: 195px; + max-width: 195px; } .footer__block--license { diff --git a/static/styles/compilacao.scss b/static/styles/compilacao.scss index 42c33e747..c46dcdeef 100644 --- a/static/styles/compilacao.scss +++ b/static/styles/compilacao.scss @@ -79,7 +79,7 @@ a:link:after, a:visited:after { width: 0px; border-color: transparent transparent #3385CA; position: absolute; - top: -0.75rem; + top: -0.71rem; left: 0.9375rem; } &:hover::before { @@ -597,6 +597,7 @@ a:link:after, a:visited:after { .dne { height: 0.1667rem; transform: scaleX(1); + transition-delay: 1s; ul.btns-action { clip: rect(-100px, 2000px, 2000px, -100px); @@ -610,7 +611,7 @@ a:link:after, a:visited:after { } .dne-nota { height: auto; - + transition-delay: 0s; } } diff --git a/templates/base.html b/templates/base.html index 31f9d7858..be0d7b45d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -117,12 +117,12 @@ {% block main_header %}
-
{# XXX Make better use of translation tags in html blocks ie. actually use the proper blocktrans tag efficiently #} @@ -158,7 +158,7 @@ {% block title %} {% if view.title %} -

{{ view.title }}

+

{{ view.title|linebreaksbr }}

{% endif %} {% endblock %} @@ -214,9 +214,10 @@ - +