From 6b183274ccb2742d823729af6d8eb3cb035ec0ad Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Tue, 1 Mar 2016 18:09:56 -0300 Subject: [PATCH 01/10] =?UTF-8?q?Exclus=C3=A3o=20de=20dispositivos=20e=20b?= =?UTF-8?q?locos=20de=20dispositivos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0044_auto_20160301_1816.py | 26 +++ compilacao/models.py | 27 ++- compilacao/views.py | 174 +++++++++++++++++- static/js/compilacao_edit.js | 2 +- static/styles/compilacao.scss | 104 ++++++----- templates/compilacao/text_edit.html | 3 +- templates/compilacao/text_edit_bloco.html | 31 ++-- .../compilacao/text_edit_blocoalteracao.html | 3 +- 8 files changed, 288 insertions(+), 82 deletions(-) create mode 100644 compilacao/migrations/0044_auto_20160301_1816.py diff --git a/compilacao/migrations/0044_auto_20160301_1816.py b/compilacao/migrations/0044_auto_20160301_1816.py new file mode 100644 index 000000000..fcca5b769 --- /dev/null +++ b/compilacao/migrations/0044_auto_20160301_1816.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-03-01 21:16 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('compilacao', '0043_auto_20160110_1733'), + ] + + operations = [ + migrations.AlterField( + model_name='dispositivo', + name='dispositivo_subsequente', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='compilacao.Dispositivo', verbose_name='Dispositivo Subsequente'), + ), + migrations.AlterField( + model_name='dispositivo', + name='dispositivo_substituido', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='compilacao.Dispositivo', verbose_name='Dispositivo Substituido'), + ), + ] diff --git a/compilacao/models.py b/compilacao/models.py index 8ce953a98..b05f21629 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -59,6 +59,17 @@ class BaseModel(models.Model): self.__class__, tuple(unique_fields)) raise ValidationError(msg) + def save(self, force_insert=False, force_update=False, using=None, + update_fields=None, clean=True): + if clean: + self.clean() + return models.Model.save( + self, + force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) + class TipoTextoArticulado(models.Model): sigla = models.CharField(max_length=3, verbose_name=_('Sigla')) @@ -581,11 +592,13 @@ class Dispositivo(BaseModel, TimestampedMixin): 'self', blank=True, null=True, default=None, related_name='+', + on_delete=models.SET_NULL, verbose_name=_('Dispositivo Subsequente')) dispositivo_substituido = models.ForeignKey( 'self', blank=True, null=True, default=None, related_name='+', + on_delete=models.SET_NULL, verbose_name=_('Dispositivo Substituido')) dispositivo_pai = models.ForeignKey( 'self', @@ -925,7 +938,7 @@ class Dispositivo(BaseModel, TimestampedMixin): def get_parents_asc(self): return self.get_parents(ordem='asc') - def incrementar_irmaos(self, variacao=0, tipoadd=[]): + def incrementar_irmaos(self, variacao=0, tipoadd=[], force=True): if not self.tipo_dispositivo.contagem_continua: irmaos = list(Dispositivo.objects.filter( @@ -956,6 +969,10 @@ class Dispositivo(BaseModel, TimestampedMixin): dp_profundidade = self.get_profundidade() + if (not force and not variacao and len(irmaos) > 0 and + irmaos[0].get_numero_completo() > self.get_numero_completo()): + return + irmaos_a_salvar = [] ultimo_irmao = None for irmao in irmaos: @@ -1032,12 +1049,8 @@ class Dispositivo(BaseModel, TimestampedMixin): proxima_articulacao = Dispositivo.objects.filter( ordem__gt=self.ordem, nivel=0, - ta_id=self.ta_id)[:1] - - if not proxima_articulacao.exists(): - return None - - return proxima_articulacao[0] + ta_id=self.ta_id).first() + return proxima_articulacao def is_relative_auto_insert(self, perfil_pk=None): if self.dispositivo_pai is not None: diff --git a/compilacao/views.py b/compilacao/views.py index a331705f1..5835ea8ea 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1007,26 +1007,180 @@ class ActionsEditMixin: return JsonResponse(action(context), safe=False) def delete_item_dispositivo(self, context): - return self.delete_bloco_dispositivo(context) + return self.delete_bloco_dispositivo(context, bloco=False) - def delete_bloco_dispositivo(self, context): + def delete_bloco_dispositivo(self, context, bloco=True): 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() + data = {} if base_anterior.exists(): - if base_anterior[0].dispositivo_pai_id: - data = {'pk': base_anterior[0].pk, 'pai': [ - base_anterior[0].dispositivo_pai_id, ]} + if base.dispositivo_pai_id: + data = {'pk': base_anterior[0].pk, + 'pai': [base.dispositivo_pai_id, ]} else: data = {'pk': base_anterior[0].pk, 'pai': [-1, ]} - return data - else: - return {} + + self.remover_dispositivo(base, bloco) + return data + + def remover_dispositivo(self, base, bloco): + if base.dispositivo_subsequente or base.dispositivo_substituido: + p = base.dispositivo_substituido + n = base.dispositivo_subsequente + + if n: + print(n.id, n) + n.dispositivo_substituido = p + n.save() + + if p: + print(p.id, p) + p.dispositivo_subsequente = n + if n: + p.fim_vigencia = n.ini_vigencia - timedelta(days=1) + p.fim_eficacia = n.ini_eficacia - timedelta(days=1) + else: + p.fim_vigencia = None + p.fim_eficacia = None + + for d in base.dispositivos_filhos_set.all(): + if d.tipo_dispositivo.possiveis_pais.filter( + pai=base.tipo_dispositivo, + perfil__padrao=True, + filho_de_insercao_automatica=True).exists(): + self.remover_dispositivo(d, bloco) + elif not bloco: + p.dispositivos_filhos_set.add(d) + p.save() + base.delete() + elif not bloco: + for d in base.dispositivos_filhos_set.all(): + # inserções automáticas são excluidas junto com sua base, + # independente da escolha do usuário + if d.tipo_dispositivo.possiveis_pais.filter( + pai=base.tipo_dispositivo, + perfil__padrao=True, + filho_de_insercao_automatica=True).exists(): + continue + + # encontrar possível pai que será o primeiro parent possível + # dos parents do dispostivo + # imediatamente anterior ao dispositivo base + anterior = Dispositivo.objects.order_by('-ordem').filter( + ta_id=base.ta_id, + ordem__lt=d.ordem + ).exclude(pk=base.pk).first() + + if anterior.tipo_dispositivo == d.tipo_dispositivo: + d.dispositivo_pai = anterior.dispositivo_pai + d.nivel = anterior.nivel + if not d.tipo_dispositivo.contagem_continua: + d.set_numero_completo(anterior.get_numero_completo()) + + if d.dispositivo_substituido != anterior: + d.transform_in_next() + d.rotulo = d.rotulo_padrao() + else: + parents = anterior.get_parents() + + for candidato in parents: + if candidato.tipo_dispositivo == d.tipo_dispositivo: + d.dispositivo_pai = candidato.dispositivo_pai + d.nivel = candidato.nivel + if not d.tipo_dispositivo.contagem_continua: + d.set_numero_completo( + candidato.get_numero_completo()) + if d.dispositivo_substituido != candidato: + d.transform_in_next() + d.rotulo = d.rotulo_padrao() + break + elif d.tipo_dispositivo.possiveis_pais.filter( + pai=candidato.tipo_dispositivo, + perfil__padrao=True).exists(): + d.dispositivo_pai = candidato + if ';' in d.tipo_dispositivo.rotulo_prefixo_texto: + d.set_numero_completo([0, 0, 0, 0, 0, 0, ]) + else: + d.set_numero_completo([1, 0, 0, 0, 0, 0, ]) + d.nivel = candidato.nivel + 1 + break + + d.save() + d.organizar_niveis() + + if base.nivel: + if not base.tipo_dispositivo.contagem_continua: + pai_base = base.dispositivo_pai + irmaos_posteriores = pai_base.dispositivos_filhos_set.\ + filter( + ordem__gt=base.ordem, + tipo_dispositivo=base.tipo_dispositivo) + + numero_completo_base = base.get_numero_completo() + base.delete() + + else: + proxima_articulacao = base.get_proximo_nivel_zero() + numero_completo_base = base.get_numero_completo() + + if proxima_articulacao: + irmaos_posteriores = Dispositivo.objects.filter( + ta_id=base.ta_id, + ordem__gt=base.ordem, + tipo_dispositivo=base.tipo_dispositivo, + ordem__lt=proxima_articulacao.ordem + ) + else: + irmaos_posteriores = Dispositivo.objects.filter( + ta_id=base.ta_id, + ordem__gt=base.ordem, + tipo_dispositivo=base.tipo_dispositivo) + + base.delete() + + numero_completo_irmao = None + for irmao in irmaos_posteriores: + numero_completo_irmao = irmao.get_numero_completo() + irmao.set_numero_completo(numero_completo_base) + numero_completo_base = numero_completo_irmao + irmao.rotulo = irmao.rotulo_padrao() + irmao.save() + else: + proxima_articulacao = base.get_proximo_nivel_zero() + + # Dispostivos de Contagem contínua de dentro da base + dcc = Dispositivo.objects.order_by('ordem').filter( + ta_id=base.ta_id, + ordem__gt=base.ordem, + tipo_dispositivo__contagem_continua=True) + + for d in dcc: + ultimo_dcc = Dispositivo.objects.order_by( + 'ordem').filter( + ta_id=base.ta_id, + ordem__lt=d.ordem, + tipo_dispositivo__contagem_continua=True, + tipo_dispositivo=d.tipo_dispositivo).last() + if not ultimo_dcc: + break + d.set_numero_completo(ultimo_dcc.get_numero_completo()) + + if d.dispositivo_substituido != ultimo_dcc: + d.transform_in_next() + + d.rotulo = d.rotulo_padrao() + d.save(clean=False) + + base.delete() + + elif bloco: + # TODO: reorganizar dispositivos de contagem continua + base.delete() def add_prior(self, context): return {} @@ -1124,7 +1278,7 @@ class ActionsEditMixin: dp.rotulo = dp.rotulo_padrao() dp.ordem = ordem - dp.incrementar_irmaos(variacao, [local_add, ]) + dp.incrementar_irmaos(variacao, [local_add, ], force=False) dp.clean() dp.save() diff --git a/static/js/compilacao_edit.js b/static/js/compilacao_edit.js index a5f720e33..feffe4450 100644 --- a/static/js/compilacao_edit.js +++ b/static/js/compilacao_edit.js @@ -250,7 +250,7 @@ $(document).ready(function() { $("#message_block").css("display", "none"); href = location.href.split('#') - if (href.length == 2) { + if (href.length == 2 && href[1] != '') { clickUpdateDispositivo(null, href[1], href[1], 'refresh', true); } diff --git a/static/styles/compilacao.scss b/static/styles/compilacao.scss index d4b79b424..d41499311 100644 --- a/static/styles/compilacao.scss +++ b/static/styles/compilacao.scss @@ -143,12 +143,15 @@ a:link:after, a:visited:after { .cp { - .desativado, .desativado * { - text-decoration: line-through; - color: #999 !important; + .desativado { - table, table td { - border: 1px dotted #ccc; + .dtxt, .dtxt * { + text-decoration: line-through; + color: #999 !important; + + table, table td { + border: 1px dotted #ccc; + } } } @@ -261,7 +264,6 @@ a:link:after, a:visited:after { } - .bloco_alteracao { padding-left: 10%; font-style: italic; @@ -399,6 +401,8 @@ a:link:after, a:visited:after { transform-origin: right; transition: all 0.3s ease; border-top: 1px solid $color_buttons; + + ul.btns-action { list-style: none; padding: 0; @@ -436,6 +440,7 @@ a:link:after, a:visited:after { text-align: left; font-size: 1.6rem; + .container-busca { ul{ list-style: none; @@ -708,7 +713,16 @@ a:link:after, a:visited:after { margin-bottom: 15em; - margin-left: 0.8em; + + .desativado, .desativado * { + + text-decoration: line-through; + color: #999 !important; + + table, table td { + border: 1px dotted #ccc; + } + } a { text-decoration: none; @@ -723,54 +737,36 @@ a:link:after, a:visited:after { font-weight: bold; color: #BFD1F6; } - .artigo { float: none; } + .caput { + margin-top: 0; + } & > .actions_left { color: #fff; + left: 0em; position: absolute; - left: -2.6em; opacity: 0; transition: all 0.4s ease-in-out; + z-index: 1; a { &.btn-edit { @include background-top-down(#3498DB, #2980C9); - @include border-radius(7px); color: #ffffff !important; font-weight: bold; - padding: 2px 7px 2px 7px; + padding: 5px 7px 3px; + display: inline-block; + line-height: 1; - &:hover { - @include background-top-down(#3cb0fd, #3498DB); - } } } } &:hover > .actions_left { - opacity: 0.5; - background-color: transparent !important; - &::before { - content: ""; - border: inset 0.375rem; - border-color: transparent transparent transparent #3cb0fd; - position: absolute; - display: block; - height: 0; - width: 0; - top: 0.4rem; - right: -0.73rem; - } - &:hover { - opacity: 1; - &::before { - border-color: transparent transparent transparent #3cf0ff; - } - } + opacity: 1; } - .bloco { display: block; clear: both; @@ -781,27 +777,36 @@ a:link:after, a:visited:after { cursor: pointer; } } - .articulacao{ - margin-left: -0.8em; + .articulacao { + border-top: 2 px solid #e5e5e5; + margin: 2em 0; + } + .bloco_alteracao { + border: 1px solid #ddd; + margin: -1px 0 0; + padding: 1em; + } + + .articulacao1 { margin-top: 2em; &::before { content: "Articulação"; background-color: #eee; - border-bottom: 1px solid #aaa; + border-bottom: 1px dotted #E88C8C; padding: 0.333em; padding-left: 1em; display:block; } } - .bloco_alteracao { - @extend .articulacao; - margin: 0; - padding-top: 3em; - padding-left: 0em; - background: #ddd; + .bloco_alteracao1 { + @extend .articulacao1; + margin: -1px 0 0; + padding: 1em; + border: 1px dotted #E88C8C; + overflow: hidden; &::before { content: "Bloco de Alteração"; - + margin: -1em -1em 0; display: block; } } @@ -837,16 +842,19 @@ a:link:after, a:visited:after { a:hover { background: transparent; } - } - & > .bloco { - padding: 1em 0; opacity: 1; - margin: 0 !important; + margin: 1em !important; + } + + .bloco_alteracao { + padding-top: 2em; } + + & > .dpt { padding: 0; &:last-child { diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index 41df0d905..7b9e3916a 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -14,7 +14,6 @@

Edição: {{ view.title }} - {% trans 'Texto Multivigente' %}

{% endblock %} -
{% trans 'Aguarde... Atualizando informações!!!'%}
{% block actions %}
@@ -95,23 +98,23 @@ {% endif%} {% if view.pk_view == 0 and view.pk_edit == 0 or view.pk_edit != view.pk_view %} - {% if not dpt.rotulo and not dpt.texto %} + {% if not dpt.rotulo and not dpt.texto and dpt.tipo_dispositivo.dispositivo_de_articulacao%} {% endif %}
{% spaceless %}
{{ dpt.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ dpt.rotulo }}{{ dpt.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{% if dpt.texto == '' and not dpt.tipo_dispositivo.dispositivo_de_articulacao %}({{dpt.tipo_dispositivo}} sem texto){%else%}{{ dpt.texto|safe }}{%endif%}
{% if dpt.ta_publicado_id != None and not dpt.tipo_dispositivo.dispositivo_de_articulacao %} - + {{ dpt.tipo_dispositivo.nota_automatica_prefixo_html|safe }} {% nota_automatica dpt ta_pub_list %} {{ dpt.tipo_dispositivo.nota_automatica_sufixo_html|safe }} {% endif %} {% endspaceless %} - {% if view.is_ta_alterador and dpt.tipo_dispositivo.class_css == 'bloco_alteracao'%} + {% if dpt.tipo_dispositivo.class_css == 'bloco_alteracao'%} {%with node=dpt template_name='compilacao/text_edit_blocoalteracao.html' %} {%include template_name%} {%endwith%} diff --git a/templates/compilacao/text_edit_blocoalteracao.html b/templates/compilacao/text_edit_blocoalteracao.html index d9cb1f05c..b2fa9a4ff 100644 --- a/templates/compilacao/text_edit_blocoalteracao.html +++ b/templates/compilacao/text_edit_blocoalteracao.html @@ -1,10 +1,11 @@ {% load compilacao_filters %} {% load common_tags %} +aaaaa {% for ch in dpt.pk|get_bloco_atualizador %} {% spaceless %}
- {{ ch.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ ch.rotulo }}{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }} + {{ ch.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ ch.rotulo }}{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }}
{% endspaceless %} From 206791e3352d156faf8d2c9363f6048cb0558e62 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Fri, 4 Mar 2016 17:31:04 -0300 Subject: [PATCH 02/10] =?UTF-8?q?Refatorar=20exclus=C3=A3o=20de=20Disposit?= =?UTF-8?q?ivos=20e=20religar=20DCC's?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DCC (Dispositivos de Contagem Continua) --- compilacao/models.py | 24 +- compilacao/templatetags/compilacao_filters.py | 8 +- compilacao/views.py | 352 +++++++++++------- static/js/compilacao_edit.js | 56 ++- static/js/compilacao_view.js | 8 - static/styles/app.scss | 6 + static/styles/compilacao.scss | 2 +- templates/compilacao/text_edit.html | 12 + templates/compilacao/text_list.html | 33 +- 9 files changed, 323 insertions(+), 178 deletions(-) diff --git a/compilacao/models.py b/compilacao/models.py index b05f21629..f45e94f64 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -790,6 +790,21 @@ class Dispositivo(BaseModel, TimestampedMixin): return (flag_direcao, flag_variacao) + def transform_in_prior(self): + numero = self.get_numero_completo() + + numero.reverse() + + for i in range(len(numero)): + if not numero[i]: + continue + + numero[i] -= 1 + numero.reverse() + break + + self.set_numero_completo(numero) + def set_numero_completo(self, *numero): numero = numero[0] self.dispositivo0 = numero[0] @@ -1046,12 +1061,19 @@ class Dispositivo(BaseModel, TimestampedMixin): irmao.save() def get_proximo_nivel_zero(self): - proxima_articulacao = Dispositivo.objects.filter( + proxima_articulacao = Dispositivo.objects.order_by('ordem').filter( ordem__gt=self.ordem, nivel=0, ta_id=self.ta_id).first() return proxima_articulacao + def get_nivel_zero_anterior(self): + anterior_articulacao = Dispositivo.objects.order_by('ordem').filter( + ordem__lt=self.ordem, + nivel=0, + ta_id=self.ta_id).last() + return anterior_articulacao + def is_relative_auto_insert(self, perfil_pk=None): if self.dispositivo_pai is not None: # pp possiveis_pais diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index ac2d103dc..ac5bc4297 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -2,6 +2,7 @@ from django import template from django.core.signing import Signer from django.db.models import Q from django.utils.translation import ugettext_lazy as _ +from django.utils.safestring import mark_safe from compilacao.models import Dispositivo, TipoDispositivo @@ -60,12 +61,15 @@ def set_nivel_old(view, value): @register.simple_tag def close_div(value_max, value_min, varr): - return '
' * (int(value_max) - int(value_min) + 1 + varr) + return mark_safe('
' * (int(value_max) - int(value_min) + 1 + varr)) @register.filter def get_sign_vigencia(value): - string = "%s,%s" % (value.inicio_vigencia, value.fim_vigencia) + string = "%s,%s,%s" % ( + value.ta_publicado_id if value.ta_publicado_id else 0, + value.inicio_vigencia, + value.fim_vigencia) signer = Signer() return signer.sign(str(string)) diff --git a/compilacao/views.py b/compilacao/views.py index 5835ea8ea..222935674 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -325,6 +325,7 @@ class TextView(ListView, CompMixin): inicio_vigencia = None fim_vigencia = None + ta_vigencia = None def get(self, request, *args, **kwargs): ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) @@ -427,14 +428,19 @@ class TextView(ListView, CompMixin): self.inicio_vigencia = None self.fim_vigencia = None + self.ta_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]) + self.ta_vigencia = int(string[0]) + self.inicio_vigencia = parse_date(string[1]) + self.fim_vigencia = parse_date(string[2]) except: - return{} + return Dispositivo.objects.filter( + ordem__gt=0, + ta_id=self.kwargs['ta_id'], + ).select_related(*DISPOSITIVO_SELECT_RELATED) return Dispositivo.objects.filter( inicio_vigencia__lte=self.fim_vigencia, @@ -1015,17 +1021,26 @@ class ActionsEditMixin: base_anterior = Dispositivo.objects.order_by('-ordem').filter( ta_id=base.ta_id, ordem__lt=base.ordem - )[:1] + ).first() data = {} - if base_anterior.exists(): - if base.dispositivo_pai_id: - data = {'pk': base_anterior[0].pk, - 'pai': [base.dispositivo_pai_id, ]} + if base_anterior: + data = self.get_json_for_refresh(base_anterior) + else: + base_anterior = Dispositivo.objects.order_by('ordem').filter( + ta_id=base.ta_id, + ordem__lt=base.ordem + ).first() + if base_anterior: + data = self.get_json_for_refresh(base_anterior) else: - data = {'pk': base_anterior[0].pk, 'pai': [-1, ]} + data['pk'] = '' + + # TODO: a linha abaixo causa atualização da tela inteira... + # retirar a linha abaixo e identificar atualizações pontuais + data['pai'] = [-1, ] - self.remover_dispositivo(base, bloco) + data['message'] = str(self.remover_dispositivo(base, bloco)) return data def remover_dispositivo(self, base, bloco): @@ -1034,12 +1049,12 @@ class ActionsEditMixin: n = base.dispositivo_subsequente if n: - print(n.id, n) + # print(n.id, n) n.dispositivo_substituido = p n.save() if p: - print(p.id, p) + # print(p.id, p) p.dispositivo_subsequente = n if n: p.fim_vigencia = n.ini_vigencia - timedelta(days=1) @@ -1058,60 +1073,79 @@ class ActionsEditMixin: p.dispositivos_filhos_set.add(d) p.save() base.delete() - elif not bloco: - for d in base.dispositivos_filhos_set.all(): - # inserções automáticas são excluidas junto com sua base, - # independente da escolha do usuário - if d.tipo_dispositivo.possiveis_pais.filter( - pai=base.tipo_dispositivo, - perfil__padrao=True, - filho_de_insercao_automatica=True).exists(): - continue + else: + if not bloco: + for d in base.dispositivos_filhos_set.all(): + # inserções automáticas são excluidas junto com sua base, + # independente da escolha do usuário - # encontrar possível pai que será o primeiro parent possível - # dos parents do dispostivo - # imediatamente anterior ao dispositivo base - anterior = Dispositivo.objects.order_by('-ordem').filter( - ta_id=base.ta_id, - ordem__lt=d.ordem - ).exclude(pk=base.pk).first() - - if anterior.tipo_dispositivo == d.tipo_dispositivo: - d.dispositivo_pai = anterior.dispositivo_pai - d.nivel = anterior.nivel - if not d.tipo_dispositivo.contagem_continua: - d.set_numero_completo(anterior.get_numero_completo()) - - if d.dispositivo_substituido != anterior: - d.transform_in_next() - d.rotulo = d.rotulo_padrao() - else: - parents = anterior.get_parents() - - for candidato in parents: - if candidato.tipo_dispositivo == d.tipo_dispositivo: - d.dispositivo_pai = candidato.dispositivo_pai - d.nivel = candidato.nivel - if not d.tipo_dispositivo.contagem_continua: - d.set_numero_completo( - candidato.get_numero_completo()) - if d.dispositivo_substituido != candidato: - d.transform_in_next() - d.rotulo = d.rotulo_padrao() - break - elif d.tipo_dispositivo.possiveis_pais.filter( - pai=candidato.tipo_dispositivo, - perfil__padrao=True).exists(): - d.dispositivo_pai = candidato - if ';' in d.tipo_dispositivo.rotulo_prefixo_texto: - d.set_numero_completo([0, 0, 0, 0, 0, 0, ]) - else: - d.set_numero_completo([1, 0, 0, 0, 0, 0, ]) - d.nivel = candidato.nivel + 1 - break + d_nivel_old = d.nivel + if d.tipo_dispositivo.possiveis_pais.filter( + pai=base.tipo_dispositivo, + perfil__padrao=True, + filho_de_insercao_automatica=True).exists(): + continue + + # encontrar possível pai que será o primeiro parent + # possível dos parents do dispostivo + # imediatamente anterior ao dispositivo base + anterior = Dispositivo.objects.order_by('-ordem').filter( + ta_id=base.ta_id, + ordem__lt=base.ordem + ).first() + + if not anterior: + return _('Não é possível excluir este Dispositivo sem' + ' excluir toda a sua estrutura!!!') + + if anterior.tipo_dispositivo == d.tipo_dispositivo: + d.dispositivo_pai = anterior.dispositivo_pai + d.nivel = anterior.nivel + if not d.tipo_dispositivo.contagem_continua: + d.set_numero_completo( + anterior.get_numero_completo()) + + if d.dispositivo_substituido != anterior: + d.transform_in_next() + d.rotulo = d.rotulo_padrao() + else: + parents = [anterior, ] + anterior.get_parents() + + for candidato in parents: + if candidato == base: + return _('Não é possível excluir este ' + 'Dispositivo sem ' + 'excluir toda a sua estrutura!!!') + if (candidato.tipo_dispositivo == + d.tipo_dispositivo): + d.dispositivo_pai = candidato.dispositivo_pai + d.nivel = candidato.nivel + if not d.tipo_dispositivo.contagem_continua: + d.set_numero_completo( + candidato.get_numero_completo()) + if d.dispositivo_substituido != candidato: + d.transform_in_next() + d.rotulo = d.rotulo_padrao() + break + elif d.tipo_dispositivo.possiveis_pais.filter( + pai=candidato.tipo_dispositivo, + perfil__padrao=True).exists(): + d.dispositivo_pai = candidato + if ';' in d.tipo_dispositivo.\ + rotulo_prefixo_texto: + d.set_numero_completo([0, 0, 0, 0, 0, 0, ]) + else: + d.set_numero_completo([1, 0, 0, 0, 0, 0, ]) + d.nivel = candidato.nivel + 1 + break - d.save() - d.organizar_niveis() + if not parents: + d.dispositivo_pai = anterior + d.nivel = anterior.nivel + 1 + + d.save(clean=False) + if d.nivel != d_nivel_old: + d.organizar_niveis() if base.nivel: if not base.tipo_dispositivo.contagem_continua: @@ -1121,20 +1155,66 @@ class ActionsEditMixin: ordem__gt=base.ordem, tipo_dispositivo=base.tipo_dispositivo) - numero_completo_base = base.get_numero_completo() - base.delete() + # Religar numeração de dispositivos de contagem contínua + # que seram excluidos + + proximo_independente_base = irmaos_posteriores.first() + proxima_articulacao = base.get_proximo_nivel_zero() + + if not proximo_independente_base: + proximo_independente_base = Dispositivo.objects.\ + order_by('ordem').filter( + ta_id=base.ta_id, + ordem__gt=base.ordem, + nivel__lte=base.nivel) + if proximo_independente_base: + dcc = Dispositivo.objects.order_by('ordem').filter( + ta_id=base.ta_id, + ordem__gt=base.ordem, + ordem__lt=proximo_independente_base.ordem, + tipo_dispositivo__contagem_continua=True) + + religado = {} + + for d in dcc: + if d.tipo_dispositivo.class_css in religado: + continue + religado[ + d.tipo_dispositivo.class_css] = d.dispositivo0 + + if proxima_articulacao: + dcc_a_religar = Dispositivo.objects.filter( + ta_id=d.ta_id, + ordem__gt=proximo_independente_base.ordem, + tipo_dispositivo=d.tipo_dispositivo, + ordem__lt=proxima_articulacao.ordem) + else: + dcc_a_religar = Dispositivo.objects.filter( + ta_id=base.ta_id, + ordem__gt=proximo_independente_base.ordem, + tipo_dispositivo=d.tipo_dispositivo) + + primeiro_a_religar = 0 + for dr in dcc_a_religar: + if not primeiro_a_religar: + primeiro_a_religar = dr.dispositivo0 + + dr.dispositivo0 = ( + dr.dispositivo0 - + primeiro_a_religar + d.dispositivo0) + dr.rotulo = dr.rotulo_padrao() + dr.save() + base.delete() else: proxima_articulacao = base.get_proximo_nivel_zero() - numero_completo_base = base.get_numero_completo() if proxima_articulacao: irmaos_posteriores = Dispositivo.objects.filter( ta_id=base.ta_id, ordem__gt=base.ordem, tipo_dispositivo=base.tipo_dispositivo, - ordem__lt=proxima_articulacao.ordem - ) + ordem__lt=proxima_articulacao.ordem) else: irmaos_posteriores = Dispositivo.objects.filter( ta_id=base.ta_id, @@ -1143,44 +1223,71 @@ class ActionsEditMixin: base.delete() - numero_completo_irmao = None - for irmao in irmaos_posteriores: - numero_completo_irmao = irmao.get_numero_completo() - irmao.set_numero_completo(numero_completo_base) - numero_completo_base = numero_completo_irmao - irmao.rotulo = irmao.rotulo_padrao() - irmao.save() + if (len(irmaos_posteriores) == 1 and + ';' in irmaos_posteriores[0]. + tipo_dispositivo.rotulo_prefixo_texto): + i = irmaos_posteriores[0] + i.set_numero_completo([0, 0, 0, 0, 0, 0, ]) + i.rotulo = i.rotulo_padrao(local_insert=1) + i.save() + + else: + for irmao in irmaos_posteriores: + irmao.transform_in_prior() + irmao.rotulo = irmao.rotulo_padrao() + irmao.save() else: proxima_articulacao = base.get_proximo_nivel_zero() - # Dispostivos de Contagem contínua de dentro da base - dcc = Dispositivo.objects.order_by('ordem').filter( - ta_id=base.ta_id, - ordem__gt=base.ordem, - tipo_dispositivo__contagem_continua=True) - - for d in dcc: - ultimo_dcc = Dispositivo.objects.order_by( - 'ordem').filter( + # Renumerar Dispostivos de Contagem Contínua de dentro da base + if not proxima_articulacao: + dcc = Dispositivo.objects.order_by('ordem').filter( ta_id=base.ta_id, - ordem__lt=d.ordem, - tipo_dispositivo__contagem_continua=True, - tipo_dispositivo=d.tipo_dispositivo).last() - if not ultimo_dcc: - break - d.set_numero_completo(ultimo_dcc.get_numero_completo()) + ordem__gt=base.ordem, + tipo_dispositivo__contagem_continua=True) + else: + dcc = Dispositivo.objects.order_by('ordem').filter( + ta_id=base.ta_id, + ordem__gt=base.ordem, + ordem__lt=proxima_articulacao.ordem, + tipo_dispositivo__contagem_continua=True) + + base_adicao = {} + + nivel_zero_anterior = base.get_nivel_zero_anterior() + if nivel_zero_anterior: + nivel_zero_anterior = nivel_zero_anterior.ordem + else: + nivel_zero_anterior = 0 + + dcc = list(dcc) + for d in dcc: # ultimo DCC do tipo encontrado + + if d.tipo_dispositivo.class_css not in base_adicao: + ultimo_dcc = Dispositivo.objects.order_by( + 'ordem').filter( + ta_id=base.ta_id, + ordem__lt=base.ordem, + ordem__gt=nivel_zero_anterior, + tipo_dispositivo__contagem_continua=True, + tipo_dispositivo=d.tipo_dispositivo).last() + + if not ultimo_dcc: + break + + base_adicao[ + d.tipo_dispositivo.class_css] = ultimo_dcc.\ + dispositivo0 - if d.dispositivo_substituido != ultimo_dcc: - d.transform_in_next() + d.dispositivo0 += base_adicao[d.tipo_dispositivo.class_css] d.rotulo = d.rotulo_padrao() - d.save(clean=False) + dcc.reverse() + for d in dcc: + d.save() base.delete() - - elif bloco: - # TODO: reorganizar dispositivos de contagem continua - base.delete() + return '' def add_prior(self, context): return {} @@ -1238,6 +1345,7 @@ class ActionsEditMixin: ultimo_irmao = Dispositivo.objects.order_by( '-ordem').filter( ordem__lte=base.ordem, + ordem__gte=parents[-1].ordem, tipo_dispositivo_id=tipo.pk, ta_id=base.ta_id)[:1] @@ -1268,9 +1376,9 @@ class ActionsEditMixin: 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.')) + 'message': str(_('Limite de inserções de ' + 'dispositivos deste tipo ' + 'foi excedido.')) } ordem = base.criar_espaco( @@ -1280,7 +1388,6 @@ class ActionsEditMixin: dp.ordem = ordem dp.incrementar_irmaos(variacao, [local_add, ], force=False) - dp.clean() dp.save() dp_auto_insert = None @@ -1300,7 +1407,6 @@ class ActionsEditMixin: 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) @@ -1377,58 +1483,38 @@ class ActionsEditMixin: 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] + proxima_articulacao = dp.get_proximo_nivel_zero() - if not proxima_articulacao.exists(): + if not proxima_articulacao: 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), + ordem__gt=dp.ordem, + ordem__lt=proxima_articulacao.ordem, ta_id=dp.ta_id, tipo_dispositivo__contagem_continua=True)) - for filho in filhos_continuos: + base_reducao = {} - 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 + for filho in filhos_continuos: + if filho.tipo_dispositivo.class_css not in base_reducao: + base_reducao[filho.tipo_dispositivo.class_css] = \ + filho.dispositivo0 - 1 - filho.dispositivo0 = numtipos[ + filho.dispositivo0 -= base_reducao[ filho.tipo_dispositivo.class_css] filho.rotulo = filho.rotulo_padrao() - filho.clean() filho.save() except Exception as e: diff --git a/static/js/compilacao_edit.js b/static/js/compilacao_edit.js index feffe4450..0e04d15b7 100644 --- a/static/js/compilacao_edit.js +++ b/static/js/compilacao_edit.js @@ -108,9 +108,7 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, } else if (_action.startsWith('delete_')) { var r = confirm("Confirma Exclusão deste dispositivo?"); - if (r == true) { - x = "You pressed OK!"; - } else { + if (!r) { return } url = pk_refresh+'/actions?action='+_action; @@ -175,10 +173,6 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, else if (_action == 'add_next' || _action == 'add_in') { clearEditSelected(); if (data.pk != null) { - - if (data.alert != null) - alert(data.alert) - refreshScreenFocusPk(data); } else { @@ -189,32 +183,60 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, $("#message_block").css("display", "block"); clearEditSelected(); if (data.pk != null) { - refreshScreenFocusPk(data); + if (data.message != null && data.message != '') { + + modalMessage(data.message, 'alert-danger', function() { + //refreshScreenFocusPk(data); + }); + } + else { + refreshScreenFocusPk(data); + } } else { - alert('Erro exclusão!'); + alert('Erro exclusão de Dispositivo!'); } } else { clearEditSelected(); reloadFunctionClicks(); } + }).always(function() { $("#message_block").css("display", "none"); }); } +function modalMessage(message, alert, closeFunction) { + $('#modal-message #message').html(message); + $('#modal-message').modal('show'); + if (closeFunction != null) { + $('#modal-message, #modal-message .alert button').off(); + $('#modal-message .alert').removeClass('alert-success alert-info alert-warning alert-danger alert-danger'); + $('#modal-message .alert').addClass(alert); + $('#modal-message').on('hidden.bs.modal', closeFunction); + $('#modal-message .alert button').on('click', function() { + $('#modal-message').modal('hide'); + }); + } + +} + function refreshScreenFocusPk(data) { - for (var pai = 0; pai < data.pai.length; pai++) - if (data.pai[pai] != -1) { - clickUpdateDispositivo(null, data.pai[pai], data.pk, 'refresh', pai == 0, true); - } - else { - href = location.href.split('#')[0] - location.href = href+'#'+data.pk - location.reload(true) + if (data.pai[0] == -1) { + $("#message_block").css("display", "block"); + href = location.href.split('#')[0] + location.href = href+'#'+data.pk; + location.reload(true) } + else { + clickUpdateDispositivo(null, data.pai[0], data.pk, 'refresh', true, true); + setTimeout(function() { + for (var pai = 1; pai < data.pai.length; pai++) + clickUpdateDispositivo(null, data.pai[pai], data.pk, 'refresh', false, true); + }, 1000); + } } function clearEditSelected() { diff --git a/static/js/compilacao_view.js b/static/js/compilacao_view.js index f83ab3311..83303432c 100644 --- a/static/js/compilacao_view.js +++ b/static/js/compilacao_view.js @@ -1,11 +1,3 @@ -$( window ).scroll(function() { - if (window.pageYOffset <= 180) - $( "section.vigencias" ).removeClass("fixed"); - else if ( ! $( "section.vigencias" ).hasClass("fixed") ) - $( "section.vigencias" ).addClass("fixed"); -}); - - function isElementInViewport (el) { //special bonus for those using jQuery diff --git a/static/styles/app.scss b/static/styles/app.scss index 61af8fab6..2a1f72c81 100644 --- a/static/styles/app.scss +++ b/static/styles/app.scss @@ -120,3 +120,9 @@ body { .checkbox input, .radio input { display: initial; } + +.modal { + .alert { + margin-bottom: 0; + } +} diff --git a/static/styles/compilacao.scss b/static/styles/compilacao.scss index d41499311..ce3434db1 100644 --- a/static/styles/compilacao.scss +++ b/static/styles/compilacao.scss @@ -778,7 +778,7 @@ a:link:after, a:visited:after { } } .articulacao { - border-top: 2 px solid #e5e5e5; + border-top: 2px solid #e5e5e5; margin: 2em 0; } .bloco_alteracao { diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index 7b9e3916a..30cce516a 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -29,6 +29,18 @@
{% trans 'Aguarde... Atualizando informações!!!'%}
+ +
{% include 'compilacao/text_edit_bloco.html'%}
diff --git a/templates/compilacao/text_list.html b/templates/compilacao/text_list.html index 218befe22..e78344749 100644 --- a/templates/compilacao/text_list.html +++ b/templates/compilacao/text_list.html @@ -49,23 +49,24 @@ {% if forloop.parentloop.last %} - {% if view.inicio_vigencia and view.fim_vigencia %} - - {% blocktrans with inicio_vigencia=view.inicio_vigencia fim_vigencia=view.fim_vigencia ta_publicado=dispositivo.ta_publicado%} + + + {% if view.inicio_vigencia and view.fim_vigencia %} + {% blocktrans with inicio_vigencia=view.inicio_vigencia fim_vigencia=view.fim_vigencia%} Vigência entre {{inicio_vigencia}} e {{fim_vigencia}}. -
- Dada pela {{ta_publicado}} -
- {% endblocktrans%} - {% else%} - - {% blocktrans with inicio_vigencia=dispositivo.inicio_vigencia ta_publicado=dispositivo.ta_publicado%} + {% endblocktrans%} + {% else%} + {% blocktrans with inicio_vigencia=dispositivo.inicio_vigencia%} Vigência a partir de {{inicio_vigencia}}. -
- Dada pela {{ta_publicado}} - {% endblocktrans %} -
- {%endif%} + {% endblocktrans%} + {% endif %} +
+ {% if view.ta_vigencia %} + {% trans 'Dada por '%}{{ta_pub_list|lookup:view.ta_vigencia}} + {% elif view.ta_vigencia != 0 %} + {% trans 'Dada por '%}{{dispositivo.ta_publicado}} + {% endif %} +
{% endif%} {% endfor %} {% else %} @@ -86,7 +87,7 @@ From 621ad13f737c8b4ecb5f4ba5645673e995ca1c6c Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Mon, 7 Mar 2016 10:23:20 -0300 Subject: [PATCH 03/10] =?UTF-8?q?Setar=20dispositivo=20de=20vig=C3=AAncia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compilacao/forms.py | 26 +++++++++++++++++ compilacao/templatetags/compilacao_filters.py | 2 +- compilacao/urls.py | 3 ++ compilacao/views.py | 28 +++++++++++++------ static/js/compilacao_edit.js | 7 +++++ templates/compilacao/publicacao_list.html | 3 -- templates/compilacao/text_edit_bloco.html | 23 +++++++++------ .../compilacao/textoarticulado_detail.html | 2 +- 8 files changed, 71 insertions(+), 23 deletions(-) diff --git a/compilacao/forms.py b/compilacao/forms.py index 68d74191e..1b8d39c9f 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -136,6 +136,17 @@ class TaForm(ModelForm): ) super(TaForm, self).__init__(*args, **kwargs) + instance = getattr(self, 'instance', None) + if instance and instance.pk: + self.fields['tipo_ta'].widget.attrs['disabled'] = True + self.fields['tipo_ta'].required = False + + def clean_tipo_ta(self): + instance = getattr(self, 'instance', None) + if instance and instance.pk: + return instance.tipo_ta + else: + return self.cleaned_data['tipo_ta'] class NotaForm(ModelForm): @@ -451,3 +462,18 @@ class PublicacaoForm(ModelForm): super(PublicacaoForm, self).__init__(*args, **kwargs) pass + + +class DispositivoForm(ModelForm): + + class Meta: + model = Dispositivo + fields = [] + + def __init__(self, *args, **kwargs): + self.helper = FormHelper() + """self.helper.layout = SaplFormLayout( + Fieldset(Publicacao._meta.verbose_name, + row1, row2, row3, css_class="col-md-12"))""" + + super(PublicacaoForm, self).__init__(*args, **kwargs) diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index ac5bc4297..6372ba127 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -93,7 +93,7 @@ def isinst(value, class_str): @register.filter def render_actions_head(view, d_atual): - if view.__class__.__name__ != 'DispositivoEditView': + if view.__class__.__name__ != 'DispositivoSimpleEditView': return False # Menu diff --git a/compilacao/urls.py b/compilacao/urls.py index b3329a16d..0a2948be8 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -31,6 +31,9 @@ urlpatterns_compilacao = [ views.DispositivoView.as_view(), name='dispositivo'), url(r'^(?P[0-9]+)/text/(?P[0-9]+)/refresh', + views.DispositivoSimpleEditView.as_view(), name='dispositivo_refresh'), + + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit', views.DispositivoEditView.as_view(), name='dispositivo_edit'), url(r'^(?P[0-9]+)/text/(?P[0-9]+)/actions', diff --git a/compilacao/views.py b/compilacao/views.py index 222935674..557ae2c49 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1,6 +1,6 @@ -import sys from collections import OrderedDict from datetime import datetime, timedelta +import sys from braces.views import FormMessagesMixin from django import forms @@ -21,7 +21,7 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.views.generic.list import ListView from compilacao.forms import (NotaForm, PublicacaoForm, TaForm, TipoTaForm, - VideForm) + VideForm, DispositivoForm) from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, Publicacao, TextoArticulado, TipoDispositivo, TipoNota, @@ -29,6 +29,7 @@ from compilacao.models import (Dispositivo, Nota, VeiculoPublicacao, Vide) from crud.base import Crud, CrudListView, make_pagination + DISPOSITIVO_SELECT_RELATED = ( 'tipo_dispositivo', 'ta_publicado', @@ -162,7 +163,7 @@ class TipoTaListView(ListView): class TipoTaCreateView(FormMessagesMixin, CreateView): model = TipoTextoArticulado form_class = TipoTaForm - template_name = "compilacao/form.html" + template_name = "crud/form.html" form_valid_message = _('Registro criado com sucesso!') form_invalid_message = _('O registro não foi criado.') @@ -191,7 +192,7 @@ class TipoTaDetailView(CompMixin, DetailView): class TipoTaUpdateView(CompMixin, UpdateView): model = TipoTextoArticulado form_class = TipoTaForm - template_name = "compilacao/form.html" + template_name = "crud/form.html" def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -264,7 +265,7 @@ class TaDetailView(DetailView): class TaCreateView(FormMessagesMixin, CreateView): model = TextoArticulado form_class = TaForm - template_name = "compilacao/form.html" + template_name = "crud/form.html" form_valid_message = _('Registro criado com sucesso!') form_invalid_message = _('O registro não foi criado.') @@ -280,7 +281,7 @@ class TaCreateView(FormMessagesMixin, CreateView): class TaUpdateView(CompMixin, UpdateView): model = TextoArticulado form_class = TaForm - template_name = "compilacao/form.html" + template_name = "crud/form.html" def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -662,7 +663,7 @@ class TextEditView(ListView, CompMixin): request.session['perfil_estrutural'] = perfis[0].pk -class DispositivoEditView(TextEditView): +class DispositivoSimpleEditView(TextEditView): template_name = 'compilacao/text_edit_bloco.html' def post(self, request, *args, **kwargs): @@ -1012,6 +1013,9 @@ class ActionsEditMixin: action = getattr(self, context['action']) return JsonResponse(action(context), safe=False) + def set_dvt(self, context): + return {} + def delete_item_dispositivo(self, context): return self.delete_bloco_dispositivo(context, bloco=False) @@ -1911,7 +1915,7 @@ class PublicacaoListView(ListView): class PublicacaoCreateView(FormMessagesMixin, CreateView): model = Publicacao form_class = PublicacaoForm - template_name = "compilacao/form.html" + template_name = "crud/form.html" form_valid_message = _('Registro criado com sucesso!') form_invalid_message = _('O registro não foi criado.') @@ -1939,7 +1943,7 @@ class PublicacaoDetailView(CompMixin, DetailView): class PublicacaoUpdateView(CompMixin, UpdateView): model = Publicacao form_class = PublicacaoForm - template_name = "compilacao/form.html" + template_name = "crud/form.html" def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -1974,3 +1978,9 @@ class PublicacaoDeleteView(CompMixin, DeleteView): def get_success_url(self): return reverse_lazy('compilacao:ta_pub_list', kwargs={'ta_id': self.kwargs['ta_id']}) + + +class DispositivoEditView(CompMixin, UpdateView): + model = Dispositivo + form_class = DispositivoForm + template_name = "crud/form.html" diff --git a/static/js/compilacao_edit.js b/static/js/compilacao_edit.js index 0e04d15b7..e23e547d6 100644 --- a/static/js/compilacao_edit.js +++ b/static/js/compilacao_edit.js @@ -105,6 +105,13 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, $("#message_block").css("display", "block"); + } + else if (_action.startsWith('set_')) { + + url = pk_refresh+'/actions?action='+_action; + + $("#message_block").css("display", "block"); + } else if (_action.startsWith('delete_')) { var r = confirm("Confirma Exclusão deste dispositivo?"); diff --git a/templates/compilacao/publicacao_list.html b/templates/compilacao/publicacao_list.html index fb80695b6..1c56a343a 100644 --- a/templates/compilacao/publicacao_list.html +++ b/templates/compilacao/publicacao_list.html @@ -9,9 +9,6 @@ {% trans 'Adicionar'%} {%model_verbose_name 'compilacao.models.Publicacao'%} - - {% trans 'Voltar' %} - {% if not object_list %} diff --git a/templates/compilacao/text_edit_bloco.html b/templates/compilacao/text_edit_bloco.html index cf4b0544d..30bc6a2d5 100644 --- a/templates/compilacao/text_edit_bloco.html +++ b/templates/compilacao/text_edit_bloco.html @@ -9,7 +9,7 @@ {% close_div view.flag_nivel_old dpt.nivel 0 %} {% endif%} - {% if forloop.first and view|isinst:'DispositivoEditView' %} + {% if forloop.first and view|isinst:'DispositivoSimpleEditView' %} {% else %}
{% endif%} @@ -25,13 +25,18 @@
  • E*
  • C
  • + {% endblock %} From 68ef0264db7a5e9107d8451c80ee2fd3535fe630 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Fri, 11 Mar 2016 10:10:05 -0300 Subject: [PATCH 04/10] =?UTF-8?q?Criar=20template=20da=20edi=C3=A7=C3=A3o?= =?UTF-8?q?=20avan=C3=A7ada=20-=20issue=20#14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compilacao/forms.py | 96 +++++++++++++++++-- ...301_1816.py => 0045_auto_20160311_1117.py} | 14 ++- compilacao/models.py | 17 +++- compilacao/templatetags/compilacao_filters.py | 4 +- compilacao/urls.py | 6 +- compilacao/utils.py | 2 + compilacao/views.py | 84 ++++++++++++---- static/js/app.js | 25 ++++- static/js/compilacao.js | 17 ---- static/js/compilacao_edit.js | 44 ++++++--- static/js/compilacao_notas.js | 4 +- static/styles/compilacao.scss | 23 ++++- ...mpilacao_tinymce.css => style_tinymce.css} | 2 - templates/compilacao/dispositivo_form.html | 67 +++++++++++++ .../compilacao/dispositivo_form_parents.html | 28 ++++++ templates/compilacao/form.html | 6 -- templates/compilacao/text_edit.html | 55 +++++++++++ templates/compilacao/text_edit_bloco.html | 17 +++- 18 files changed, 429 insertions(+), 82 deletions(-) rename compilacao/migrations/{0044_auto_20160301_1816.py => 0045_auto_20160311_1117.py} (60%) rename static/styles/{compilacao_tinymce.css => style_tinymce.css} (98%) create mode 100644 templates/compilacao/dispositivo_form.html create mode 100644 templates/compilacao/dispositivo_form_parents.html delete mode 100644 templates/compilacao/form.html diff --git a/compilacao/forms.py b/compilacao/forms.py index 1b8d39c9f..eed197ca4 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -464,16 +464,100 @@ class PublicacaoForm(ModelForm): pass -class DispositivoForm(ModelForm): +class DispositivoIntegerField(forms.IntegerField): + + def __init__(self, field_name=None, *args, **kwargs): + + if 'required' not in kwargs: + kwargs.setdefault('required', False) + + self.widget = forms.NumberInput( + attrs={'title': Dispositivo._meta.get_field( + field_name).verbose_name, + 'onchange': 'atualizaRotulo()'}) + + super(DispositivoIntegerField, self).__init__( + min_value=0, *args, **kwargs) + + +class DispositivoEdicaoBasicaForm(ModelForm): + + texto = forms.CharField( + widget=forms.Textarea, + required=False) + + dispositivo1 = DispositivoIntegerField( + label=('1ª %s' % _('Variação')), + field_name='dispositivo1') + dispositivo2 = DispositivoIntegerField( + label=('2ª'), + field_name='dispositivo2') + dispositivo3 = DispositivoIntegerField( + label=('3ª'), + field_name='dispositivo3') + dispositivo4 = DispositivoIntegerField( + label=('4ª'), + field_name='dispositivo4') + dispositivo5 = DispositivoIntegerField( + label=('5ª'), + field_name='dispositivo5') + + rotulo = forms.CharField(label=_('Rótulo Resultante')) class Meta: model = Dispositivo - fields = [] + fields = ( + 'dispositivo0', + 'dispositivo1', + 'dispositivo2', + 'dispositivo3', + 'dispositivo4', + 'dispositivo5', + 'rotulo', + 'texto') + + widgets = { + 'dispositivo0': forms.NumberInput( + attrs={'title': _('Valor 0(zero) é permitido apenas ' + 'para Dispositivos com tipos variáveis.'), + 'onchange': 'atualizaRotulo()'})} def __init__(self, *args, **kwargs): + + layout = [] + + rotulo_fieldset = to_row([ + ('dispositivo0', 3), + ('dispositivo1', 2), + ('dispositivo2', 1), + ('dispositivo3', 1), + ('dispositivo4', 1), + ('dispositivo5', 1), + ('rotulo', 3) + ]) + + layout.append( + Fieldset( + _('Montagem do Rótulo'), + rotulo_fieldset, + css_class="col-md-12")) + + # Campo Texto + row_texto = to_row([('texto', 12)]) + css_class_texto = "col-md-12" + if 'instance' in kwargs and\ + kwargs['instance'].tipo_dispositivo.dispositivo_de_articulacao: + css_class_texto = "col-md-12 hidden" + layout.append( + Fieldset( + Dispositivo._meta.get_field('texto').verbose_name, + row_texto, + css_class=css_class_texto)) + self.helper = FormHelper() - """self.helper.layout = SaplFormLayout( - Fieldset(Publicacao._meta.verbose_name, - row1, row2, row3, css_class="col-md-12"))""" + if layout: + self.helper.layout = SaplFormLayout(*layout) + else: + self.helper.layout = SaplFormLayout() - super(PublicacaoForm, self).__init__(*args, **kwargs) + super(DispositivoEdicaoBasicaForm, self).__init__(*args, **kwargs) diff --git a/compilacao/migrations/0044_auto_20160301_1816.py b/compilacao/migrations/0045_auto_20160311_1117.py similarity index 60% rename from compilacao/migrations/0044_auto_20160301_1816.py rename to compilacao/migrations/0045_auto_20160311_1117.py index fcca5b769..07645df62 100644 --- a/compilacao/migrations/0044_auto_20160301_1816.py +++ b/compilacao/migrations/0045_auto_20160311_1117.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-03-01 21:16 +# Generated by Django 1.9 on 2016-03-11 14:17 from __future__ import unicode_literals from django.db import migrations, models @@ -9,7 +9,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('compilacao', '0043_auto_20160110_1733'), + ('compilacao', '0044_auto_20160307_0918'), ] operations = [ @@ -23,4 +23,14 @@ class Migration(migrations.Migration): name='dispositivo_substituido', field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='compilacao.Dispositivo', verbose_name='Dispositivo Substituido'), ), + migrations.AlterField( + model_name='dispositivo', + name='inconstitucionalidade', + field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Declaração de Inconstitucionalidade'), + ), + migrations.AlterField( + model_name='dispositivo', + name='texto', + field=models.TextField(blank=True, default='', verbose_name='Texto na Norma Original'), + ), ] diff --git a/compilacao/models.py b/compilacao/models.py index f45e94f64..026b4496e 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -135,6 +135,19 @@ class TextoArticulado(TimestampedMixin): 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")} + def organizar_ordem_de_dispositivos(self): + dpts = Dispositivo.objects.filter(ta=self) + + ordem_max = dpts.last().ordem + + dpts.update(ordem=F('ordem') + ordem_max) + + count = 0 + for d in dpts: + count += Dispositivo.INTERVALO_ORDEM + d.ordem = count + d.save() + class TipoNota(models.Model): sigla = models.CharField( @@ -543,7 +556,7 @@ class Dispositivo(BaseModel, TimestampedMixin): texto = models.TextField( blank=True, default='', - verbose_name=_('Texto')) + verbose_name=_('Texto na Norma Original')) texto_atualizador = models.TextField( blank=True, default='', @@ -562,7 +575,7 @@ class Dispositivo(BaseModel, TimestampedMixin): inconstitucionalidade = models.BooleanField( default=False, choices=utils.YES_NO_CHOICES, - verbose_name=_('Inconstitucionalidade')) + verbose_name=_('Declaração de Inconstitucionalidade')) # Relevant attribute only in altering norms visibilidade = models.BooleanField( default=False, diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index 6372ba127..6aab329a5 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -1,8 +1,8 @@ from django import template from django.core.signing import Signer from django.db.models import Q -from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ from compilacao.models import Dispositivo, TipoDispositivo @@ -125,7 +125,7 @@ def nomenclatura(d): result = '(' + d.tipo_dispositivo.nome + ' ' + \ d.rotulo + ')' else: - result = '(' + d.tipo_dispositivo.nome + \ + result = '(' + d.tipo_dispositivo.nome + ' ' + \ d.rotulo_padrao() + ')' return result diff --git a/compilacao/urls.py b/compilacao/urls.py index 0a2948be8..d70445d2a 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -33,8 +33,10 @@ urlpatterns_compilacao = [ url(r'^(?P[0-9]+)/text/(?P[0-9]+)/refresh', views.DispositivoSimpleEditView.as_view(), name='dispositivo_refresh'), - url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit', - views.DispositivoEditView.as_view(), name='dispositivo_edit'), + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit', + views.DispositivoEdicaoBasicaView.as_view(), name='dispositivo_edit'), + + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/actions', views.ActionsEditView.as_view(), name='dispositivo_actions'), diff --git a/compilacao/utils.py b/compilacao/utils.py index ca00f66b4..ef517e08d 100644 --- a/compilacao/utils.py +++ b/compilacao/utils.py @@ -18,6 +18,8 @@ def int_to_roman(int_value): def int_to_letter(int_value): result = '' + if not int_value: + return '0' int_value -= 1 while int_value >= 26: rest = int_value % 26 diff --git a/compilacao/views.py b/compilacao/views.py index 557ae2c49..f631d48bc 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1,6 +1,6 @@ +import sys from collections import OrderedDict from datetime import datetime, timedelta -import sys from braces.views import FormMessagesMixin from django import forms @@ -20,8 +20,8 @@ from django.views.generic.detail import DetailView from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.views.generic.list import ListView -from compilacao.forms import (NotaForm, PublicacaoForm, TaForm, TipoTaForm, - VideForm, DispositivoForm) +from compilacao.forms import (DispositivoEdicaoBasicaForm, NotaForm, + PublicacaoForm, TaForm, TipoTaForm, VideForm) from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, Publicacao, TextoArticulado, TipoDispositivo, TipoNota, @@ -29,7 +29,6 @@ from compilacao.models import (Dispositivo, Nota, VeiculoPublicacao, Vide) from crud.base import Crud, CrudListView, make_pagination - DISPOSITIVO_SELECT_RELATED = ( 'tipo_dispositivo', 'ta_publicado', @@ -1014,7 +1013,18 @@ class ActionsEditMixin: return JsonResponse(action(context), safe=False) def set_dvt(self, context): - return {} + dvt = Dispositivo.objects.get(pk=context['dispositivo_id']) + + if dvt.is_relative_auto_insert(): + dvt = dvt.dispositivo_pai + + try: + Dispositivo.objects.all().update(dispositivo_vigencia=dvt) + return {'message': str(_('Dispositivo de Vigência atualizado ' + 'com sucesso!!!'))} + except: + return {'message': str(_('Ocorreu um erro na atualização do ' + 'Dispositivo de Vigência'))} def delete_item_dispositivo(self, context): return self.delete_bloco_dispositivo(context, bloco=False) @@ -1040,11 +1050,15 @@ class ActionsEditMixin: else: data['pk'] = '' + ta_base = base.ta + # TODO: a linha abaixo causa atualização da tela inteira... # retirar a linha abaixo e identificar atualizações pontuais data['pai'] = [-1, ] - data['message'] = str(self.remover_dispositivo(base, bloco)) + + ta_base.organizar_ordem_de_dispositivos() + return data def remover_dispositivo(self, base, bloco): @@ -1068,10 +1082,7 @@ class ActionsEditMixin: p.fim_eficacia = None for d in base.dispositivos_filhos_set.all(): - if d.tipo_dispositivo.possiveis_pais.filter( - pai=base.tipo_dispositivo, - perfil__padrao=True, - filho_de_insercao_automatica=True).exists(): + if d.is_relative_auto_insert(): self.remover_dispositivo(d, bloco) elif not bloco: p.dispositivos_filhos_set.add(d) @@ -1084,10 +1095,7 @@ class ActionsEditMixin: # independente da escolha do usuário d_nivel_old = d.nivel - if d.tipo_dispositivo.possiveis_pais.filter( - pai=base.tipo_dispositivo, - perfil__padrao=True, - filho_de_insercao_automatica=True).exists(): + if d.is_relative_auto_insert(): continue # encontrar possível pai que será o primeiro parent @@ -1170,7 +1178,7 @@ class ActionsEditMixin: order_by('ordem').filter( ta_id=base.ta_id, ordem__gt=base.ordem, - nivel__lte=base.nivel) + nivel__lte=base.nivel).first() if proximo_independente_base: dcc = Dispositivo.objects.order_by('ordem').filter( @@ -1980,7 +1988,47 @@ class PublicacaoDeleteView(CompMixin, DeleteView): kwargs={'ta_id': self.kwargs['ta_id']}) -class DispositivoEditView(CompMixin, UpdateView): +class DispositivoEdicaoBasicaView(UpdateView): model = Dispositivo - form_class = DispositivoForm - template_name = "crud/form.html" + form_class = DispositivoEdicaoBasicaForm + + @property + def cancel_url(self): + return reverse_lazy( + 'compilacao:ta_text_edit', + kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) + + def get_success_url(self): + return reverse_lazy( + 'compilacao:dispositivo_edit', + kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) + + def get_context_data(self, **kwargs): + return UpdateView.get_context_data(self, **kwargs) + + def run_actions(self, request): + if 'action' in request.GET and\ + request.GET['action'] == 'atualiza_rotulo': + try: + d = Dispositivo.objects.get(pk=self.kwargs['pk']) + d.dispositivo0 = int(request.GET['dispositivo0']) + d.dispositivo1 = int(request.GET['dispositivo1']) + d.dispositivo2 = int(request.GET['dispositivo2']) + d.dispositivo3 = int(request.GET['dispositivo3']) + d.dispositivo4 = int(request.GET['dispositivo4']) + d.dispositivo5 = int(request.GET['dispositivo5']) + d.rotulo = d.rotulo_padrao() + except: + return True, JsonResponse({'message': str( + _('Ocorreu erro na atualização do rótulo'))}, safe=False) + return True, JsonResponse({'rotulo': d.rotulo}, safe=False) + + return False, '' + + def get(self, request, *args, **kwargs): + + flag_action, render_json_response = self.run_actions(request) + if flag_action: + return render_json_response + + return UpdateView.get(self, request, *args, **kwargs) diff --git a/static/js/app.js b/static/js/app.js index 2ae9c1c57..71edb18ac 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1,8 +1,24 @@ +function initTinymce() { + removeTinymce(); + tinymce.init({ + mode : "textareas", + force_br_newlines : false, + force_p_newlines : false, + forced_root_block : '', + plugins: ["table save code"], + menubar: "edit format table tools", + toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent", + tools: "inserttable", + border_css: "/static/styles/style_tinymce.css", + content_css: "/static/styles/style_tinymce.css" + }); +} -tinymce.init({ - mode : "exact", - elements : "biografia-parlamentar,casa-informacoes" - }); +function removeTinymce() { + while (tinymce.editors.length > 0) { + tinymce.remove(tinymce.editors[0]); + } +} function refreshDatePicker() { $.datepicker.setDefaults($.datepicker.regional['pt-BR']); @@ -96,4 +112,5 @@ $(document).ready(function(){ refreshDatePicker(); refreshMask(); autorModal(); + initTinymce(); }); diff --git a/static/js/compilacao.js b/static/js/compilacao.js index b36783c66..3c4a3f859 100644 --- a/static/js/compilacao.js +++ b/static/js/compilacao.js @@ -1,20 +1,3 @@ -function initTinymce() { - - tinymce.init({ - mode : "textareas", - force_br_newlines : false, - force_p_newlines : false, - forced_root_block : '', - plugins: ["table save code"], - menubar: "edit format table tools", - toolbar: "save | undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent", - tools: "inserttable", - save_onsavecallback: onSubmitEditForm, - border_css: "/static/styles/compilacao_tinymce.css", - content_css: "/static/styles/compilacao_tinymce.css" - }); -} - function SetCookie(cookieName,cookieValue,nDays) { var today = new Date(); var expire = new Date(); diff --git a/static/js/compilacao_edit.js b/static/js/compilacao_edit.js index e23e547d6..51b7b8cee 100644 --- a/static/js/compilacao_edit.js +++ b/static/js/compilacao_edit.js @@ -1,3 +1,19 @@ +function initTinymceForEdit() { + + tinymce.init({ + mode : "textareas", + force_br_newlines : false, + force_p_newlines : false, + forced_root_block : '', + plugins: ["table save code"], + menubar: "edit format table tools", + toolbar: "save | undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent", + tools: "inserttable", + save_onsavecallback: onSubmitEditForm, + border_css: "/static/styles/compilacao_tinymce.css", + content_css: "/static/styles/compilacao_tinymce.css" + }); +} var editortype = "textarea"; var gets = 0; @@ -95,7 +111,6 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, } } url = pk_refresh+'/refresh?edit='+pk_edit+url; - } else if (_action.startsWith('add_')) { @@ -109,7 +124,6 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, else if (_action.startsWith('set_')) { url = pk_refresh+'/actions?action='+_action; - $("#message_block").css("display", "block"); } @@ -148,7 +162,7 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, } if ( _editortype == 'tinymce' ) { - initTinymce(); + initTinymceForEdit(); } else if (_editortype == 'textarea') { $('.csform form').submit(onSubmitEditForm); @@ -190,15 +204,10 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, $("#message_block").css("display", "block"); clearEditSelected(); if (data.pk != null) { - if (data.message != null && data.message != '') { - - modalMessage(data.message, 'alert-danger', function() { + if (!modalMessage(data.message, 'alert-danger', function() { //refreshScreenFocusPk(data); - }); - } - else { + })) refreshScreenFocusPk(data); - } } else { alert('Erro exclusão de Dispositivo!'); @@ -207,6 +216,7 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, else { clearEditSelected(); reloadFunctionClicks(); + modalMessage(data.message, 'alert-success', null); } }).always(function() { @@ -215,18 +225,22 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action, } function modalMessage(message, alert, closeFunction) { - $('#modal-message #message').html(message); - $('#modal-message').modal('show'); - if (closeFunction != null) { + if (message != null && message != '') { + $('#modal-message #message').html(message); + $('#modal-message').modal('show'); $('#modal-message, #modal-message .alert button').off(); $('#modal-message .alert').removeClass('alert-success alert-info alert-warning alert-danger alert-danger'); $('#modal-message .alert').addClass(alert); - $('#modal-message').on('hidden.bs.modal', closeFunction); + + if (closeFunction != null) + $('#modal-message').on('hidden.bs.modal', closeFunction); + $('#modal-message .alert button').on('click', function() { $('#modal-message').modal('hide'); }); + return true; } - + return false; } function refreshScreenFocusPk(data) { diff --git a/static/js/compilacao_notas.js b/static/js/compilacao_notas.js index dd5a02c91..97a4709f2 100644 --- a/static/js/compilacao_notas.js +++ b/static/js/compilacao_notas.js @@ -7,7 +7,7 @@ function onEventsDneExec(pk, model) { refreshDatePicker() - $('#dne'+pk+" #button-id-submit-form").click(onSubmitEditForm); + $('#dne'+pk+" #button-id-submit-form").click(onSubmitEditNVForm); $('#dne'+pk+" .btn-close-container").click(function(){ $(this).closest('.dne-nota').removeClass('dne-nota'); $(this).closest('.dne-form').html(''); @@ -88,7 +88,7 @@ var onChangeParamNorma = function(event) { }); } -var onSubmitEditForm = function(event) { +var onSubmitEditNVForm = function(event) { var url = ''; var model = 'nota'; diff --git a/static/styles/compilacao.scss b/static/styles/compilacao.scss index ce3434db1..d0f7b86d3 100644 --- a/static/styles/compilacao.scss +++ b/static/styles/compilacao.scss @@ -919,6 +919,7 @@ a:link:after, a:visited:after { display: table; li { display: table-cell; + padding: 0 0.5em; } } @@ -1196,6 +1197,26 @@ a:link:after, a:visited:after { } } +.cp-nav-parents { + & > .dropdown-menu { + left: 0; + right: auto; + &::before { + content: ''; + position: absolute; + top: -11px; + width: 100%; + height: 11px; + } + } + &:hover { + & > .dropdown-menu { + display: block; + } + } +} + + .class_color_container { background: #ddd !important; @@ -1204,7 +1225,7 @@ a:link:after, a:visited:after { clear:both; } .mce-panel { - border: 0px solid #ccc !important; + /*border: 0px solid #ccc !important;*/ } .mce-btn button:hover { background-color: rgba(0,0,0,0.1) !important; diff --git a/static/styles/compilacao_tinymce.css b/static/styles/style_tinymce.css similarity index 98% rename from static/styles/compilacao_tinymce.css rename to static/styles/style_tinymce.css index cf39b89ad..d2909b025 100644 --- a/static/styles/compilacao_tinymce.css +++ b/static/styles/style_tinymce.css @@ -1,5 +1,3 @@ - - .mce-content-body { font-family: "Open Sans" "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; font-style: normal; diff --git a/templates/compilacao/dispositivo_form.html b/templates/compilacao/dispositivo_form.html new file mode 100644 index 000000000..cb17c9cfa --- /dev/null +++ b/templates/compilacao/dispositivo_form.html @@ -0,0 +1,67 @@ +{% extends "base.html" %} +{% load i18n crispy_forms_tags %} +{% load compilacao_filters %} +{% load staticfiles %} +{% load sass_tags %} + +{% block head_content %}{{block.super}} + +{% endblock %} + +{% block title %} +

    {{object.ta}}
    {% trans 'Edição de Dispositivo' %}

    +{% endblock%} +{% block base_content %} +
    + {%for parent in object.get_parents_asc %} + {%with node=parent active=False template_name='compilacao/dispositivo_form_parents.html' %} + {%include template_name%} + {%endwith%} + {%endfor %} + + {%with node=object active=True template_name='compilacao/dispositivo_form_parents.html' %} + {%include template_name%} + {%endwith%} +
    +

    + {% crispy form %} +{% endblock %} + +{% block foot_js %} + {{block.super}} + +{% endblock %} + +{% block extra_js %} + +{% endblock %} diff --git a/templates/compilacao/dispositivo_form_parents.html b/templates/compilacao/dispositivo_form_parents.html new file mode 100644 index 000000000..7006d2581 --- /dev/null +++ b/templates/compilacao/dispositivo_form_parents.html @@ -0,0 +1,28 @@ +{% load i18n %} +{% load compilacao_filters %} + +{% if not node.dispositivos_filhos_set.exists %} + + {{node|nomenclatura}} + +{% else %} + +
    + + {{node|nomenclatura}} + + + + + +
    + +{% endif %} diff --git a/templates/compilacao/form.html b/templates/compilacao/form.html deleted file mode 100644 index e25d5d3ab..000000000 --- a/templates/compilacao/form.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "base.html" %} -{% load i18n crispy_forms_tags %} - -{% block base_content %} - {% crispy form %} -{% endblock %} diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index 30cce516a..d201c2a98 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -45,6 +45,61 @@ {% include 'compilacao/text_edit_bloco.html'%}
    + + {% endblock base_content %} {% block foot_js %} diff --git a/templates/compilacao/text_edit_bloco.html b/templates/compilacao/text_edit_bloco.html index 30bc6a2d5..c5568fe21 100644 --- a/templates/compilacao/text_edit_bloco.html +++ b/templates/compilacao/text_edit_bloco.html @@ -22,7 +22,7 @@
  • E
  • E+
  • {%endif%} -
  • E*
  • +
  • E*
  • C
  • @@ -87,8 +87,19 @@
      -
    • p: {{dpt.dispositivo_substituido_id}}, n: {{dpt.dispositivo_subsequente_id}}, Ordem: {{dpt.ordem}}, Nivel: {{dpt.nivel}}, Número: {{dpt.get_numero_completo}}
    • -
    • .
    • +
    • p: {{dpt.dispositivo_substituido_id|default:''}}, n: {{dpt.dispositivo_subsequente_id|default:''}}, Ordem: {{dpt.ordem}}, Nivel: {{dpt.nivel}}, Número: {{dpt.get_numero_completo}}
    • + + {% if dpt.dispositivo_vigencia %} +
    • {% field_verbose_name dpt 'dispositivo_vigencia'%}: {{dpt.dispositivo_vigencia|nomenclatura}}
    • + {% endif %} + +
    • + + ? + +
    • + +
      From 61d91b75e3f8063acdd14d5e1b037cd9caabcd4f Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 16 Mar 2016 14:19:37 -0300 Subject: [PATCH 05/10] =?UTF-8?q?Criar=20form=20de=20Dados=20B=C3=A1sicos?= =?UTF-8?q?=20da=20Edi=C3=A7=C3=A3o=20Avan=C3=A7ada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compilacao/forms.py | 218 ++++++++++++------ compilacao/models.py | 4 +- compilacao/urls.py | 6 +- compilacao/views.py | 64 ++++- crispy_layout_mixin.py | 6 +- templates/compilacao/dispositivo_form.html | 16 ++ .../compilacao/dispositivo_form_parents.html | 6 +- 7 files changed, 232 insertions(+), 88 deletions(-) diff --git a/compilacao/forms.py b/compilacao/forms.py index eed197ca4..cb854f9af 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -1,20 +1,24 @@ -from crispy_forms.bootstrap import FieldWithButtons, FormActions, StrictButton +from crispy_forms.bootstrap import FieldWithButtons, FormActions, StrictButton,\ + InlineRadios, Alert from crispy_forms.helper import FormHelper from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, Layout, Row) from django import forms from django.core.exceptions import NON_FIELD_ERRORS from django.forms.models import ModelForm +from django.template import defaultfilters from django.utils.translation import ugettext_lazy as _ from compilacao.models import (NOTAS_PUBLICIDADE_CHOICES, PARTICIPACAO_SOCIAL_CHOICES, Dispositivo, Nota, Publicacao, TextoArticulado, TipoNota, TipoPublicacao, TipoTextoArticulado, TipoVide, - VeiculoPublicacao, Vide) + VeiculoPublicacao, Vide, TipoDispositivo) from crispy_layout_mixin import SaplFormLayout, to_column, to_row +from sapl import utils from sapl.utils import YES_NO_CHOICES + error_messages = { 'required': _('Este campo é obrigatório'), 'invalid': _('URL inválida.') @@ -257,6 +261,10 @@ class NotaForm(ModelForm): super(NotaForm, self).__init__(*args, **kwargs) +class DispositivoSearchFragmentForm(ModelForm): + pass + + class VideForm(ModelForm): dispositivo_base = forms.ModelChoiceField( queryset=Dispositivo.objects.all(), @@ -343,7 +351,7 @@ class VideForm(ModelForm): 'números ou algo' ' que estejam ' 'no rótulo ou no texto.')), - StrictButton("Buscar", css_class='btn-busca')), 12))), + StrictButton(_('Buscar'), css_class='btn-busca')), 12))), Row(to_column( (Div(css_class='container-busca'), 12))) ) @@ -482,82 +490,156 @@ class DispositivoIntegerField(forms.IntegerField): class DispositivoEdicaoBasicaForm(ModelForm): - texto = forms.CharField( - widget=forms.Textarea, - required=False) + class Meta: + model = Dispositivo + fields = [] + + def __init__(self, *args, **kwargs): + + layout = [] + + inst = kwargs['instance'] if 'instance' in kwargs else None + + if inst and inst.tipo_dispositivo.formato_variacao0 in [ + TipoDispositivo.FNC8, TipoDispositivo.FNCN]: + if 'rotulo' in DispositivoEdicaoBasicaForm.Meta.fields: + DispositivoEdicaoBasicaForm.Meta.fields.remove('rotulo') + for i in range(6): + DispositivoEdicaoBasicaForm.Meta.fields.remove( + 'dispositivo%s' % i) + else: + if 'rotulo' not in DispositivoEdicaoBasicaForm.Meta.fields: + DispositivoEdicaoBasicaForm.Meta.fields.append('rotulo') + for i in range(6): + DispositivoEdicaoBasicaForm.Meta.fields.append( + 'dispositivo%s' % i) + # adiciona campos de rótulo no formulário + self.dispositivo0 = forms.IntegerField( + min_value=0, + label=Dispositivo._meta.get_field('dispositivo0').verbose_name, + widget=forms.NumberInput( + attrs={'title': _('Valor 0(zero) é permitido apenas para ' + 'Dispositivos com tipos variáveis.'), + 'onchange': 'atualizaRotulo()'})) + self.dispositivo1 = DispositivoIntegerField( + label=('1ª %s' % _('Variação')), + field_name='dispositivo1') + self.dispositivo2 = DispositivoIntegerField( + label=('2ª'), + field_name='dispositivo2') + self.dispositivo3 = DispositivoIntegerField( + label=('3ª'), + field_name='dispositivo3') + self.dispositivo4 = DispositivoIntegerField( + label=('4ª'), + field_name='dispositivo4') + self.dispositivo5 = DispositivoIntegerField( + label=('5ª'), + field_name='dispositivo5') + + self.rotulo = forms.CharField( + required=False, label=_('Rótulo Resultante')) + + rotulo_fieldset = to_row([ + ('dispositivo0', 3), + ('dispositivo1', 2), + ('dispositivo2', 1), + ('dispositivo3', 1), + ('dispositivo4', 1), + ('dispositivo5', 1), + ('rotulo', 3)]) + + layout.append(Fieldset(_('Construção do Rótulo'), rotulo_fieldset, + css_class="col-md-12")) + + if inst and inst.tipo_dispositivo.dispositivo_de_articulacao: + if 'texto' in DispositivoEdicaoBasicaForm.Meta.fields: + DispositivoEdicaoBasicaForm.Meta.fields.remove('texto') + else: + if 'texto' not in DispositivoEdicaoBasicaForm.Meta.fields: + DispositivoEdicaoBasicaForm.Meta.fields.append('texto') + + self.texto = forms.CharField(required=False, + label='', + widget=forms.Textarea()) + row_texto = to_row([('texto', 12)]) + layout.append( + Fieldset(Dispositivo._meta.get_field('texto').verbose_name, + row_texto, + css_class="col-md-12")) + + fields = DispositivoEdicaoBasicaForm.Meta.fields + if fields: + self.base_fields.clear() + for f in fields: + self.base_fields.update({f: getattr(self, f)}) - dispositivo1 = DispositivoIntegerField( - label=('1ª %s' % _('Variação')), - field_name='dispositivo1') - dispositivo2 = DispositivoIntegerField( - label=('2ª'), - field_name='dispositivo2') - dispositivo3 = DispositivoIntegerField( - label=('3ª'), - field_name='dispositivo3') - dispositivo4 = DispositivoIntegerField( - label=('4ª'), - field_name='dispositivo4') - dispositivo5 = DispositivoIntegerField( - label=('5ª'), - field_name='dispositivo5') - - rotulo = forms.CharField(label=_('Rótulo Resultante')) + self.helper = FormHelper() + self.helper.layout = SaplFormLayout( + *layout, + label_cancel=_('Retornar para o Editor Sequencial')) + + super(DispositivoEdicaoBasicaForm, self).__init__(*args, **kwargs) + + +class DispositivoEdicaoVigenciaForm(ModelForm): + + inconstitucionalidade = forms.ChoiceField( + label=Dispositivo._meta.get_field( + 'inconstitucionalidade').verbose_name, + choices=utils.YES_NO_CHOICES, + widget=forms.RadioSelect()) class Meta: model = Dispositivo - fields = ( - 'dispositivo0', - 'dispositivo1', - 'dispositivo2', - 'dispositivo3', - 'dispositivo4', - 'dispositivo5', - 'rotulo', - 'texto') - - widgets = { - 'dispositivo0': forms.NumberInput( - attrs={'title': _('Valor 0(zero) é permitido apenas ' - 'para Dispositivos com tipos variáveis.'), - 'onchange': 'atualizaRotulo()'})} + fields = ['inicio_vigencia', + 'fim_vigencia', + 'inicio_eficacia', + 'fim_eficacia', + 'publicacao', + 'inconstitucionalidade' + ] def __init__(self, *args, **kwargs): layout = [] - rotulo_fieldset = to_row([ - ('dispositivo0', 3), - ('dispositivo1', 2), - ('dispositivo2', 1), - ('dispositivo3', 1), - ('dispositivo4', 1), - ('dispositivo5', 1), - ('rotulo', 3) - ]) + row_publicacao = to_row([ + ('publicacao', 6), + (InlineRadios('inconstitucionalidade'), 3), ]) + row_publicacao.fields.append( + Alert( + css_class='alert-info col-md-3', + content='%s%s' % ( + _('Dica!'), _('Inclua uma Nota de Dispositivo informando ' + 'sobre a Inconstitucionalidade.')))) layout.append( - Fieldset( - _('Montagem do Rótulo'), - rotulo_fieldset, - css_class="col-md-12")) - - # Campo Texto - row_texto = to_row([('texto', 12)]) - css_class_texto = "col-md-12" - if 'instance' in kwargs and\ - kwargs['instance'].tipo_dispositivo.dispositivo_de_articulacao: - css_class_texto = "col-md-12 hidden" + Fieldset(_('Registro de Publicação e Validade'), + row_publicacao, + css_class="col-md-12")) + + row_datas = to_row([ + ('inicio_vigencia', 3), + ('fim_vigencia', 3), + ('inicio_eficacia', 3), + ('fim_eficacia', 3), ]) layout.append( - Fieldset( - Dispositivo._meta.get_field('texto').verbose_name, - row_texto, - css_class=css_class_texto)) + Fieldset(_('Datas de Controle de Vigência'), + row_datas, + css_class="col-md-12")) self.helper = FormHelper() - if layout: - self.helper.layout = SaplFormLayout(*layout) - else: - self.helper.layout = SaplFormLayout() - - super(DispositivoEdicaoBasicaForm, self).__init__(*args, **kwargs) + self.helper.layout = SaplFormLayout( + *layout, + label_cancel=_('Retornar para o Editor Sequencial')) + + super(DispositivoEdicaoVigenciaForm, self).__init__(*args, **kwargs) + + pubs = Publicacao.objects.order_by( + '-data', '-hora').filter(ta=self.instance.ta) + self.fields['publicacao'].choices = [("", "---------")] + [( + p.pk, _('%s realizada em %s') % ( + p.tipo_publicacao, + defaultfilters.date( + p.data, "d \d\e F \d\e Y"))) for p in pubs] diff --git a/compilacao/models.py b/compilacao/models.py index 026b4496e..f9bfb61ff 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -556,7 +556,7 @@ class Dispositivo(BaseModel, TimestampedMixin): texto = models.TextField( blank=True, default='', - verbose_name=_('Texto na Norma Original')) + verbose_name=_('Texto Original')) texto_atualizador = models.TextField( blank=True, default='', @@ -575,7 +575,7 @@ class Dispositivo(BaseModel, TimestampedMixin): inconstitucionalidade = models.BooleanField( default=False, choices=utils.YES_NO_CHOICES, - verbose_name=_('Declaração de Inconstitucionalidade')) + verbose_name=_('Declarado Inconstitucional')) # Relevant attribute only in altering norms visibilidade = models.BooleanField( default=False, diff --git a/compilacao/urls.py b/compilacao/urls.py index d70445d2a..0d48376b1 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -33,9 +33,13 @@ urlpatterns_compilacao = [ url(r'^(?P[0-9]+)/text/(?P[0-9]+)/refresh', views.DispositivoSimpleEditView.as_view(), name='dispositivo_refresh'), - url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit', + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit$', views.DispositivoEdicaoBasicaView.as_view(), name='dispositivo_edit'), + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit/vigencia', + views.DispositivoEdicaoVigenciaView.as_view(), + name='dispositivo_edit_vigencia'), + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/actions', diff --git a/compilacao/views.py b/compilacao/views.py index f631d48bc..62bdd32f4 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1,6 +1,6 @@ -import sys from collections import OrderedDict from datetime import datetime, timedelta +import sys from braces.views import FormMessagesMixin from django import forms @@ -21,7 +21,8 @@ from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.views.generic.list import ListView from compilacao.forms import (DispositivoEdicaoBasicaForm, NotaForm, - PublicacaoForm, TaForm, TipoTaForm, VideForm) + PublicacaoForm, TaForm, TipoTaForm, VideForm, + DispositivoEdicaoVigenciaForm) from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, Publicacao, TextoArticulado, TipoDispositivo, TipoNota, @@ -29,6 +30,7 @@ from compilacao.models import (Dispositivo, Nota, VeiculoPublicacao, Vide) from crud.base import Crud, CrudListView, make_pagination + DISPOSITIVO_SELECT_RELATED = ( 'tipo_dispositivo', 'ta_publicado', @@ -1772,12 +1774,6 @@ class VideDeleteView(VideMixin, TemplateView): class DispositivoSearchFragmentFormView(ListView): template_name = 'compilacao/dispositivo_search_fragment_form.html' - @method_decorator(login_required) - def dispatch(self, *args, **kwargs): - return super( - DispositivoSearchFragmentFormView, - self).dispatch(*args, **kwargs) - def get_queryset(self): try: busca = '' @@ -2003,8 +1999,8 @@ class DispositivoEdicaoBasicaView(UpdateView): 'compilacao:dispositivo_edit', kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) - def get_context_data(self, **kwargs): - return UpdateView.get_context_data(self, **kwargs) + def get_url_this_view(self): + return 'compilacao:dispositivo_edit' def run_actions(self, request): if 'action' in request.GET and\ @@ -2018,10 +2014,32 @@ class DispositivoEdicaoBasicaView(UpdateView): d.dispositivo4 = int(request.GET['dispositivo4']) d.dispositivo5 = int(request.GET['dispositivo5']) d.rotulo = d.rotulo_padrao() + + numero = d.get_numero_completo()[1:] + + zerar = False + for i in range(len(numero)): + if not numero[i]: + zerar = True + + if zerar: + numero[i] = 0 + + if zerar: + d.set_numero_completo([d.dispositivo0, ] + numero) + d.rotulo = d.rotulo_padrao() + except: return True, JsonResponse({'message': str( _('Ocorreu erro na atualização do rótulo'))}, safe=False) - return True, JsonResponse({'rotulo': d.rotulo}, safe=False) + return True, JsonResponse({ + 'rotulo': d.rotulo, + 'dispositivo0': d.dispositivo0, + 'dispositivo1': d.dispositivo1, + 'dispositivo2': d.dispositivo2, + 'dispositivo3': d.dispositivo3, + 'dispositivo4': d.dispositivo4, + 'dispositivo5': d.dispositivo5}, safe=False) return False, '' @@ -2032,3 +2050,27 @@ class DispositivoEdicaoBasicaView(UpdateView): return render_json_response return UpdateView.get(self, request, *args, **kwargs) + + +class DispositivoEdicaoVigenciaView(DispositivoEdicaoBasicaView): + model = Dispositivo + form_class = DispositivoEdicaoVigenciaForm + + def get_url_this_view(self): + return 'compilacao:dispositivo_edit_vigencia' + + def get_success_url(self): + return reverse_lazy( + 'compilacao:dispositivo_edit_vigencia', + kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) + + def run_actions(self, request): + if 'action' in request.GET and\ + request.GET['action'] == 'atualiza_rotulo': + try: + pass + except: + return True, JsonResponse({'message': str( + _('Ocorreu erro na atualização do rótulo'))}, safe=False) + return True, JsonResponse({}, safe=False) + return False, '' diff --git a/crispy_layout_mixin.py b/crispy_layout_mixin.py index 46dadf7a7..c812b4315 100644 --- a/crispy_layout_mixin.py +++ b/crispy_layout_mixin.py @@ -1,11 +1,11 @@ from math import ceil from os.path import dirname, join -import rtyaml from crispy_forms.bootstrap import FormActions from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit from django.utils.translation import ugettext as _ +import rtyaml def heads_and_tails(list_of_lists): @@ -39,10 +39,10 @@ def form_actions(more=[], save_label=_('Salvar')): class SaplFormLayout(Layout): - def __init__(self, *fields): + def __init__(self, *fields, label_cancel=_('Cancelar')): buttons = form_actions(more=[ HTML('%s' % _('Cancelar'))]) + ' class="btn btn-inverse">%s' % label_cancel)]) _fields = list(to_fieldsets(fields)) + [to_row([(buttons, 12)])] super(SaplFormLayout, self).__init__(*_fields) diff --git a/templates/compilacao/dispositivo_form.html b/templates/compilacao/dispositivo_form.html index cb17c9cfa..1c5350be9 100644 --- a/templates/compilacao/dispositivo_form.html +++ b/templates/compilacao/dispositivo_form.html @@ -7,6 +7,16 @@ {% block head_content %}{{block.super}} {% endblock %} +{% block sections_nav %} + +{% endblock sections_nav %} {% block title %}

      {{object.ta}}
      {% trans 'Edição de Dispositivo' %}

      @@ -52,6 +62,12 @@ $.get(url, formData).done(function(data) { if (data.rotulo != undefined) { $('[name="rotulo"]').val(data.rotulo); + $('[name="dispositivo0"]').val(data.dispositivo0); + $('[name="dispositivo1"]').val(data.dispositivo1); + $('[name="dispositivo2"]').val(data.dispositivo2); + $('[name="dispositivo3"]').val(data.dispositivo3); + $('[name="dispositivo4"]').val(data.dispositivo4); + $('[name="dispositivo5"]').val(data.dispositivo5); return; } }); diff --git a/templates/compilacao/dispositivo_form_parents.html b/templates/compilacao/dispositivo_form_parents.html index 7006d2581..09d1c2cf1 100644 --- a/templates/compilacao/dispositivo_form_parents.html +++ b/templates/compilacao/dispositivo_form_parents.html @@ -2,13 +2,13 @@ {% load compilacao_filters %} {% if not node.dispositivos_filhos_set.exists %} - + {{node|nomenclatura}} {% else %}
      - + {{node|nomenclatura}} @@ -16,7 +16,7 @@
      - {% elif dpt.tipo_dispositivo.dispositivo_de_articulacao and request.GET.tipo_select != 'select_for_vide'%} + {% elif dpt.tipo_dispositivo.dispositivo_de_articulacao%}
    • diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index d201c2a98..e72b41eba 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -29,7 +29,7 @@
      {% trans 'Aguarde... Atualizando informações!!!'%}
      -
    • (C) Construtor Estrutural: Neste modo, o editor foca na inserção de Dispositivos e busca deixar mais acessíveis as estas ações.
    • -
    • A Edição Avançada é complexa e sensível a erros. É recomendável o uso cuidadoso e consciente das funcionalidades.
    • +
    • A Edição Avançada é complexa e sensível a erros de edição. É recomendável o uso cuidadoso e consciente das funcionalidades.
    • Gere toda a estrutura básica sem adicionar texto, isso evitará erros estruturais e otimizará seu trabalho por:
      1. Facilitar o trabalho local aí, de seu navegador.
      2. @@ -75,21 +75,35 @@
    • Inserir os Dispositivos na sequência natural é mais produtivo para você, além de ser também mais simples para o algorítmo que controla este processo. Quanto maior a mudança estutural, mais lento será o procedimento.
    • -
    • A exclusão de Dispositivos é um processo moroso e complicado, principalmente se o que está sendo excluido for, ou envolver, os DCC's - Dispositivos de Contagem Continua, como é o caso do Tipo de Dispositivo (Artigo), que é um tipo comum nos Textos Articulados Brasileiros. - As exclusões podem ser diretas, individuais ou em bloco: +
    • A Opção DVt (Dispositivo de Vigência do Texto) redefine o dispositivo em seleção, como o dispositivo de vigência de todos os outros, desde que estes sejam os dispositivos originais do texto.
        -
      1. Diretas: Dispositivos que não possuam itens internos são excluidos diretamente.
      2. -
      3. Individuais: Dispositivos que possuam itens internos e este podem ser reenquadrados no Dispositivo imediatamente anterior
      4. -
      5. Em Bloco: Todo o conteúdo incluído no Dispositivo em edição será excluído.
      6. +
      7. O Dispositivo de Vigência de Dispositivos Alterados são controlados pelos seus Dispositivos Alteradores
      8. +
      9. Ao usar a opção DVt, todas as datas de início de vigência serão reenquadradas para a data de vigência do dispositivo de vigência. Posteriormente, alterações manuais poderão ser feitas.
      -
        + +
      • A criação de Tipos de Dispositivos é dinâmica e deverão estar amarrados por perfis estuturais configuráveis. Por serem tarefas técnicas e complicadas, criar/editar tipos de dispositivos e perfis estuturais estão disponíveis apenas na área de edição técnica do SAPL (admin). +
      • + +
        • As exclusões e inserções, quando acionadas, renumeram e redefinem os rótulos, tanto de dispositivos locais, quanto os DCC's.
        - +
        +

        Exclusões

        +
          +
        1. A exclusão de Dispositivos é um processo moroso e complicado, principalmente se o que está sendo excluido for, ou envolver, os DCC's - Dispositivos de Contagem Continua, como é o caso do Tipo de Dispositivo (Artigo), que é um tipo comum nos Textos Articulados Brasileiros. + As exclusões podem ser diretas, individuais ou em bloco: +
            +
          1. Diretas: Dispositivos que não possuam itens internos são excluidos diretamente.
          2. +
          3. Individuais: Dispositivos que possuam itens internos e este podem ser reenquadrados no Dispositivo imediatamente anterior +
              +
            • Ainda Não foi implementado a transferência de conteúdo na exclusão individual de DCC's que estão estruturalmente separados. Ex: Um artigo possui parágrafos, se seu artigo imediatamente anterior estiver no mesmo sub-grupo, esses parágrafos, na exlcusão individual, serão transferidos para o artigo anterior, no entanto, se estiverem em sub-grupo separados, o artigo será completamente excluido como em uma exclusão em bloco.
            • +
            +
          4. +
          5. Em Bloco: Todo o conteúdo incluído no Dispositivo em edição será excluído.
          6. +
          +
        2. +
        -
      • A criação de Tipos de Dispositivos é dinâmica e deverão estar amarrados por perfis estuturais configuráveis. Por serem tarefas técnicas e complicadas, criar/editar tipos de dispositivos e perfis estuturais estão disponíveis apenas na área de edição técnica do SAPL (admin). -
      • - {% endblocktrans %} diff --git a/templates/compilacao/text_edit_bloco.html b/templates/compilacao/text_edit_bloco.html index f35de10b8..1cd33507e 100644 --- a/templates/compilacao/text_edit_bloco.html +++ b/templates/compilacao/text_edit_bloco.html @@ -121,7 +121,7 @@ {% endif %}
        {% spaceless %} -
        {{ dpt.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ dpt.rotulo }}{{ dpt.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{% if dpt.texto == '' and not dpt.tipo_dispositivo.dispositivo_de_articulacao %}({{dpt.tipo_dispositivo}} sem texto){%else%}{{ dpt.texto|safe }}{%endif%}
        +
        {{ dpt.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ dpt.rotulo }}{{ dpt.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{% if dpt.texto == '' and not dpt.tipo_dispositivo.dispositivo_de_articulacao %}({{dpt.tipo_dispositivo}} sem texto){%else%}{{ dpt.texto|safe }}{%endif%}
        {% if dpt.ta_publicado_id != None and not dpt.tipo_dispositivo.dispositivo_de_articulacao %} {{ dpt.tipo_dispositivo.nota_automatica_prefixo_html|safe }} diff --git a/templates/compilacao/text_list.html b/templates/compilacao/text_list.html index e78344749..99db8a044 100644 --- a/templates/compilacao/text_list.html +++ b/templates/compilacao/text_list.html @@ -45,7 +45,7 @@ {% elif forloop.last %} {% for dispositivo in values %}
      • - {% trans 'Texto Atual'%} + {% trans 'Texto Atual'%}
      • {% if forloop.parentloop.last %}
      @@ -75,7 +75,7 @@ {% for dispositivo in values %}
    • {% if not forloop.parentloop.first %} - {% trans 'Vigência entre'%} {{dispositivo.inicio_vigencia}} {% trans 'e'%} {{dispositivo.fim_vigencia}} + {% trans 'Vigência entre'%} {{dispositivo.inicio_vigencia}} {% trans 'e'%} {{dispositivo.fim_vigencia}} {% endif %}
    • {% endfor %} From c4f8ef3b770fefdd45970bdb1cdae091c1652e66 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 30 Mar 2016 00:18:40 -0300 Subject: [PATCH 08/10] =?UTF-8?q?Impl=20Editores=20(individual=20e=20rever?= =?UTF-8?q?so)=20de=20vig=C3=AAncias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compilacao/forms.py | 229 +++++- compilacao/models.py | 20 +- compilacao/templatetags/compilacao_filters.py | 30 +- compilacao/urls.py | 10 +- compilacao/views.py | 748 ++++++++++-------- static/js/compilacao.js | 203 ++++- static/js/compilacao_edit.js | 18 +- static/styles/compilacao.scss | 51 +- templates/compilacao/dispositivo_form.html | 78 +- .../dispositivo_form_definidor_vigencia.html | 11 + .../dispositivo_form_edicao_basica.html | 42 + .../compilacao/dispositivo_form_parents.html | 9 +- .../compilacao/dispositivo_form_search.html | 19 + .../dispositivo_form_search_fragment.html | 75 ++ .../compilacao/dispositivo_form_vigencia.html | 27 + .../dispositivo_search_fragment_form.html | 48 -- .../layout/dispositivo_checkbox.html | 49 ++ .../layout/dispositivo_checkbox_old.html | 54 ++ .../compilacao/layout/dispositivo_radio.html | 54 ++ templates/compilacao/text_edit.html | 10 +- templates/compilacao/text_edit_bloco.html | 23 +- templates/compilacao/text_list_bloco.html | 4 +- 22 files changed, 1206 insertions(+), 606 deletions(-) create mode 100644 templates/compilacao/dispositivo_form_definidor_vigencia.html create mode 100644 templates/compilacao/dispositivo_form_edicao_basica.html create mode 100644 templates/compilacao/dispositivo_form_search.html create mode 100644 templates/compilacao/dispositivo_form_search_fragment.html create mode 100644 templates/compilacao/dispositivo_form_vigencia.html delete mode 100644 templates/compilacao/dispositivo_search_fragment_form.html create mode 100644 templates/compilacao/layout/dispositivo_checkbox.html create mode 100644 templates/compilacao/layout/dispositivo_checkbox_old.html create mode 100644 templates/compilacao/layout/dispositivo_radio.html diff --git a/compilacao/forms.py b/compilacao/forms.py index 3d81a1622..8b52a4d81 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -1,12 +1,16 @@ +from datetime import datetime + from crispy_forms.bootstrap import FieldWithButtons, FormActions, StrictButton,\ InlineRadios, Alert from crispy_forms.helper import FormHelper from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, Layout, Row) from django import forms -from django.core.exceptions import NON_FIELD_ERRORS +from django.core.exceptions import NON_FIELD_ERRORS, ValidationError +from django.forms.forms import Form from django.forms.models import ModelForm from django.template import defaultfilters +from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from compilacao.models import (NOTAS_PUBLICIDADE_CHOICES, @@ -599,13 +603,78 @@ class DispositivoEdicaoBasicaForm(ModelForm): super(DispositivoEdicaoBasicaForm, self).__init__(*args, **kwargs) -FIELD_NAME_MAPPING = { - 'dispositivo_vigencia': 'dispositivo_ref', -} +class DispositivoSearchModalForm(Form): + + tipo_ta = forms.ModelChoiceField( + label=_('Tipo do Texto Articulado'), + queryset=TipoTextoArticulado.objects.all(), + required=False) + + tipo_model = forms.ChoiceField( + choices=[], + label=_('Tipos de...'), required=False) + + num_ta = forms.IntegerField( + label=_('Número do Documento'), required=False) + ano_ta = forms.IntegerField( + label=_('Ano do Documento'), required=False) + + dispositivos_internos = forms.ChoiceField( + label=_('Incluir Dispositivos Internos?'), + choices=utils.YES_NO_CHOICES, + widget=forms.RadioSelect(), + required=False) + + rotulo_dispositivo = forms.CharField( + label=_('Rótulo'), + required=False) + + texto_dispositivo = forms.CharField( + label=_('Pesquisa Textual'), + required=False) + + def __init__(self, *args, **kwargs): + + fields_search = Fieldset( + _('Busca por um Dispositivo'), + Row( + to_column(('num_ta', 4)), + to_column(('ano_ta', 4)), + to_column((InlineRadios('dispositivos_internos'), 4))), + Row( + to_column(('tipo_ta', 6)), + to_column(('tipo_model', 6))), + Row(to_column(('rotulo_dispositivo', 3)), + to_column((FieldWithButtons( + Field( + 'texto_dispositivo', + placeholder=_('Digite palavras, letras, ' + 'números ou algo' + ' que estejam no texto.')), + StrictButton(_('Buscar'), css_class='btn-busca')), 9))) + ) -class DispositivoEdicaoVigenciaForm(DispositivoSearchFragmentForm): + self.helper = FormHelper() + self.helper.layout = Layout( + fields_search, + Row(to_column((Div(css_class='result-busca-dispositivo'), 12)))) + if 'choice_model_type_foreignkey_in_extenal_views' in kwargs: + ch = kwargs.pop('choice_model_type_foreignkey_in_extenal_views') + if 'data' in kwargs: + choice = ch(kwargs['data']['tipo_ta']) + self.base_fields['tipo_model'].choices = choice + elif 'instance' in kwargs and\ + isinstance(kwargs['instance'], Dispositivo): + choice = ch(kwargs['instance'].ta.tipo_ta_id) + self.base_fields['tipo_model'].choices = choice + + kwargs['initial'].update({'dispositivos_internos': False}) + super(DispositivoSearchModalForm, self).__init__(*args, **kwargs) + + +class DispositivoEdicaoVigenciaForm(ModelForm): inconstitucionalidade = forms.ChoiceField( label=Dispositivo._meta.get_field( 'inconstitucionalidade').verbose_name, @@ -613,9 +682,18 @@ class DispositivoEdicaoVigenciaForm(DispositivoSearchFragmentForm): widget=forms.RadioSelect()) dispositivo_vigencia = forms.ModelChoiceField( + label=Dispositivo._meta.get_field( + 'dispositivo_vigencia').verbose_name, required=False, - queryset=Dispositivo.objects.all(), - widget=forms.HiddenInput()) + queryset=Dispositivo.objects.all()) + + extensao = forms.ChoiceField( + label=_('Extender a seleção abaixo como Dispositivo de Vigência ' + 'para todos dependentes originais ' + 'deste Dispositivo em edição?'), + choices=utils.YES_NO_CHOICES, + widget=forms.RadioSelect(), + required=False) class Meta: model = Dispositivo @@ -628,11 +706,6 @@ class DispositivoEdicaoVigenciaForm(DispositivoSearchFragmentForm): 'dispositivo_vigencia' ] - def add_prefix(self, field_name): - # look up field name; return original if not found - field_name = FIELD_NAME_MAPPING.get(field_name, field_name) - return super(DispositivoEdicaoVigenciaForm, self).add_prefix(field_name) - def __init__(self, *args, **kwargs): layout = [] @@ -646,7 +719,6 @@ class DispositivoEdicaoVigenciaForm(DispositivoSearchFragmentForm): content='%s %s' % ( _('Dica!'), _('Inclua uma Nota de Dispositivo informando ' 'sobre a Inconstitucionalidade.')))) - layout.append( Fieldset(_('Registro de Publicação e Validade'), row_publicacao, @@ -657,24 +729,28 @@ class DispositivoEdicaoVigenciaForm(DispositivoSearchFragmentForm): ('fim_vigencia', 3), ('inicio_eficacia', 3), ('fim_eficacia', 3), ]) - layout.append( Fieldset(_('Datas de Controle de Vigência'), row_datas, css_class="col-md-12")) + row_vigencia = Field( + 'dispositivo_vigencia', + data_sapl_ta='DispositivoSearch', + data_field='dispositivo_vigencia', + data_type_selection='radio', + template="compilacao/layout/dispositivo_radio.html") + layout.append( + Fieldset(_('Dispositivo de Vigência'), + to_row([(InlineRadios('extensao'), 12)]), + row_vigencia, + css_class="col-md-12")) + self.helper = FormHelper() self.helper.layout = SaplFormLayout( + *layout, label_cancel=_('Retornar para o Editor Sequencial')) - self.helper.layout.fields += layout - - kwargs['fields_search'] = fields_search = Div() - self.helper.layout.fields.append( - Fieldset(_('Dispositivo de Vigência'), - fields_search, - css_class="col-md-12 dispositivo_vigencia_busca")) - super(DispositivoEdicaoVigenciaForm, self).__init__(*args, **kwargs) pubs = Publicacao.objects.order_by( @@ -684,3 +760,112 @@ class DispositivoEdicaoVigenciaForm(DispositivoSearchFragmentForm): p.tipo_publicacao, defaultfilters.date( p.data, "d \d\e F \d\e Y"))) for p in pubs] + + dvs = Dispositivo.objects.order_by('ordem').filter( + pk=self.instance.dispositivo_vigencia_id) + self.fields['dispositivo_vigencia'].choices = [(d.pk, d) for d in dvs] + + def save(self): + super(DispositivoEdicaoVigenciaForm, self).save() + + data = self.cleaned_data + + extensao = 'extensao' in data and data['extensao'] == 'True' + + if extensao: + dv = data['dispositivo_vigencia'] + dv_pk = dv.pk if dv else None + instance = self.instance + + def extenderPara(dpt_pk): + + Dispositivo.objects.filter( + dispositivo_pai_id=dpt_pk, + ta_publicado__isnull=True).update( + dispositivo_vigencia_id=dv_pk) + + filhos = Dispositivo.objects.filter( + dispositivo_pai_id=dpt_pk).values_list('pk', flat=True) + + for d in filhos: + extenderPara(d) + + extenderPara(instance.pk) + + +class MultipleChoiceWithoutValidationField(forms.MultipleChoiceField): + + def validate(self, value): + if self.required and not value: + raise ValidationError( + self.error_messages['required'], code='required') + + +class DispositivoDefinidorVigenciaForm(Form): + + dispositivo_vigencia = MultipleChoiceWithoutValidationField( + label=Dispositivo._meta.get_field( + 'dispositivo_vigencia').verbose_name, + required=False) + + def __init__(self, *args, **kwargs): + + layout = [] + + row_vigencia = Field( + 'dispositivo_vigencia', + data_sapl_ta='DispositivoSearch', + data_field='dispositivo_vigencia', + data_type_selection='checkbox', + template="compilacao/layout/dispositivo_checkbox.html") + layout.append( + Fieldset(_('Definidor de Vigência dos Dispositívos abaixo'), + row_vigencia, + css_class="col-md-12")) + + self.helper = FormHelper() + self.helper.layout = SaplFormLayout( + *layout, + label_cancel=_('Retornar para o Editor Sequencial')) + + pk = kwargs.pop('pk') + super(DispositivoDefinidorVigenciaForm, self).__init__(*args, **kwargs) + + dvs = Dispositivo.objects.order_by('ta', 'ordem').filter( + dispositivo_vigencia_id=pk).select_related( + 'tipo_dispositivo', + 'ta_publicado', + 'ta', + 'dispositivo_atualizador', + 'dispositivo_atualizador__dispositivo_pai', + 'dispositivo_atualizador__dispositivo_pai__ta', + 'dispositivo_atualizador__dispositivo_pai__ta__tipo_ta', + 'dispositivo_pai', + 'dispositivo_pai__tipo_dispositivo', + 'ta_publicado', + 'ta',) + self.initial['dispositivo_vigencia'] = [d.pk for d in dvs] + + tas = Dispositivo.objects.filter( + dispositivo_vigencia_id=pk).values_list('ta', 'ta_publicado') + + tas = list(set().union(*list(map(list, zip(*tas))))) + + if not tas: + tas = Dispositivo.objects.filter(pk=pk).values_list('ta_id') + + dvs = Dispositivo.objects.order_by('-ta__data', '-ta__ano', '-ta__numero', 'ta', 'ordem').filter( + ta__in=tas).select_related( + 'tipo_dispositivo', + 'ta_publicado', + 'ta', + 'dispositivo_atualizador', + 'dispositivo_atualizador__dispositivo_pai', + 'dispositivo_atualizador__dispositivo_pai__ta', + 'dispositivo_atualizador__dispositivo_pai__ta__tipo_ta', + 'dispositivo_pai', + 'dispositivo_pai__tipo_dispositivo', + 'ta_publicado', + 'ta',) + self.fields['dispositivo_vigencia'].choices = [ + (d.pk, d) for d in dvs] diff --git a/compilacao/models.py b/compilacao/models.py index 847e2f7ff..96961f673 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -627,7 +627,7 @@ class Dispositivo(BaseModel, TimestampedMixin): dispositivo_vigencia = models.ForeignKey( 'self', blank=True, null=True, default=None, - related_name='+', + related_name='dispositivos_vigencias_set', verbose_name=_('Dispositivo de Vigência')) dispositivo_atualizador = models.ForeignKey( 'self', @@ -752,6 +752,8 @@ class Dispositivo(BaseModel, TimestampedMixin): r += prefixo[0] r += self.get_nomenclatura_completa() else: + if self.dispositivo0 == 0: + self.dispositivo0 = 1 r += prefixo[0] r += self.get_nomenclatura_completa() @@ -1150,10 +1152,20 @@ class Dispositivo(BaseModel, TimestampedMixin): dp.texto = '' dp.ta = dispositivo_base.ta dp.dispositivo_pai = dispositivo_base.dispositivo_pai - dp.inicio_eficacia = dispositivo_base.inicio_eficacia - dp.inicio_vigencia = dispositivo_base.inicio_vigencia dp.publicacao = dispositivo_base.publicacao - dp.timestamp = datetime.now() + + dp.dispositivo_vigencia = dispositivo_base.dispositivo_vigencia + if dp.dispositivo_vigencia: + dp.inicio_eficacia = dp.dispositivo_vigencia.inicio_eficacia + dp.inicio_vigencia = dp.dispositivo_vigencia.inicio_vigencia + dp.fim_eficacia = dp.dispositivo_vigencia.fim_eficacia + dp.fim_vigencia = dp.dispositivo_vigencia.fim_vigencia + else: + dp.inicio_eficacia = dispositivo_base.inicio_eficacia + dp.inicio_vigencia = dispositivo_base.inicio_vigencia + dp.fim_eficacia = dispositivo_base.inicio_eficacia + dp.fim_vigencia = dispositivo_base.fim_vigencia + dp.ordem = dispositivo_base.ordem return dp diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index 6aab329a5..2ee09593b 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -16,13 +16,6 @@ def get_bloco_atualizador(pk_atualizador): Q(dispositivo_atualizador_id=pk_atualizador)).select_related() -@register.filter -def get_tipos_dispositivo(pk_atual): - - return TipoDispositivo.objects.filter( - id__gte=pk_atual) - - @register.simple_tag def dispositivo_desativado(dispositivo, inicio_vigencia, fim_vigencia): if inicio_vigencia and fim_vigencia: @@ -39,17 +32,23 @@ def dispositivo_desativado(dispositivo, inicio_vigencia, fim_vigencia): @register.simple_tag def nota_automatica(dispositivo, ta_pub_list): + if dispositivo.ta_publicado is not None: d = dispositivo.dispositivo_atualizador.dispositivo_pai + + ta_publicado = ta_pub_list[dispositivo.ta_publicado_id] if\ + ta_pub_list else dispositivo.ta_publicado + if dispositivo.texto == Dispositivo.TEXTO_PADRAO_DISPOSITIVO_REVOGADO: return _('Revogado pelo %s - %s.') % ( - d, ta_pub_list[dispositivo.ta_publicado_id]) + d, ta_publicado) elif not dispositivo.dispositivo_substituido_id: return _('Inclusão feita pelo %s - %s.') % ( - d, ta_pub_list[dispositivo.ta_publicado_id]) + d, ta_publicado) else: return _('Alteração feita pelo %s - %s.') % ( - d, ta_pub_list[dispositivo.ta_publicado_id]) + d, ta_publicado) + return '' @@ -125,8 +124,10 @@ def nomenclatura(d): result = '(' + d.tipo_dispositivo.nome + ' ' + \ d.rotulo + ')' else: - result = '(' + d.tipo_dispositivo.nome + ' ' + \ - d.rotulo_padrao() + ')' + r = d.rotulo_padrao() + if r: + r += ' ' + result = '(' + d.tipo_dispositivo.nome + r + ')' return result @@ -159,3 +160,8 @@ def nomenclatura_heranca(d, ignore_ultimo=0, ignore_primeiro=0): @register.filter def urldetail_content_type(obj): return '%s:detail' % obj.content_type.model + + +@register.filter +def list(obj): + return [obj, ] diff --git a/compilacao/urls.py b/compilacao/urls.py index bc5d22754..1a2262c02 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -40,13 +40,13 @@ urlpatterns_compilacao = [ views.DispositivoEdicaoVigenciaView.as_view(), name='dispositivo_edit_vigencia'), - + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit/definidor_vigencia', + views.DispositivoDefinidorVigenciaView.as_view(), + name='dispositivo_edit_definidor_vigencia'), 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'), @@ -75,6 +75,10 @@ urlpatterns_compilacao = [ views.DispositivoSearchFragmentFormView.as_view(), name='dispositivo_fragment_form'), + url(r'^search_form$', + views.DispositivoSearchModalView.as_view(), + name='dispositivo_search_form'), + url(r'^(?P[0-9]+)/publicacao$', views.PublicacaoListView.as_view(), name='ta_pub_list'), diff --git a/compilacao/views.py b/compilacao/views.py index 82dceebbf..1e6c901f4 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -19,12 +19,15 @@ from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import TemplateView from django.views.generic.detail import DetailView -from django.views.generic.edit import CreateView, DeleteView, UpdateView +from django.views.generic.edit import CreateView, DeleteView, UpdateView,\ + FormView from django.views.generic.list import ListView from compilacao.forms import (DispositivoEdicaoBasicaForm, NotaForm, PublicacaoForm, TaForm, TipoTaForm, VideForm, - DispositivoEdicaoVigenciaForm) + DispositivoEdicaoVigenciaForm, + DispositivoSearchModalForm, + DispositivoDefinidorVigenciaForm) from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, Publicacao, TextoArticulado, TipoDispositivo, TipoNota, @@ -317,6 +320,266 @@ class TaDeleteView(CompMixin, DeleteView): return reverse_lazy('compilacao:ta_list') +class DispositivoSuccessUrlMixin: + + def get_success_url(self): + return reverse_lazy( + 'compilacao:dispositivo', kwargs={ + 'ta_id': self.kwargs[ + 'ta_id'], + 'dispositivo_id': self.kwargs[ + 'dispositivo_id']}) + + +class NotaMixin(DispositivoSuccessUrlMixin): + + def get_modelo_nota(self, request): + if 'action' in request.GET and request.GET['action'] == 'modelo_nota': + tn = TipoNota.objects.get(pk=request.GET['id_tipo']) + return True, tn.modelo + return False, '' + + def get_initial(self): + dispositivo = get_object_or_404( + Dispositivo, pk=self.kwargs.get('dispositivo_id')) + initial = {'dispositivo': dispositivo} + + if 'pk' in self.kwargs: + initial['pk'] = self.kwargs.get('pk') + + return initial + + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(NotaMixin, self).dispatch(*args, **kwargs) + + +class NotasCreateView(NotaMixin, CreateView): + template_name = 'compilacao/ajax_form.html' + form_class = NotaForm + + def get(self, request, *args, **kwargs): + flag_action, modelo_nota = self.get_modelo_nota(request) + if flag_action: + return HttpResponse(modelo_nota) + + return super(NotasCreateView, self).get(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + self.object = None + try: + ta_id = kwargs.pop('ta_id') + dispositivo_id = kwargs.pop('dispositivo_id') + form = NotaForm(request.POST, request.FILES, **kwargs) + kwargs['ta_id'] = ta_id + kwargs['dispositivo_id'] = dispositivo_id + + if form.is_valid(): + nt = form.save(commit=False) + nt.owner_id = request.user.pk + nt.save() + self.kwargs['pk'] = nt.pk + return self.form_valid(form) + else: + return self.form_invalid(form) + except Exception as e: + print(e) + return HttpResponse("error post") + + +class NotasEditView(NotaMixin, UpdateView): + model = Nota + template_name = 'compilacao/ajax_form.html' + form_class = NotaForm + + def get(self, request, *args, **kwargs): + flag_action, modelo_nota = self.get_modelo_nota(request) + if flag_action: + return HttpResponse(modelo_nota) + + return super(NotasEditView, self).get(request, *args, **kwargs) + + +class NotasDeleteView(NotaMixin, TemplateView): + + def get(self, request, *args, **kwargs): + nt = Nota.objects.get(pk=self.kwargs['pk']) + nt.delete() + return HttpResponseRedirect(self.get_success_url()) + + +class VideMixin(DispositivoSuccessUrlMixin): + + def get_initial(self): + dispositivo_base = get_object_or_404( + Dispositivo, pk=self.kwargs.get('dispositivo_id')) + + initial = {'dispositivo_base': dispositivo_base} + + if 'pk' in self.kwargs: + initial['pk'] = self.kwargs.get('pk') + + return initial + + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(VideMixin, self).dispatch(*args, **kwargs) + + +def choice_model_type_foreignkey_in_extenal_views(id_tipo_ta=None): + yield None, '-------------' + + if not id_tipo_ta: + return + + tipo_ta = TipoTextoArticulado.objects.get(pk=id_tipo_ta) + + integrations_view_names = get_integrations_view_names() + for item in integrations_view_names: + if hasattr(item, 'model_type_foreignkey'): + if (tipo_ta.content_type.model == item.model.__name__.lower() and + tipo_ta.content_type.app_label == + item.model._meta.app_label): + for i in item.model_type_foreignkey.objects.all(): + yield i.pk, i + + +class VideCreateView(VideMixin, CreateView): + model = Vide + template_name = 'compilacao/ajax_form.html' + form_class = VideForm + + def get(self, request, *args, **kwargs): + self.object = None + form = self.get_form() + return self.render_to_response(self.get_context_data(form=form)) + + def get_form_kwargs(self): + + kwargs = super(VideCreateView, self).get_form_kwargs() + + if 'choice_model_type_foreignkey_in_extenal_views' not in kwargs: + kwargs.update({ + 'choice_model_type_foreignkey_in_extenal_views': + choice_model_type_foreignkey_in_extenal_views + }) + + return kwargs + + +class VideEditView(VideMixin, UpdateView): + model = Vide + template_name = 'compilacao/ajax_form.html' + form_class = VideForm + + +class VideDeleteView(VideMixin, TemplateView): + + def get(self, request, *args, **kwargs): + vd = Vide.objects.get(pk=self.kwargs['pk']) + vd.delete() + return HttpResponseRedirect(self.get_success_url()) + + +class PublicacaoListView(ListView): + model = Publicacao + verbose_name = model._meta.verbose_name + + @property + def title(self): + return _('%s de %s' % ( + self.model._meta.verbose_name_plural, + self.ta)) + + @property + def ta(self): + ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) + return ta + + @property + def create_url(self): + return reverse_lazy( + 'compilacao:ta_pub_create', + kwargs={'ta_id': self.kwargs['ta_id']}) + + def get_queryset(self): + pubs = Publicacao.objects.filter(ta_id=self.kwargs['ta_id']) + return pubs + + def get_context_data(self, **kwargs): + context = super(PublicacaoListView, self).get_context_data(**kwargs) + context['NO_ENTRIES_MSG'] = CrudListView.no_entries_msg + return context + + +class PublicacaoCreateView(FormMessagesMixin, CreateView): + model = Publicacao + form_class = PublicacaoForm + template_name = "crud/form.html" + form_valid_message = _('Registro criado com sucesso!') + form_invalid_message = _('O registro não foi criado.') + + def get_success_url(self): + return reverse_lazy( + 'compilacao:ta_pub_detail', + kwargs={ + 'pk': self.object.id, + 'ta_id': self.kwargs['ta_id']}) + + @property + def cancel_url(self): + return reverse_lazy( + 'compilacao:ta_pub_list', + kwargs={'ta_id': self.kwargs['ta_id']}) + + def get_initial(self): + return {'ta': self.kwargs['ta_id']} + + +class PublicacaoDetailView(CompMixin, DetailView): + model = Publicacao + + +class PublicacaoUpdateView(CompMixin, UpdateView): + model = Publicacao + form_class = PublicacaoForm + template_name = "crud/form.html" + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + form = self.get_form() + # if self.object and self.object.content_object: + # form.fields['tipo_ta'].required = False + # form.fields['tipo_ta'].widget.attrs['disabled'] = 'disabled' + return self.render_to_response(self.get_context_data(form=form)) + + def get_success_url(self): + return reverse_lazy('compilacao:ta_pub_detail', + kwargs={ + 'pk': self.object.id, + 'ta_id': self.kwargs['ta_id']}) + + @property + def cancel_url(self): + return self.get_success_url() + + +class PublicacaoDeleteView(CompMixin, DeleteView): + model = Publicacao + template_name = "crud/confirm_delete.html" + + @property + def detail_url(self): + return reverse_lazy('compilacao:ta_pub_detail', + kwargs={ + 'pk': self.object.id, + 'ta_id': self.kwargs['ta_id']}) + + def get_success_url(self): + return reverse_lazy('compilacao:ta_pub_list', + kwargs={'ta_id': self.kwargs['ta_id']}) + + class TextView(ListView, CompMixin): template_name = 'compilacao/text_list.html' @@ -617,7 +880,6 @@ class TextEditView(ListView, CompMixin): a.tipo_dispositivo = td a.inicio_vigencia = ta.data a.inicio_eficacia = ta.data - a.timestamp = datetime.now() a.save() td = TipoDispositivo.objects.filter(class_css='ementa')[0] @@ -630,7 +892,6 @@ class TextEditView(ListView, CompMixin): e.tipo_dispositivo = td e.inicio_vigencia = ta.data e.inicio_eficacia = ta.data - e.timestamp = datetime.now() e.texto = ta.ementa e.dispositivo_pai = a e.save() @@ -640,7 +901,6 @@ class TextEditView(ListView, CompMixin): 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( @@ -1018,6 +1278,7 @@ class ActionsEditMixin: return JsonResponse(action(context), safe=False) def set_dvt(self, context): + # Dispositivo de Vigência do Texto Original e de Dpts Alterados dvt = Dispositivo.objects.get(pk=context['dispositivo_id']) if dvt.is_relative_auto_insert(): @@ -1025,15 +1286,28 @@ class ActionsEditMixin: try: Dispositivo.objects.filter( - ta=dvt.ta, - ta_publicado__isnull=True).update( - dispositivo_vigencia=dvt, - inicio_vigencia=dvt.inicio_vigencia) - - Dispositivo.objects.filter( - ta_publicado=dvt.ta).update( + (Q(ta=dvt.ta) & Q(ta_publicado__isnull=True)) | + Q(ta_publicado=dvt.ta) + ).update( dispositivo_vigencia=dvt, - inicio_vigencia=dvt.inicio_vigencia) + inicio_vigencia=dvt.inicio_vigencia, + inicio_eficacia=dvt.inicio_eficacia) + + dps = Dispositivo.objects.filter(dispositivo_vigencia_id=dvt.pk, + ta_publicado_id=dvt.ta_id) + + for d in dps: + if d.dispositivo_substituido: + ds = d.dispositivo_substituido + ds.fim_vigencia = d.inicio_vigencia - timedelta(days=1) + ds.fim_eficacia = d.inicio_eficacia - timedelta(days=1) + ds.save() + + if d.dispositivo_subsequente: + ds = d.dispositivo_subsequente + d.fim_vigencia = ds.inicio_vigencia - timedelta(days=1) + d.fim_eficacia = ds.inicio_eficacia - timedelta(days=1) + d.save() return {'message': str(_('Dispositivo de Vigência atualizado ' 'com sucesso!!!'))} @@ -1723,172 +1997,80 @@ class ActionsEditView(ActionsEditMixin, TemplateView): return self.render_to_json_response(context, **response_kwargs) -class DispositivoSuccessUrlMixin: +class DispositivoEdicaoBasicaView(FormMessagesMixin, UpdateView): + model = Dispositivo + template_name = 'compilacao/dispositivo_form_edicao_basica.html' + form_class = DispositivoEdicaoBasicaForm + form_valid_message = _('Alterações no Dispositivo realizadas com sucesso!') + form_invalid_message = _('Houve erro em registrar ' + 'as alterações no Dispositivo') - def get_success_url(self): + @property + def cancel_url(self): return reverse_lazy( - 'compilacao:dispositivo', kwargs={ - 'ta_id': self.kwargs[ - 'ta_id'], - 'dispositivo_id': self.kwargs[ - 'dispositivo_id']}) - - -class NotaMixin(DispositivoSuccessUrlMixin): - - def get_modelo_nota(self, request): - if 'action' in request.GET and request.GET['action'] == 'modelo_nota': - tn = TipoNota.objects.get(pk=request.GET['id_tipo']) - return True, tn.modelo - return False, '' - - def get_initial(self): - dispositivo = get_object_or_404( - Dispositivo, pk=self.kwargs.get('dispositivo_id')) - initial = {'dispositivo': dispositivo} - - if 'pk' in self.kwargs: - initial['pk'] = self.kwargs.get('pk') - - return initial - - @method_decorator(login_required) - def dispatch(self, *args, **kwargs): - return super(NotaMixin, self).dispatch(*args, **kwargs) - - -class NotasCreateView(NotaMixin, CreateView): - template_name = 'compilacao/ajax_form.html' - form_class = NotaForm - - def get(self, request, *args, **kwargs): - flag_action, modelo_nota = self.get_modelo_nota(request) - if flag_action: - return HttpResponse(modelo_nota) - - return super(NotasCreateView, self).get(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - self.object = None - try: - ta_id = kwargs.pop('ta_id') - dispositivo_id = kwargs.pop('dispositivo_id') - form = NotaForm(request.POST, request.FILES, **kwargs) - kwargs['ta_id'] = ta_id - kwargs['dispositivo_id'] = dispositivo_id - - if form.is_valid(): - nt = form.save(commit=False) - nt.owner_id = request.user.pk - nt.save() - self.kwargs['pk'] = nt.pk - return self.form_valid(form) - else: - return self.form_invalid(form) - except Exception as e: - print(e) - return HttpResponse("error post") - - -class NotasEditView(NotaMixin, UpdateView): - model = Nota - template_name = 'compilacao/ajax_form.html' - form_class = NotaForm - - def get(self, request, *args, **kwargs): - flag_action, modelo_nota = self.get_modelo_nota(request) - if flag_action: - return HttpResponse(modelo_nota) - - return super(NotasEditView, self).get(request, *args, **kwargs) - - -class NotasDeleteView(NotaMixin, TemplateView): - - def get(self, request, *args, **kwargs): - nt = Nota.objects.get(pk=self.kwargs['pk']) - nt.delete() - return HttpResponseRedirect(self.get_success_url()) - - -class VideMixin(DispositivoSuccessUrlMixin): - - def get_initial(self): - dispositivo_base = get_object_or_404( - Dispositivo, pk=self.kwargs.get('dispositivo_id')) - - initial = {'dispositivo_base': dispositivo_base} - - if 'pk' in self.kwargs: - initial['pk'] = self.kwargs.get('pk') - - return initial - - @method_decorator(login_required) - def dispatch(self, *args, **kwargs): - return super(VideMixin, self).dispatch(*args, **kwargs) - - -def choice_model_type_foreignkey_in_extenal_views(id_tipo_ta=None): - yield None, '-------------' - - if not id_tipo_ta: - return - - tipo_ta = TipoTextoArticulado.objects.get(pk=id_tipo_ta) - - integrations_view_names = get_integrations_view_names() - for item in integrations_view_names: - if hasattr(item, 'model_type_foreignkey'): - if (tipo_ta.content_type.model == item.model.__name__.lower() and - tipo_ta.content_type.app_label == - item.model._meta.app_label): - for i in item.model_type_foreignkey.objects.all(): - yield i.pk, i - - -class DispositivoSearchMixin: + 'compilacao:ta_text_edit', + kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) - def get_form_kwargs(self): + def get_success_url(self): + return reverse_lazy( + 'compilacao:dispositivo_edit', + kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) - kwargs = super(DispositivoSearchMixin, self).get_form_kwargs() + def get_url_this_view(self): + return 'compilacao:dispositivo_edit' - if 'choice_model_type_foreignkey_in_extenal_views' not in kwargs: - kwargs.update({ - 'choice_model_type_foreignkey_in_extenal_views': - choice_model_type_foreignkey_in_extenal_views - }) + def run_actions(self, request): + if 'action' in request.GET and\ + request.GET['action'] == 'atualiza_rotulo': + try: + d = Dispositivo.objects.get(pk=self.kwargs['pk']) + d.dispositivo0 = int(request.GET['dispositivo0']) + d.dispositivo1 = int(request.GET['dispositivo1']) + d.dispositivo2 = int(request.GET['dispositivo2']) + d.dispositivo3 = int(request.GET['dispositivo3']) + d.dispositivo4 = int(request.GET['dispositivo4']) + d.dispositivo5 = int(request.GET['dispositivo5']) + d.rotulo = d.rotulo_padrao() - return kwargs + numero = d.get_numero_completo()[1:] + zerar = False + for i in range(len(numero)): + if not numero[i]: + zerar = True -class VideCreateView(VideMixin, DispositivoSearchMixin, CreateView): - model = Vide - template_name = 'compilacao/ajax_form.html' - form_class = VideForm + if zerar: + numero[i] = 0 - def get(self, request, *args, **kwargs): - self.object = None - form = self.get_form() - return self.render_to_response(self.get_context_data(form=form)) + if zerar: + d.set_numero_completo([d.dispositivo0, ] + numero) + d.rotulo = d.rotulo_padrao() + except: + return True, JsonResponse({'message': str( + _('Ocorreu erro na atualização do rótulo'))}, safe=False) + return True, JsonResponse({ + 'rotulo': d.rotulo, + 'dispositivo0': d.dispositivo0, + 'dispositivo1': d.dispositivo1, + 'dispositivo2': d.dispositivo2, + 'dispositivo3': d.dispositivo3, + 'dispositivo4': d.dispositivo4, + 'dispositivo5': d.dispositivo5}, safe=False) -class VideEditView(VideMixin, UpdateView): - model = Vide - template_name = 'compilacao/ajax_form.html' - form_class = VideForm + return False, '' + def get(self, request, *args, **kwargs): -class VideDeleteView(VideMixin, TemplateView): + flag_action, render_json_response = self.run_actions(request) + if flag_action: + return render_json_response - def get(self, request, *args, **kwargs): - vd = Vide.objects.get(pk=self.kwargs['pk']) - vd.delete() - return HttpResponseRedirect(self.get_success_url()) + return UpdateView.get(self, request, *args, **kwargs) class DispositivoSearchFragmentFormView(ListView): - template_name = 'compilacao/dispositivo_search_fragment_form.html' + template_name = 'compilacao/dispositivo_form_search_fragment.html' def get(self, request, *args, **kwargs): @@ -1908,16 +2090,18 @@ class DispositivoSearchFragmentFormView(ListView): def get_queryset(self): try: + n = 10 + q = Q(nivel__gt=0) if 'initial_ref' in self.request.GET: initial_ref = self.request.GET['initial_ref'] if initial_ref: - q = Q(pk=initial_ref) + q = q & Q(pk=initial_ref) result = Dispositivo.objects.filter(q).select_related( 'ta').exclude( tipo_dispositivo__dispositivo_de_alteracao=True) - return result + return result[:n] texto = '' rotulo = '' @@ -1925,9 +2109,7 @@ class DispositivoSearchFragmentFormView(ListView): if 'texto' in self.request.GET: texto = self.request.GET['texto'] - q = Q(nivel__gt=0) texto = texto.split(' ') - n = 10 if 'rotulo' in self.request.GET: rotulo = self.request.GET['rotulo'] @@ -2023,220 +2205,84 @@ class DispositivoSearchFragmentFormView(ListView): print(e) -class PublicacaoListView(ListView): - model = Publicacao - verbose_name = model._meta.verbose_name - - @property - def title(self): - return _('%s de %s' % ( - self.model._meta.verbose_name_plural, - self.ta)) - - @property - def ta(self): - ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) - return ta - - @property - def create_url(self): - return reverse_lazy( - 'compilacao:ta_pub_create', - kwargs={'ta_id': self.kwargs['ta_id']}) - - def get_queryset(self): - pubs = Publicacao.objects.filter(ta_id=self.kwargs['ta_id']) - return pubs - - def get_context_data(self, **kwargs): - context = super(PublicacaoListView, self).get_context_data(**kwargs) - context['NO_ENTRIES_MSG'] = CrudListView.no_entries_msg - return context - +class DispositivoSearchModalView(FormView): + template_name = 'compilacao/dispositivo_form_search.html' + form_class = DispositivoSearchModalForm -class PublicacaoCreateView(FormMessagesMixin, CreateView): - model = Publicacao - form_class = PublicacaoForm - template_name = "crud/form.html" - form_valid_message = _('Registro criado com sucesso!') - form_invalid_message = _('O registro não foi criado.') - def get_success_url(self): - return reverse_lazy( - 'compilacao:ta_pub_detail', - kwargs={ - 'pk': self.object.id, - 'ta_id': self.kwargs['ta_id']}) +class DispositivoEdicaoVigenciaView(FormMessagesMixin, UpdateView): + model = Dispositivo + template_name = 'compilacao/dispositivo_form_vigencia.html' + form_class = DispositivoEdicaoVigenciaForm + form_valid_message = _('Alterações no Dispositivo realizadas com sucesso!') + form_invalid_message = _('Houve erro em registrar ' + 'as alterações no Dispositivo') @property def cancel_url(self): return reverse_lazy( - 'compilacao:ta_pub_list', - kwargs={'ta_id': self.kwargs['ta_id']}) - - def get_initial(self): - return {'ta': self.kwargs['ta_id']} - - -class PublicacaoDetailView(CompMixin, DetailView): - model = Publicacao - - -class PublicacaoUpdateView(CompMixin, UpdateView): - model = Publicacao - form_class = PublicacaoForm - template_name = "crud/form.html" - - def get(self, request, *args, **kwargs): - self.object = self.get_object() - form = self.get_form() - # if self.object and self.object.content_object: - # form.fields['tipo_ta'].required = False - # form.fields['tipo_ta'].widget.attrs['disabled'] = 'disabled' - return self.render_to_response(self.get_context_data(form=form)) - - def get_success_url(self): - return reverse_lazy('compilacao:ta_pub_detail', - kwargs={ - 'pk': self.object.id, - 'ta_id': self.kwargs['ta_id']}) - - @property - def cancel_url(self): - return self.get_success_url() - - -class PublicacaoDeleteView(CompMixin, DeleteView): - model = Publicacao - template_name = "crud/confirm_delete.html" + 'compilacao:ta_text_edit', + kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) - @property - def detail_url(self): - return reverse_lazy('compilacao:ta_pub_detail', - kwargs={ - 'pk': self.object.id, - 'ta_id': self.kwargs['ta_id']}) + def get_url_this_view(self): + return 'compilacao:dispositivo_edit_vigencia' def get_success_url(self): - return reverse_lazy('compilacao:ta_pub_list', - kwargs={'ta_id': self.kwargs['ta_id']}) + return reverse_lazy( + 'compilacao:dispositivo_edit_vigencia', + kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) -class DispositivoEdicaoBasicaView(FormMessagesMixin, UpdateView): +class DispositivoDefinidorVigenciaView(FormMessagesMixin, FormView): model = Dispositivo - form_class = DispositivoEdicaoBasicaForm + template_name = 'compilacao/dispositivo_form_definidor_vigencia.html' + form_class = DispositivoDefinidorVigenciaForm form_valid_message = _('Alterações no Dispositivo realizadas com sucesso!') form_invalid_message = _('Houve erro em registrar ' 'as alterações no Dispositivo') + def get_form_kwargs(self): + kwargs = FormView.get_form_kwargs(self) + kwargs.update({ + 'pk': self.kwargs['pk'], + }) + return kwargs + @property def cancel_url(self): return reverse_lazy( 'compilacao:ta_text_edit', kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) - def get_success_url(self): - return reverse_lazy( - 'compilacao:dispositivo_edit', - kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) - - def get_url_this_view(self): - return 'compilacao:dispositivo_edit' - - def run_actions(self, request): - if 'action' in request.GET and\ - request.GET['action'] == 'atualiza_rotulo': - try: - d = Dispositivo.objects.get(pk=self.kwargs['pk']) - d.dispositivo0 = int(request.GET['dispositivo0']) - d.dispositivo1 = int(request.GET['dispositivo1']) - d.dispositivo2 = int(request.GET['dispositivo2']) - d.dispositivo3 = int(request.GET['dispositivo3']) - d.dispositivo4 = int(request.GET['dispositivo4']) - d.dispositivo5 = int(request.GET['dispositivo5']) - d.rotulo = d.rotulo_padrao() - - numero = d.get_numero_completo()[1:] - - zerar = False - for i in range(len(numero)): - if not numero[i]: - zerar = True - - if zerar: - numero[i] = 0 - - if zerar: - d.set_numero_completo([d.dispositivo0, ] + numero) - d.rotulo = d.rotulo_padrao() - - except: - return True, JsonResponse({'message': str( - _('Ocorreu erro na atualização do rótulo'))}, safe=False) - return True, JsonResponse({ - 'rotulo': d.rotulo, - 'dispositivo0': d.dispositivo0, - 'dispositivo1': d.dispositivo1, - 'dispositivo2': d.dispositivo2, - 'dispositivo3': d.dispositivo3, - 'dispositivo4': d.dispositivo4, - 'dispositivo5': d.dispositivo5}, safe=False) - - return False, '' - - def get(self, request, *args, **kwargs): - - flag_action, render_json_response = self.run_actions(request) - if flag_action: - return render_json_response - - return UpdateView.get(self, request, *args, **kwargs) - - -class DispositivoEdicaoVigenciaView( - DispositivoSearchMixin, DispositivoEdicaoBasicaView): - model = Dispositivo - form_class = DispositivoEdicaoVigenciaForm - def get_url_this_view(self): - return 'compilacao:dispositivo_edit_vigencia' + return 'compilacao:dispositivo_edit_definidor_vigencia' def get_success_url(self): return reverse_lazy( - 'compilacao:dispositivo_edit_vigencia', + 'compilacao:dispositivo_edit_definidor_vigencia', kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) - def run_actions(self, request): - if 'action' in request.GET and\ - request.GET['action'] == 'atualiza_rotulo': - try: - pass - except: - return True, JsonResponse({'message': str( - _('Ocorreu erro na atualização do rótulo'))}, safe=False) - return True, JsonResponse({}, safe=False) - return False, '' - - def get_initial(self): - - ta = self.object.ta_publicado if self.object.ta_publicado else\ - self.object.ta + def get(self, request, *args, **kwargs): + self.object = get_object_or_404(Dispositivo, pk=kwargs['pk']) + return FormView.get(self, request, *args, **kwargs) - initial = { - 'ano_ta': ta.ano, - 'num_ta': ta.numero, - 'tipo_ta': ta.tipo_ta, - } - if hasattr(ta, 'content_object') and\ - ta.content_object: - lista_tipos = list(choice_model_type_foreignkey_in_extenal_views( - id_tipo_ta=ta.tipo_ta_id)) + def get_context_data(self, **kwargs): + context = FormView.get_context_data(self, **kwargs) + context.update({'object': self.object}) + return context - content_object = model_to_dict(ta.content_object) + def post(self, request, *args, **kwargs): + self.object = get_object_or_404(Dispositivo, pk=kwargs['pk']) - for key, value in content_object.items(): - for item in lista_tipos: - if getattr(ta.content_object, key) == item[1]: - initial['tipo_model'] = item[0] + form = self.get_form() + if form.is_valid(): + dvs = form.cleaned_data['dispositivo_vigencia'] + with transaction.atomic(): + self.object.dispositivos_vigencias_set.clear() + for item in dvs: + d = Dispositivo.objects.get(pk=item) + self.object.dispositivos_vigencias_set.add(d) - return initial + return self.form_valid(form) + else: + return self.form_invalid(form) diff --git a/static/js/compilacao.js b/static/js/compilacao.js index b6d2242f4..0a7f2aa3a 100644 --- a/static/js/compilacao.js +++ b/static/js/compilacao.js @@ -34,18 +34,14 @@ var configFormSearchTA = function(container, _tipo_form, _tipo_select) { $(container+" select[name='tipo_ta']").change(function(event) { var url = ''; url = '/ta/search_fragment_form?action=get_tipos&tipo_ta='+this.value; - $(container+" label[for='id_tipo_model']").html('Tipos de ' + this.children[this.selectedIndex].innerHTML); - var select = $(container+" select[name='tipo_model']"); select.empty(); $('').appendTo(select); $.get(url).done(function( data ) { select.empty(); - - for(var item in data) { for (var i in data[item]) select.append($("
    diff --git a/templates/compilacao/dispositivo_form_search.html b/templates/compilacao/dispositivo_form_search.html new file mode 100644 index 000000000..4a7732446 --- /dev/null +++ b/templates/compilacao/dispositivo_form_search.html @@ -0,0 +1,19 @@ +{% load i18n crispy_forms_tags %} + + diff --git a/templates/compilacao/dispositivo_form_search_fragment.html b/templates/compilacao/dispositivo_form_search_fragment.html new file mode 100644 index 000000000..f32a89482 --- /dev/null +++ b/templates/compilacao/dispositivo_form_search_fragment.html @@ -0,0 +1,75 @@ +{% load i18n compilacao_filters %} + +{% if object_list.count >= 100 %} +
    + {% trans 'Use argumentos para simplificar listagem...' %} +
    +{% endif %} + +{% for dpt in object_list %} + {% ifchanged dpt.ta%} + {% if not forloop.first %}{% endif %} + {% endif %} +{% endfor %} diff --git a/templates/compilacao/dispositivo_form_vigencia.html b/templates/compilacao/dispositivo_form_vigencia.html new file mode 100644 index 000000000..73ac5d95d --- /dev/null +++ b/templates/compilacao/dispositivo_form_vigencia.html @@ -0,0 +1,27 @@ +{% extends "compilacao/dispositivo_form.html" %} +{% load i18n %} +{% block extra_js %}{{block.super}} + +{% endblock %} diff --git a/templates/compilacao/dispositivo_search_fragment_form.html b/templates/compilacao/dispositivo_search_fragment_form.html deleted file mode 100644 index 501233d09..000000000 --- a/templates/compilacao/dispositivo_search_fragment_form.html +++ /dev/null @@ -1,48 +0,0 @@ -{% load i18n %} -{% load compilacao_filters %} - -{% if object_list.count >= 100 %} -
    - {% trans 'Use argumentos para simplificar listagem...' %} -
    -{% endif %} - -{% for dpt in object_list %} - {% ifchanged dpt.ta%} - {% if not forloop.first %}{% endif %} -
    {{dpt.ta}}
    -
      - {% endifchanged %} - {% if dpt.is_relative_auto_insert and dpt.dispositivo_pai.nivel != 0 %} -
    • -
      - -
      -
      - - {% nomenclatura_heranca dpt 1 1 %} -
      -
    • - {% elif not dpt.tipo_dispositivo.dispositivo_de_articulacao %} -
    • -
      - -
      -
      - - {% nomenclatura_heranca dpt 1 1 %} -
      -
    • - {% elif dpt.tipo_dispositivo.dispositivo_de_articulacao%} -
    • -
      - -
      -
      - - {% nomenclatura_heranca dpt 1 1 %} -
      -
    • - {% endif%} - {% if forloop.last %}
    {% endif %} -{% endfor %} diff --git a/templates/compilacao/layout/dispositivo_checkbox.html b/templates/compilacao/layout/dispositivo_checkbox.html new file mode 100644 index 000000000..815c9fd2d --- /dev/null +++ b/templates/compilacao/layout/dispositivo_checkbox.html @@ -0,0 +1,49 @@ +{% load crispy_forms_filters %} +{% load i18n compilacao_filters common_tags%} + + +
    + {% include 'bootstrap/layout/field_errors_block.html' %} + + {% for choice in field.field.choices %} + + {% ifchanged choice.1.ta%} + {% if not forloop.first %}{% endif %} + {% endif %} + {% endfor %} + + + + {% include 'bootstrap/layout/help_text.html' %} +
    diff --git a/templates/compilacao/layout/dispositivo_checkbox_old.html b/templates/compilacao/layout/dispositivo_checkbox_old.html new file mode 100644 index 000000000..ec994877d --- /dev/null +++ b/templates/compilacao/layout/dispositivo_checkbox_old.html @@ -0,0 +1,54 @@ +{% load crispy_forms_filters %} +{% load i18n compilacao_filters common_tags%} + + +
    + {% include 'bootstrap/layout/field_errors_block.html' %} + + + + + {% for choice, dpt in field.field.choices %} + {% ifchanged dpt.ta%} + {% if not forloop.first %}{% endif %} +
      +
    • {{dpt.ta}}
    • + {% endifchanged %} + {% if dpt.is_relative_auto_insert %} +
    • +
      + +
      +
      + + {% nomenclatura_heranca dpt 1 1 %} +
      +
    • + {% elif not dpt.tipo_dispositivo.dispositivo_de_articulacao and not dpt.is_relative_auto_insert %} +
    • +
      + +
      +
      + + {% nomenclatura_heranca dpt 1 1 %} +
      +
    • + {% elif dpt.tipo_dispositivo.dispositivo_de_articulacao%} +
    • +
      + +
      +
      + + {% nomenclatura_heranca dpt 1 1 %} +
      +
    • + {% endif%} + {% if forloop.last %}
    {% endif %} + {% endfor %} + + + + {% include 'bootstrap/layout/help_text.html' %} +
    diff --git a/templates/compilacao/layout/dispositivo_radio.html b/templates/compilacao/layout/dispositivo_radio.html new file mode 100644 index 000000000..1192e86aa --- /dev/null +++ b/templates/compilacao/layout/dispositivo_radio.html @@ -0,0 +1,54 @@ +{% load crispy_forms_filters %} +{% load i18n compilacao_filters common_tags%} + + +
    + {% include 'bootstrap/layout/field_errors_block.html' %} + + + + + {% for choice, dpt in field.field.choices %} + {% ifchanged dpt.ta%} + {% if not forloop.first %}{% endif %} +
      +
    • {{dpt.ta}}
    • + {% endifchanged %} + {% if dpt.is_relative_auto_insert %} +
    • +
      + +
      +
      + + {% nomenclatura_heranca dpt 1 1 %} +
      +
    • + {% elif not dpt.tipo_dispositivo.dispositivo_de_articulacao and not dpt.is_relative_auto_insert %} +
    • +
      + +
      +
      + + {% nomenclatura_heranca dpt 1 1 %} +
      +
    • + {% elif dpt.tipo_dispositivo.dispositivo_de_articulacao%} +
    • +
      + +
      +
      + + {% nomenclatura_heranca dpt 1 1 %} +
      +
    • + {% endif%} + {% if forloop.last %}
    {% endif %} + {% endfor %} + + + + {% include 'bootstrap/layout/help_text.html' %} +
    diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index e72b41eba..e61c89f53 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -49,7 +49,7 @@ diff --git a/templates/compilacao/text_edit_bloco.html b/templates/compilacao/text_edit_bloco.html index 1cd33507e..34e078de9 100644 --- a/templates/compilacao/text_edit_bloco.html +++ b/templates/compilacao/text_edit_bloco.html @@ -27,7 +27,7 @@ {% endif %} {% endif %} {% endfor %} diff --git a/templates/compilacao/layout/dispositivo_checkbox.html b/templates/compilacao/layout/dispositivo_checkbox.html index 815c9fd2d..3ab87c5cc 100644 --- a/templates/compilacao/layout/dispositivo_checkbox.html +++ b/templates/compilacao/layout/dispositivo_checkbox.html @@ -1,7 +1,6 @@ {% load crispy_forms_filters %} {% load i18n compilacao_filters common_tags%} -
    {% include 'bootstrap/layout/field_errors_block.html' %} @@ -10,7 +9,14 @@ {% ifchanged choice.1.ta%} {% if not forloop.first %}{% endif %}
      -
    • {{choice.1.ta}}
    • +
    • +
      + +
      +
      + +
      +
    • {% endifchanged %} @@ -19,9 +25,11 @@
    - + {% if choice.1.ta_publicado_id %} + {% trans "Herança:" %} {% nomenclatura_heranca choice.1 1 1 %} + {% endif %}
    -
    +
    {{ choice.1.tipo_dispositivo.rotulo_prefixo_html|safe }} {% if choice.1.rotulo %}{{ choice.1.rotulo }}{%else%}[{{ choice.1|nomenclatura}}{% if choice.1.dispositivo_pai %} {% trans "de" %} {{ choice.1.dispositivo_pai.rotulo }}{% endif %}] - {% endif %} {{ choice.1.tipo_dispositivo.rotulo_sufixo_html|safe }} diff --git a/templates/compilacao/layout/dispositivo_radio.html b/templates/compilacao/layout/dispositivo_radio.html index 1192e86aa..8d019ccdb 100644 --- a/templates/compilacao/layout/dispositivo_radio.html +++ b/templates/compilacao/layout/dispositivo_radio.html @@ -12,7 +12,7 @@ {% ifchanged dpt.ta%} {% if not forloop.first %}{% endif %}
      -
    • {{dpt.ta}}
    • +
    • {{dpt.ta}}
    • {% endifchanged %} {% if dpt.is_relative_auto_insert %}
    • diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index e61c89f53..3e0bdfa66 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -63,7 +63,7 @@
    • (E) Editor Simples: Edição Básica de Texto, além de novas inserções e exclusões. É recomendável o uso deste sempre que possível.
    • (E+) Editor Rico: Edição do texto com o editor TinyMCE. Neste editor é possível registro de tabelas e textos customizados
    • (E*) Editor Avançado: Edição e Lançamento de Dispositivos Originais, Alterados e Alteradores, além de todos os dados que controlam a compilação.
    • -
    • (C) Construtor Estrutural: Neste modo, o editor foca na inserção de Dispositivos e busca deixar mais acessíveis as estas ações.
    • +
    • (C) Construtor Estrutural: Neste modo, o editor foca na inserção de Dispositivos e busca deixar mais acessíveis estas ações.
    • A Edição Avançada é complexa e sensível a erros de edição. É recomendável o uso cuidadoso e consciente das funcionalidades.
    • @@ -75,7 +75,7 @@
    • Inserir os Dispositivos na sequência natural é mais produtivo para você, além de ser também mais simples para o algorítmo que controla este processo. Quanto maior a mudança estutural, mais lento será o procedimento.
    • -
    • A Opção DVt (Dispositivo de Vigência do Texto) redefine o dispositivo em seleção, como o dispositivo de vigência de todos os outros, inclusive os dispositivos alterados, caso se trate de um Texto Alterador. +
    • A Opção DVt (Dispositivo de Vigência do Texto) redefine o dispositivo em seleção como o dispositivo de vigência de todos os outros, inclusive os dispositivos alterados, caso se trate de um Texto Alterador.
      1. O Dispositivo de Vigência de Dispositivos Alterados é, quase sempre, o Dispositivo do Texto Alterador, e não do Texto Alterado.
      2. Ao usar a opção DVt, todas as datas de início de vigência serão reenquadradas para a data de vigência do dispositivo de vigência. Posteriormente, alterações manuais poderão ser feitas.
      3. @@ -96,9 +96,9 @@ As exclusões podem ser diretas, individuais ou em bloco:
        1. Diretas: Dispositivos que não possuam itens internos são excluidos diretamente.
        2. -
        3. Individuais: Dispositivos que possuam itens internos e este podem ser reenquadrados no Dispositivo imediatamente anterior +
        4. Individuais: Dispositivos que possuam itens internos e estes podem ser reenquadrados no Dispositivo imediatamente anterior
            -
          • Ainda Não foi implementado a transferência de conteúdo na exclusão individual de DCC's que estão estruturalmente separados. Ex: Um artigo possui parágrafos, se seu artigo imediatamente anterior estiver no mesmo sub-grupo, esses parágrafos, na exlcusão individual, serão transferidos para o artigo anterior, no entanto, se estiverem em sub-grupo separados, o artigo será completamente excluido como em uma exclusão em bloco.
          • +
          • Ainda Não foi implementado a transferência de conteúdo na exclusão individual de DCC's que estão estruturalmente separados. Ex: Um artigo possui parágrafos, se seu artigo imediatamente anterior estiver no mesmo sub-grupo, esses parágrafos, na exclusão individual, serão transferidos para o artigo anterior, no entanto, se estiverem em sub-grupo separados, o artigo será completamente excluido como em uma exclusão em bloco.
        5. Em Bloco: Todo o conteúdo incluído no Dispositivo em edição será excluído.
        6. diff --git a/templates/compilacao/text_edit_bloco.html b/templates/compilacao/text_edit_bloco.html index 34e078de9..cc36d6bb6 100644 --- a/templates/compilacao/text_edit_bloco.html +++ b/templates/compilacao/text_edit_bloco.html @@ -99,7 +99,7 @@ {% if dpt.dispositivo_vigencia %}
        7. -
        8. {% field_verbose_name dpt 'dispositivo_vigencia'%}: {{dpt.dispositivo_vigencia|nomenclatura}}
        9. +
        10. {% field_verbose_name dpt 'dispositivo_vigencia'%}: {{dpt.dispositivo_vigencia|nomenclatura}}
        11. {% endif %}
        12. From 1e88b25216ab0a466b708a00f5e29b9a0c190598 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Wed, 6 Apr 2016 14:22:19 -0300 Subject: [PATCH 10/10] =?UTF-8?q?Conclus=C3=A3o=20da=20Edi=C3=A7=C3=A3o=20?= =?UTF-8?q?Avan=C3=A7ada=20-=20Issue=20#14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compilacao/forms.py | 291 ++++++++++++++- .../migrations/0048_auto_20160404_2309.py | 21 ++ compilacao/migrations/0049_merge.py | 16 + compilacao/models.py | 4 +- compilacao/templatetags/compilacao_filters.py | 92 ++++- compilacao/urls.py | 6 +- compilacao/views.py | 344 +++++++++--------- crispy_layout_mixin.py | 2 +- norma/urls.py | 2 +- static/js/app.js | 19 +- static/js/compilacao.js | 4 + templates/compilacao/dispositivo_form.html | 11 +- .../dispositivo_form_alteracao.html | 12 + .../dispositivo_form_definidor_vigencia.html | 2 +- .../dispositivo_form_edicao_basica.html | 8 +- .../dispositivo_form_search_fragment.html | 59 +-- .../compilacao/dispositivo_form_vigencia.html | 1 + .../layout/dispositivo_checkbox.html | 3 - .../compilacao/layout/dispositivo_radio.html | 55 ++- templates/compilacao/text_edit.html | 8 +- templates/compilacao/text_list_bloco.html | 2 +- .../textoarticulado_menu_config.html | 8 +- 22 files changed, 688 insertions(+), 282 deletions(-) create mode 100644 compilacao/migrations/0048_auto_20160404_2309.py create mode 100644 compilacao/migrations/0049_merge.py create mode 100644 templates/compilacao/dispositivo_form_alteracao.html diff --git a/compilacao/forms.py b/compilacao/forms.py index da081e3b4..f6d333309 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -1,7 +1,7 @@ -from datetime import datetime +from datetime import timedelta -from crispy_forms.bootstrap import FieldWithButtons, FormActions, StrictButton,\ - InlineRadios, Alert +from crispy_forms.bootstrap import (Alert, FieldWithButtons, FormActions, + InlineRadios, StrictButton) from crispy_forms.helper import FormHelper from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, Layout, Row) @@ -10,20 +10,18 @@ from django.core.exceptions import NON_FIELD_ERRORS, ValidationError from django.forms.forms import Form from django.forms.models import ModelForm from django.template import defaultfilters -from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from compilacao.models import (NOTAS_PUBLICIDADE_CHOICES, PARTICIPACAO_SOCIAL_CHOICES, Dispositivo, Nota, - Publicacao, TextoArticulado, TipoNota, - TipoPublicacao, TipoTextoArticulado, TipoVide, - VeiculoPublicacao, Vide, TipoDispositivo) + Publicacao, TextoArticulado, TipoDispositivo, + TipoNota, TipoPublicacao, TipoTextoArticulado, + TipoVide, VeiculoPublicacao, Vide) from compilacao.utils import DISPOSITIVO_SELECT_RELATED from crispy_layout_mixin import SaplFormLayout, to_column, to_row from sapl import utils from sapl.utils import YES_NO_CHOICES - error_messages = { 'required': _('Este campo é obrigatório'), 'invalid': _('URL inválida.') @@ -516,6 +514,13 @@ class DispositivoEdicaoBasicaForm(ModelForm): model = Dispositivo fields = [] + error_messages = { + NON_FIELD_ERRORS: { + 'unique_together': + _("Já existe um Dispositivo com características idênticas."), + } + } + def __init__(self, *args, **kwargs): layout = [] @@ -598,10 +603,9 @@ class DispositivoEdicaoBasicaForm(ModelForm): self.helper = FormHelper() self.helper.layout = SaplFormLayout( + *layout, label_cancel=_('Retornar para o Editor Sequencial')) - self.helper.layout.fields += layout - super(DispositivoEdicaoBasicaForm, self).__init__(*args, **kwargs) @@ -622,11 +626,20 @@ class DispositivoSearchModalForm(Form): label=_('Ano do Documento'), required=False) dispositivos_internos = forms.ChoiceField( - label=_('Incluir Dispositivos Internos Imediatos?'), + label=_('Dispositivos Internos?'), choices=utils.YES_NO_CHOICES, widget=forms.RadioSelect(), required=False) + max_results = forms.ChoiceField( + label=_('Limite de Listagem'), + choices=[(10, _('Dez Dispositivos')), + (30, _('Trinta Dispositivos')), + (50, _('Cinquenta Dispositivos')), + (0, _('Tudo que atender aos Critérios da Busca'))], + widget=forms.Select(), + required=False) + rotulo_dispositivo = forms.CharField( label=_('Rótulo'), required=False) @@ -640,20 +653,22 @@ class DispositivoSearchModalForm(Form): fields_search = Fieldset( _('Busca por um Dispositivo'), Row( - to_column(('num_ta', 3)), - to_column(('ano_ta', 3)), - to_column((InlineRadios('dispositivos_internos'), 6))), + to_column(('num_ta', 4)), + to_column(('ano_ta', 4)), + to_column(('max_results', 4))), Row( to_column(('tipo_ta', 6)), to_column(('tipo_model', 6))), - Row(to_column(('rotulo_dispositivo', 3)), + Row(to_column((InlineRadios('dispositivos_internos'), 3)), + to_column(('rotulo_dispositivo', 2)), to_column((FieldWithButtons( Field( 'texto_dispositivo', placeholder=_('Digite palavras, letras, ' 'números ou algo' ' que estejam no texto.')), - StrictButton(_('Buscar'), css_class='btn-busca')), 9))) + StrictButton(_('Buscar'), css_class='btn-busca')), 7)) + ) ) self.helper = FormHelper() @@ -707,6 +722,13 @@ class DispositivoEdicaoVigenciaForm(ModelForm): 'dispositivo_vigencia' ] + error_messages = { + NON_FIELD_ERRORS: { + 'unique_together': + _("Já existe um Dispositivo com características idênticas."), + } + } + def __init__(self, *args, **kwargs): layout = [] @@ -849,8 +871,11 @@ class DispositivoDefinidorVigenciaForm(Form): *DISPOSITIVO_SELECT_RELATED) self.initial['dispositivo_vigencia'] = [d.pk for d in dvs] - tas = Dispositivo.objects.filter( - dispositivo_vigencia_id=pk).values_list('ta', 'ta_publicado') + TA_TA_PUB = 'ta_id', 'ta_publicado_id' + tas = Dispositivo.objects.order_by( + *TA_TA_PUB).filter(dispositivo_vigencia_id=pk).distinct( + *TA_TA_PUB).values_list( + *TA_TA_PUB) tas = list(set().union(*list(map(list, zip(*tas))))) @@ -864,3 +889,233 @@ class DispositivoDefinidorVigenciaForm(Form): (d.pk, d) for d in dvs if d.pk in self.initial['dispositivo_vigencia']] + + +class DispositivoEdicaoAlteracaoForm(ModelForm): + + class Meta: + model = Dispositivo + fields = [ + 'dispositivo_atualizador', + 'dispositivo_substituido', + 'dispositivo_subsequente', + ] + error_messages = { + NON_FIELD_ERRORS: { + 'unique_together': + _("Já existe um Dispositivo com características idênticas."), + } + } + + def __init__(self, *args, **kwargs): + + layout = [] + + self.dispositivo_substituido = forms.ModelChoiceField( + label=Dispositivo._meta.get_field( + 'dispositivo_substituido').verbose_name, + required=False, + queryset=Dispositivo.objects.all()) + self.dispositivo_subsequente = forms.ModelChoiceField( + label=Dispositivo._meta.get_field( + 'dispositivo_subsequente').verbose_name, + required=False, + queryset=Dispositivo.objects.all()) + self.dispositivo_atualizador = forms.ModelChoiceField( + label=Dispositivo._meta.get_field( + 'dispositivo_atualizador').verbose_name, + required=False, + queryset=Dispositivo.objects.all()) + + substituido = Field( + 'dispositivo_substituido', + data_sapl_ta='DispositivoSearch', + data_field='dispositivo_substituido', + data_type_selection='radio', + template="compilacao/layout/dispositivo_radio.html") + subsequente = Field( + 'dispositivo_subsequente', + data_sapl_ta='DispositivoSearch', + data_field='dispositivo_subsequente', + data_type_selection='radio', + template="compilacao/layout/dispositivo_radio.html") + alterador = Field( + 'dispositivo_atualizador', + data_sapl_ta='DispositivoSearch', + data_field='dispositivo_atualizador', + data_type_selection='radio', + data_function='alterador', + template="compilacao/layout/dispositivo_radio.html") + + layout.append( + to_row([ + (Fieldset(_('Dispositivo Subsitituido'), substituido), 6), + (Fieldset(_('Dispositivo Subsequente'), subsequente), 6)])) + + layout.append( + Fieldset( + _('Dispositivo Alterador'), + Div(alterador), + css_class="col-md-12")) + + inst = kwargs['instance'] if 'instance' in kwargs else None + if inst and inst.tipo_dispositivo.dispositivo_de_articulacao: + if 'texto_atualizador' in\ + DispositivoEdicaoAlteracaoForm.Meta.fields: + DispositivoEdicaoAlteracaoForm.Meta.fields.remove( + 'texto_atualizador') + DispositivoEdicaoAlteracaoForm.Meta.fields.remove( + 'visibilidade') + else: + if 'texto_atualizador' not in\ + DispositivoEdicaoAlteracaoForm.Meta.fields: + DispositivoEdicaoAlteracaoForm.Meta.fields.append( + 'texto_atualizador') + DispositivoEdicaoAlteracaoForm.Meta.fields.append( + 'visibilidade') + + self.texto_atualizador = forms.CharField(required=False, + label='', + widget=forms.Textarea()) + self.visibilidade = forms.ChoiceField( + label=Dispositivo._meta.get_field( + 'visibilidade').verbose_name, + choices=utils.YES_NO_CHOICES, + widget=forms.RadioSelect()) + + layout.append( + Fieldset(Dispositivo._meta.get_field( + 'texto_atualizador').verbose_name, + to_row([(InlineRadios('visibilidade'), 12)]), + to_row([('texto_atualizador', 12)]), + css_class="col-md-12")) + + fields = DispositivoEdicaoAlteracaoForm.Meta.fields + if fields: + self.base_fields.clear() + for f in fields: + if hasattr(self, f): + self.base_fields.update({f: getattr(self, f)}) + + self.helper = FormHelper() + self.helper.layout = SaplFormLayout( + *layout, + label_cancel=_('Retornar para o Editor Sequencial')) + + super(DispositivoEdicaoAlteracaoForm, self).__init__(*args, **kwargs) + + self.fields['dispositivo_substituido'].choices = [] + self.fields['dispositivo_subsequente'].choices = [] + self.fields['dispositivo_atualizador'].choices = [] + if inst.dispositivo_substituido: + self.fields['dispositivo_substituido'].choices = [ + (inst.dispositivo_substituido.pk, + inst.dispositivo_substituido)] + + if inst.dispositivo_subsequente: + self.fields['dispositivo_subsequente'].choices = [ + (inst.dispositivo_subsequente.pk, + inst.dispositivo_subsequente)] + + if inst.dispositivo_atualizador: + self.fields['dispositivo_atualizador'].choices = [ + (inst.dispositivo_atualizador.pk, + inst.dispositivo_atualizador)] + + def clean_dispositivo_substituido(self): + dst = self.cleaned_data['dispositivo_substituido'] + + if dst and dst.ta != self.instance.ta: + raise ValidationError(_('Não é permitido selecionar um ' + 'Dispositivo de outro Texto Articulado.')) + if dst and dst.tipo_dispositivo != self.instance.tipo_dispositivo: + raise ValidationError(_('Não é permitido selecionar um ' + 'Dispositivo de outro Tipo.')) + return dst + + def clean_dispositivo_subsequente(self): + dsq = self.cleaned_data['dispositivo_subsequente'] + + if dsq and dsq.ta != self.instance.ta: + raise ValidationError(_('Não é permitido selecionar um ' + 'Dispositivo de outro Texto Articulado.')) + if dsq and dsq.tipo_dispositivo != self.instance.tipo_dispositivo: + raise ValidationError(_('Não é permitido selecionar um ' + 'Dispositivo de outro Tipo.')) + return dsq + + def clean_dispositivo_atualizador(self): + da = self.cleaned_data['dispositivo_atualizador'] + + if da and not da.tipo_dispositivo.dispositivo_de_alteracao and\ + not da.tipo_dispositivo.dispositivo_de_articulacao: + raise ValidationError(_('O Dispositivo de Atualização selecionado ' + 'não é um Bloco de Alteração.')) + return da + + def clean(self): + data = self.cleaned_data + ndst = data['dispositivo_substituido'] + nda = data['dispositivo_atualizador'] + + if not nda and ndst: + raise ValidationError(_('Não é permitido substituir um ' + 'Dispositivo sem haver um ' + 'Dispositivo Alterador.')) + + def save(self): + data = self.cleaned_data + + od = Dispositivo.objects.get(pk=self.instance.pk) + + nd = self.instance + ndst = data['dispositivo_substituido'] + ndsq = data['dispositivo_subsequente'] + nda = data['dispositivo_atualizador'] + + if ndst != od.dispositivo_substituido: + if od.dispositivo_substituido: + odst = od.dispositivo_substituido + + odst.dispositivo_subsequente = None + odst.fim_vigencia = None + odst.fim_eficacia = None + odst.save() + + if ndst: + if ndst.dispositivo_subsequente: + ndst.dispositivo_subsequente.dispositivo_substituido = None + ndst.dispositivo_subsequente.save() + + ndst.dispositivo_subsequente = nd + ndst.fim_vigencia = nd.inicio_vigencia - timedelta(days=1) + ndst.fim_eficacia = nd.inicio_eficacia - timedelta(days=1) + ndst.save() + + if ndsq != od.dispositivo_subsequente: + if od.dispositivo_subsequente: + odsq = od.dispositivo_subsequente + + odsq.dispositivo_substituido = None + odsq.save() + + if ndsq: + if ndsq.dispositivo_substituido: + ndsq.dispositivo_substituido.dispositivo_subsequente = None + ndsq.dispositivo_substituido.fim_vigencia = None + ndsq.dispositivo_substituido.fim_eficacia = None + ndsq.dispositivo_substituido.save() + + ndsq.dispositivo_substituido = nd + ndsq.save() + + nd.ta_publicado = nda.ta if nda else None + + super(DispositivoEdicaoAlteracaoForm, self).save() + + if nd.dispositivo_subsequente: + nd.fim_vigencia = nd.dispositivo_subsequente.inicio_vigencia - \ + timedelta(days=1) + nd.fim_eficacia = nd.dispositivo_subsequente.inicio_eficacia - \ + timedelta(days=1) + nd.save() diff --git a/compilacao/migrations/0048_auto_20160404_2309.py b/compilacao/migrations/0048_auto_20160404_2309.py new file mode 100644 index 000000000..9c25badfc --- /dev/null +++ b/compilacao/migrations/0048_auto_20160404_2309.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-04-05 02:09 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('compilacao', '0047_auto_20160330_0027'), + ] + + operations = [ + migrations.AlterField( + model_name='dispositivo', + name='dispositivo_vigencia', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='dispositivos_vigencias_set', to='compilacao.Dispositivo', verbose_name='Dispositivo de Vigência'), + ), + ] diff --git a/compilacao/migrations/0049_merge.py b/compilacao/migrations/0049_merge.py new file mode 100644 index 000000000..beaedb5ff --- /dev/null +++ b/compilacao/migrations/0049_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-04-06 17:43 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('compilacao', '0045_auto_20160404_1411'), + ('compilacao', '0048_auto_20160404_2309'), + ] + + operations = [ + ] diff --git a/compilacao/models.py b/compilacao/models.py index 8b96aba33..90a3c5c35 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -1,5 +1,3 @@ -from builtins import zip -from datetime import datetime from django.contrib.auth.models import User from django.contrib.contenttypes.fields import GenericForeignKey @@ -983,7 +981,7 @@ class Dispositivo(BaseModel, TimestampedMixin): def get_parents(self, ordem='desc'): dp = self p = [] - while dp.dispositivo_pai is not None: + while dp.dispositivo_pai: dp = dp.dispositivo_pai if ordem == 'desc': p.append(dp) diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index 2ee09593b..7a8bd5398 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -1,10 +1,11 @@ + from django import template from django.core.signing import Signer from django.db.models import Q from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from compilacao.models import Dispositivo, TipoDispositivo +from compilacao.models import Dispositivo register = template.Library() @@ -131,6 +132,92 @@ def nomenclatura(d): return result +def update_dispositivos_parents(dpts_parents, ta_id): + + dpts = Dispositivo.objects.order_by('ordem').filter( + ta_id=ta_id).values_list( + 'pk', 'dispositivo_pai_id', 'rotulo', 'tipo_dispositivo__nome', + 'tipo_dispositivo__rotulo_prefixo_texto') + + for d in dpts: + dpts_parents[str(d[0])] = { + 'd': d, 'p': [], 'h': None} + + def parents(k): + pai = dpts_parents[str(k)]['d'][1] + p = dpts_parents[str(k)]['p'] + if not p: + if pai: + parent_k = [pai, ] + parents(pai) + else: + parent_k = [] + else: + parent_k = p + + return parent_k + + for k in dpts_parents: + dpts_parents[str(k)]['p'] = parents(k) + + +@register.simple_tag +def heranca(request, d, ignore_ultimo=0, ignore_primeiro=0): + ta_dpts_parents = request.session.get('herancas') + + if not ta_dpts_parents: + ta_dpts_parents = {} + + ta_id = str(d.ta_id) + if ta_id not in ta_dpts_parents: + dpts_parents = {} + ta_dpts_parents[ta_id] = dpts_parents + update_dispositivos_parents(dpts_parents, ta_id) + + herancas_fila = request.session.get('herancas_fila') + if not herancas_fila: + herancas_fila = [] + + herancas_fila.append(ta_id) + if len(herancas_fila) > 100: + ta_remove = herancas_fila.pop(0) + del ta_dpts_parents[str(ta_remove)] + + request.session['herancas_fila'] = herancas_fila + request.session['herancas'] = ta_dpts_parents + + d_pk = str(d.pk) + h = ta_dpts_parents[ta_id][d_pk]['h'] + + if h: + return h + + dpts_parents = ta_dpts_parents[ta_id] + parents = dpts_parents[d_pk]['p'] + result = '' + + if parents: + pk_last = parents[-1] + for pk in parents: + + if ignore_ultimo and pk == pk_last: + break + + if ignore_primeiro: + ignore_primeiro = 0 + continue + + p = dpts_parents[str(pk)]['d'] + + if p[4] != '': + result = p[2] + ' ' + result + else: + result = '(' + p[3] + ' ' + \ + p[2] + ')' + ' ' + result + + dpts_parents[d_pk]['h'] = result + return result + + @register.simple_tag def nomenclatura_heranca(d, ignore_ultimo=0, ignore_primeiro=0): result = '' @@ -159,7 +246,8 @@ def nomenclatura_heranca(d, ignore_ultimo=0, ignore_primeiro=0): @register.filter def urldetail_content_type(obj): - return '%s:detail' % obj.content_type.model + return '%s:%s_detail' % ( + obj.content_type.app_label, obj.content_type.model) @register.filter diff --git a/compilacao/urls.py b/compilacao/urls.py index 1a2262c02..0a3c93222 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -40,6 +40,10 @@ urlpatterns_compilacao = [ views.DispositivoEdicaoVigenciaView.as_view(), name='dispositivo_edit_vigencia'), + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit/alteracao', + views.DispositivoEdicaoAlteracaoView.as_view(), + name='dispositivo_edit_alteracao'), + url(r'^(?P[0-9]+)/text/(?P[0-9]+)/edit/definidor_vigencia', views.DispositivoDefinidorVigenciaView.as_view(), name='dispositivo_edit_definidor_vigencia'), @@ -107,7 +111,7 @@ urlpatterns_compilacao = [ ] urlpatterns = [ - url(r'^ta/', include(urlpatterns_compilacao, 'compilacao', 'compilacao')), + url(r'^ta/', include(urlpatterns_compilacao)), url(r'^ta/config/tipo-nota/', include(TipoNotaCrud.get_urls())), diff --git a/compilacao/views.py b/compilacao/views.py index 4842f00b4..1f14f9685 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1,6 +1,6 @@ +import sys from collections import OrderedDict from datetime import datetime, timedelta -import sys from braces.views import FormMessagesMixin from django import forms @@ -10,7 +10,6 @@ from django.core.signing import Signer from django.core.urlresolvers import reverse_lazy from django.db import transaction from django.db.models import Q -from django.forms.models import model_to_dict from django.http.response import (HttpResponse, HttpResponseRedirect, JsonResponse) from django.shortcuts import get_object_or_404, redirect @@ -19,15 +18,16 @@ from django.utils.decorators import method_decorator from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import TemplateView from django.views.generic.detail import DetailView -from django.views.generic.edit import CreateView, DeleteView, UpdateView,\ - FormView +from django.views.generic.edit import (CreateView, DeleteView, FormView, + UpdateView) from django.views.generic.list import ListView -from compilacao.forms import (DispositivoEdicaoBasicaForm, NotaForm, - PublicacaoForm, TaForm, TipoTaForm, VideForm, +from compilacao.forms import (DispositivoDefinidorVigenciaForm, + DispositivoEdicaoAlteracaoForm, + DispositivoEdicaoBasicaForm, DispositivoEdicaoVigenciaForm, - DispositivoSearchModalForm, - DispositivoDefinidorVigenciaForm) + DispositivoSearchModalForm, NotaForm, + PublicacaoForm, TaForm, TipoTaForm, VideForm) from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, Publicacao, TextoArticulado, TipoDispositivo, TipoNota, @@ -36,7 +36,6 @@ from compilacao.models import (Dispositivo, Nota, from compilacao.utils import DISPOSITIVO_SELECT_RELATED from crud.base import Crud, CrudListView, make_pagination - TipoNotaCrud = Crud.build(TipoNota, 'tipo_nota') TipoVideCrud = Crud.build(TipoVide, 'tipo_vide') TipoPublicacaoCrud = Crud.build(TipoPublicacao, 'tipo_publicacao') @@ -1283,18 +1282,18 @@ class ActionsEditMixin: dps = Dispositivo.objects.filter(dispositivo_vigencia_id=dvt.pk, ta_publicado_id=dvt.ta_id) + with transaction.atomic(): + for d in dps: + if d.dispositivo_substituido: + ds = d.dispositivo_substituido + ds.fim_vigencia = d.inicio_vigencia - timedelta(days=1) + ds.fim_eficacia = d.inicio_eficacia - timedelta(days=1) + d.save() - for d in dps: - if d.dispositivo_substituido: - ds = d.dispositivo_substituido - ds.fim_vigencia = d.inicio_vigencia - timedelta(days=1) - ds.fim_eficacia = d.inicio_eficacia - timedelta(days=1) - ds.save() - - if d.dispositivo_subsequente: - ds = d.dispositivo_subsequente - d.fim_vigencia = ds.inicio_vigencia - timedelta(days=1) - d.fim_eficacia = ds.inicio_eficacia - timedelta(days=1) + if d.dispositivo_subsequente: + ds = d.dispositivo_subsequente + d.fim_vigencia = ds.inicio_vigencia - timedelta(days=1) + d.fim_eficacia = ds.inicio_eficacia - timedelta(days=1) d.save() return {'message': str(_('Dispositivo de Vigência atualizado ' @@ -1616,72 +1615,6 @@ class ActionsEditMixin: return '' - """ - if proxima_articulacao: - irmaos_posteriores = Dispositivo.objects.filter( - ta_id=base.ta_id, - ordem__gt=base.ordem, - tipo_dispositivo=base.tipo_dispositivo, - ordem__lt=proxima_articulacao.ordem) - else: - irmaos_posteriores = Dispositivo.objects.filter( - ta_id=base.ta_id, - ordem__gt=base.ordem, - tipo_dispositivo=base.tipo_dispositivo) - - proxima_articulacao = base.get_proximo_nivel_zero() - - # Renumerar Dispostivos de Contagem Contínua de dentro da base - if not proxima_articulacao: - dcc = Dispositivo.objects.order_by('ordem').filter( - ta_id=base.ta_id, - ordem__gt=base.ordem, - tipo_dispositivo__contagem_continua=True) - else: - dcc = Dispositivo.objects.order_by('ordem').filter( - ta_id=base.ta_id, - ordem__gt=base.ordem, - ordem__lt=proxima_articulacao.ordem, - tipo_dispositivo__contagem_continua=True) - - base_adicao = {} - - nivel_zero_anterior = base.get_nivel_zero_anterior() - if nivel_zero_anterior: - nivel_zero_anterior = nivel_zero_anterior.ordem - else: - nivel_zero_anterior = 0 - - dcc = list(dcc) - for d in dcc: # ultimo DCC do tipo encontrado - - if d.tipo_dispositivo.class_css not in base_adicao: - ultimo_dcc = Dispositivo.objects.order_by( - 'ordem').filter( - ta_id=base.ta_id, - ordem__lt=base.ordem, - ordem__gt=nivel_zero_anterior, - tipo_dispositivo__contagem_continua=True, - tipo_dispositivo=d.tipo_dispositivo).last() - - if not ultimo_dcc: - break - - base_adicao[ - d.tipo_dispositivo.class_css] = ultimo_dcc.\ - dispositivo0 - - d.dispositivo0 += base_adicao[d.tipo_dispositivo.class_css] - - d.rotulo = d.rotulo_padrao() - dcc.reverse() - for d in dcc: - d.save() - - base.delete() - return '' - """ - def add_prior(self, context): return {} @@ -1694,6 +1627,9 @@ class ActionsEditMixin: dp_auto_insert = None base = Dispositivo.objects.get(pk=context['dispositivo_id']) tipo = TipoDispositivo.objects.get(pk=context['tipo_pk']) + pub_last = Publicacao.objects.order_by( + 'data', 'hora').filter(ta=base.ta).last() + variacao = int(context['variacao']) parents = [base, ] + base.get_parents() @@ -1791,6 +1727,7 @@ class ActionsEditMixin: dp.ordem = ordem dp.incrementar_irmaos(variacao, [local_add, ], force=False) + dp.publicacao = pub_last dp.save() # Inserção automática @@ -1808,6 +1745,8 @@ class ActionsEditMixin: dp.rotulo = dp.rotulo_padrao() dp.texto = '' dp.ordem = dp.ordem + Dispositivo.INTERVALO_ORDEM + + dp.publicacao = pub_last dp.save() dp_auto_insert = dp dp = Dispositivo.objects.get(pk=dp_pk) @@ -1841,7 +1780,6 @@ class ActionsEditMixin: continue filho.dispositivo_pai = dp - filho.clean() filho.save() flag_niveis = True @@ -1982,79 +1920,11 @@ class ActionsEditView(ActionsEditMixin, TemplateView): 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 DispositivoEdicaoBasicaView(FormMessagesMixin, UpdateView): - model = Dispositivo - template_name = 'compilacao/dispositivo_form_edicao_basica.html' - form_class = DispositivoEdicaoBasicaForm - form_valid_message = _('Alterações no Dispositivo realizadas com sucesso!') - form_invalid_message = _('Houve erro em registrar ' - 'as alterações no Dispositivo') - - @property - def cancel_url(self): - return reverse_lazy( - 'compilacao:ta_text_edit', - kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) + if 'herancas' in self.request.session: + del self.request.session['herancas'] + del self.request.session['herancas_fila'] - def get_success_url(self): - return reverse_lazy( - 'compilacao:dispositivo_edit', - kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) - - def get_url_this_view(self): - return 'compilacao:dispositivo_edit' - - def run_actions(self, request): - if 'action' in request.GET and\ - request.GET['action'] == 'atualiza_rotulo': - try: - d = Dispositivo.objects.get(pk=self.kwargs['pk']) - d.dispositivo0 = int(request.GET['dispositivo0']) - d.dispositivo1 = int(request.GET['dispositivo1']) - d.dispositivo2 = int(request.GET['dispositivo2']) - d.dispositivo3 = int(request.GET['dispositivo3']) - d.dispositivo4 = int(request.GET['dispositivo4']) - d.dispositivo5 = int(request.GET['dispositivo5']) - d.rotulo = d.rotulo_padrao() - - numero = d.get_numero_completo()[1:] - - zerar = False - for i in range(len(numero)): - if not numero[i]: - zerar = True - - if zerar: - numero[i] = 0 - - if zerar: - d.set_numero_completo([d.dispositivo0, ] + numero) - d.rotulo = d.rotulo_padrao() - - except: - return True, JsonResponse({'message': str( - _('Ocorreu erro na atualização do rótulo'))}, safe=False) - return True, JsonResponse({ - 'rotulo': d.rotulo, - 'dispositivo0': d.dispositivo0, - 'dispositivo1': d.dispositivo1, - 'dispositivo2': d.dispositivo2, - 'dispositivo3': d.dispositivo3, - 'dispositivo4': d.dispositivo4, - 'dispositivo5': d.dispositivo5}, safe=False) - - return False, '' - - def get(self, request, *args, **kwargs): - - flag_action, render_json_response = self.run_actions(request) - if flag_action: - return render_json_response - - return UpdateView.get(self, request, *args, **kwargs) + return self.render_to_json_response(context, **response_kwargs) class DispositivoSearchFragmentFormView(ListView): @@ -2078,7 +1948,10 @@ class DispositivoSearchFragmentFormView(ListView): def get_queryset(self): try: - n = 50 + n = 10 + if 'max_results' in self.request.GET: + n = int(self.request.GET['max_results']) + q = Q() if 'initial_ref' in self.request.GET: initial_ref = self.request.GET['initial_ref'] @@ -2132,7 +2005,7 @@ class DispositivoSearchFragmentFormView(ListView): if ano_ta: q = q & Q(ta__ano=ano_ta) - if not q.children: + if not q.children and not n: n = 10 q = q & Q(nivel__gt=0) @@ -2141,16 +2014,35 @@ class DispositivoSearchFragmentFormView(ListView): '-ta__ano', '-ta__numero', 'ta', - 'ordem').filter(q).select_related('ta').exclude( - tipo_dispositivo__dispositivo_de_alteracao=True) + 'ordem').filter(q).select_related('ta') + + if 'data_type_selection' in self.request.GET and\ + self.request.GET['data_type_selection'] == 'checkbox': + result = result.exclude( + tipo_dispositivo__dispositivo_de_alteracao=True) + else: + if 'data_function' in self.request.GET and\ + self.request.GET['data_function'] == 'alterador': + result = result.exclude( + tipo_dispositivo__dispositivo_de_alteracao=False, + ) + result = result.exclude( + tipo_dispositivo__dispositivo_de_articulacao=False, + ) + print(str(result.query)) def resultados(r): - if num_ta and ano_ta and not rotulo and not str_texto and\ + if n: + return r[:n] + else: + return r + + """if num_ta and ano_ta and not rotulo and not str_texto and\ 'data_type_selection' in self.request.GET and\ self.request.GET['data_type_selection'] == 'checkbox': return r else: - return r[:n] + return r[:n]""" if 'tipo_model' not in self.request.GET: return resultados(result) @@ -2214,6 +2106,78 @@ class DispositivoSearchModalView(FormView): form_class = DispositivoSearchModalForm +class DispositivoEdicaoBasicaView(FormMessagesMixin, UpdateView): + model = Dispositivo + template_name = 'compilacao/dispositivo_form_edicao_basica.html' + form_class = DispositivoEdicaoBasicaForm + form_valid_message = _('Alterações no Dispositivo realizadas com sucesso!') + form_invalid_message = _('Houve erro em registrar ' + 'as alterações no Dispositivo') + + @property + def cancel_url(self): + return reverse_lazy( + 'compilacao:ta_text_edit', + kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) + + def get_success_url(self): + return reverse_lazy( + 'compilacao:dispositivo_edit', + kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) + + def get_url_this_view(self): + return 'compilacao:dispositivo_edit' + + def run_actions(self, request): + if 'action' in request.GET and\ + request.GET['action'] == 'atualiza_rotulo': + try: + d = Dispositivo.objects.get(pk=self.kwargs['pk']) + d.dispositivo0 = int(request.GET['dispositivo0']) + d.dispositivo1 = int(request.GET['dispositivo1']) + d.dispositivo2 = int(request.GET['dispositivo2']) + d.dispositivo3 = int(request.GET['dispositivo3']) + d.dispositivo4 = int(request.GET['dispositivo4']) + d.dispositivo5 = int(request.GET['dispositivo5']) + d.rotulo = d.rotulo_padrao() + + numero = d.get_numero_completo()[1:] + + zerar = False + for i in range(len(numero)): + if not numero[i]: + zerar = True + + if zerar: + numero[i] = 0 + + if zerar: + d.set_numero_completo([d.dispositivo0, ] + numero) + d.rotulo = d.rotulo_padrao() + + except: + return True, JsonResponse({'message': str( + _('Ocorreu erro na atualização do rótulo'))}, safe=False) + return True, JsonResponse({ + 'rotulo': d.rotulo, + 'dispositivo0': d.dispositivo0, + 'dispositivo1': d.dispositivo1, + 'dispositivo2': d.dispositivo2, + 'dispositivo3': d.dispositivo3, + 'dispositivo4': d.dispositivo4, + 'dispositivo5': d.dispositivo5}, safe=False) + + return False, '' + + def get(self, request, *args, **kwargs): + + flag_action, render_json_response = self.run_actions(request) + if flag_action: + return render_json_response + + return UpdateView.get(self, request, *args, **kwargs) + + class DispositivoEdicaoVigenciaView(FormMessagesMixin, UpdateView): model = Dispositivo template_name = 'compilacao/dispositivo_form_vigencia.html' @@ -2281,12 +2245,50 @@ class DispositivoDefinidorVigenciaView(FormMessagesMixin, FormView): form = self.get_form() if form.is_valid(): dvs = form.cleaned_data['dispositivo_vigencia'] - with transaction.atomic(): - self.object.dispositivos_vigencias_set.clear() - for item in dvs: - d = Dispositivo.objects.get(pk=item) - self.object.dispositivos_vigencias_set.add(d) + try: + with transaction.atomic(): + self.object.dispositivos_vigencias_set.clear() + for item in dvs: + d = Dispositivo.objects.get(pk=item) + self.object.dispositivos_vigencias_set.add(d) + return self.form_valid(form) + except: + return self.form_invalid(form) + else: + return self.form_invalid(form) + + +class DispositivoEdicaoAlteracaoView(FormMessagesMixin, UpdateView): + model = Dispositivo + template_name = 'compilacao/dispositivo_form_alteracao.html' + form_class = DispositivoEdicaoAlteracaoForm + form_valid_message = _('Alterações no Dispositivo realizadas com sucesso!') + form_invalid_message = _('Houve erro em registrar ' + 'as alterações no Dispositivo') + + @property + def cancel_url(self): + return reverse_lazy( + 'compilacao:ta_text_edit', + kwargs={'ta_id': self.kwargs['ta_id']}) + '#' + str(self.object.pk) - return self.form_valid(form) + def get_url_this_view(self): + return 'compilacao:dispositivo_edit_alteracao' + + def get_success_url(self): + return reverse_lazy( + 'compilacao:dispositivo_edit_alteracao', + kwargs={'ta_id': self.kwargs['ta_id'], 'pk': self.kwargs['pk']}) + + def post(self, request, *args, **kwargs): + self.object = get_object_or_404(Dispositivo, pk=kwargs['pk']) + + form = self.get_form() + if form.is_valid(): + try: + with transaction.atomic(): + return self.form_valid(form) + except: + return self.form_invalid(form) else: return self.form_invalid(form) diff --git a/crispy_layout_mixin.py b/crispy_layout_mixin.py index c812b4315..ddff0283c 100644 --- a/crispy_layout_mixin.py +++ b/crispy_layout_mixin.py @@ -1,11 +1,11 @@ from math import ceil from os.path import dirname, join +import rtyaml from crispy_forms.bootstrap import FormActions from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit from django.utils.translation import ugettext as _ -import rtyaml def heads_and_tails(list_of_lists): diff --git a/norma/urls.py b/norma/urls.py index d68fd36a5..199888813 100644 --- a/norma/urls.py +++ b/norma/urls.py @@ -19,7 +19,7 @@ app_name = AppConfig.name # url(r'^norma/(?P[0-9]+)/ta$', NormaTaView.as_view(), name='ta') # bem como a classe NormaTaView que está em norma.views norma_url_patterns = NormaTemporarioCrud.get_urls() + [ - url(r'^norma/(?P[0-9]+)/ta$', + url(r'^(?P[0-9]+)/ta$', NormaTaView.as_view(), name='ta') ] diff --git a/static/js/app.js b/static/js/app.js index 5943024d8..03537f188 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1,7 +1,6 @@ -function initTinymce() { +function initTinymce(elements) { removeTinymce(); - tinymce.init({ - mode : "textareas", + var config_tinymce = { force_br_newlines : false, force_p_newlines : false, forced_root_block : '', @@ -10,8 +9,16 @@ function initTinymce() { toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent", tools: "inserttable", border_css: "/static/styles/style_tinymce.css", - content_css: "/static/styles/style_tinymce.css" - }); + content_css: "/static/styles/style_tinymce.css", + } + if (elements != null) { + config_tinymce['elements'] = elements; + config_tinymce['mode'] = "exact"; + } + else + config_tinymce['mode'] = "textareas"; + + tinymce.init(config_tinymce); } function removeTinymce() { @@ -112,5 +119,5 @@ $(document).ready(function(){ refreshDatePicker(); refreshMask(); autorModal(); - initTinymce(); + initTinymce("biografia-parlamentar,casa-informacoes"); }); diff --git a/static/js/compilacao.js b/static/js/compilacao.js index 954e75121..058801b65 100644 --- a/static/js/compilacao.js +++ b/static/js/compilacao.js @@ -39,6 +39,7 @@ function DispostivoSearch(opts) { var field = $(this); var data_type_selection = field.attr('data-type-selection'); var data_field = field.attr('data-field'); + var data_function = field.attr('data-function'); var onChangeFieldSelects = function(event) { if (data_type_selection == 'checkbox') { @@ -77,6 +78,7 @@ function DispostivoSearch(opts) { var dispositivos_internos = $("input[name='dispositivos_internos']:checked").val(); var rotulo_dispositivo = $("input[name='rotulo_dispositivo']").val(); var texto_dispositivo = $("input[name='texto_dispositivo']").val(); + var max_results = $("select[name='max_results']").val(); var url = ''; if (rotulo_dispositivo.length > 0 || texto_dispositivo.length > 0) { @@ -97,8 +99,10 @@ function DispostivoSearch(opts) { 'texto' : texto_dispositivo, 'rotulo' : rotulo_dispositivo, 'dispositivos_internos' : dispositivos_internos, + 'max_results' : max_results, 'data_type_selection' : data_type_selection, 'data_field' : data_field, + 'data_function' : data_function, }; url = '/ta/search_fragment_form'; diff --git a/templates/compilacao/dispositivo_form.html b/templates/compilacao/dispositivo_form.html index 9cbe7f2e1..70ee7c79f 100644 --- a/templates/compilacao/dispositivo_form.html +++ b/templates/compilacao/dispositivo_form.html @@ -8,12 +8,13 @@ {% endblock sections_nav %}{% trans '' %} diff --git a/templates/compilacao/dispositivo_form_alteracao.html b/templates/compilacao/dispositivo_form_alteracao.html new file mode 100644 index 000000000..bac498539 --- /dev/null +++ b/templates/compilacao/dispositivo_form_alteracao.html @@ -0,0 +1,12 @@ +{% extends "compilacao/dispositivo_form.html" %} +{% load i18n %} + +{% block extra_js %}{{block.super}} + +{% endblock %} diff --git a/templates/compilacao/dispositivo_form_definidor_vigencia.html b/templates/compilacao/dispositivo_form_definidor_vigencia.html index c45bc8387..da7bbc4e1 100644 --- a/templates/compilacao/dispositivo_form_definidor_vigencia.html +++ b/templates/compilacao/dispositivo_form_definidor_vigencia.html @@ -5,7 +5,7 @@ {% endblock %} diff --git a/templates/compilacao/dispositivo_form_edicao_basica.html b/templates/compilacao/dispositivo_form_edicao_basica.html index 73f376d4e..45ab34594 100644 --- a/templates/compilacao/dispositivo_form_edicao_basica.html +++ b/templates/compilacao/dispositivo_form_edicao_basica.html @@ -31,12 +31,6 @@ }); } - $(document).ready(function() { - - {% if object.tipo_dispositivo.dispositivo_de_articulacao %} - setTimeout(removeTinymce, 100); - {% endif %} - - }); + initTinymce(); {% endblock %} diff --git a/templates/compilacao/dispositivo_form_search_fragment.html b/templates/compilacao/dispositivo_form_search_fragment.html index c17bceb37..b80a5c1ec 100644 --- a/templates/compilacao/dispositivo_form_search_fragment.html +++ b/templates/compilacao/dispositivo_form_search_fragment.html @@ -9,37 +9,37 @@ {% for dpt in object_list %} {% ifchanged dpt.ta%} {% if not forloop.first %}
    {% endif %} -
    {% if dpt.nivel > 1 %} - {% trans "Herança:" %} {% nomenclatura_heranca dpt 1 1 %} + {% trans "Herança:" %} {% heranca request dpt 1 0 %} {% endif %}
    -
    +
    {{ dpt.tipo_dispositivo.rotulo_prefixo_html|safe }} {% if dpt.rotulo or dpt.nivel = 1 %}{{ dpt.rotulo }}{%else%}[{{ dpt|nomenclatura}} {% trans "de" %} {{ dpt.dispositivo_pai.rotulo }}] - {% endif %} {{ dpt.tipo_dispositivo.rotulo_sufixo_html|safe }} - {{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{%if dpt.texto %}{{ dpt.texto|safe }}{%else%}{%if not dpt.tipo_dispositivo.dispositivo_de_articulacao %} {% endif %}{% endif %} - {% if dpt.ta_publicado_id and not dpt.tipo_dispositivo.dispositivo_de_articulacao %} + + {{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{%if dpt.texto %}{{ dpt.texto|safe }}{%else%}{%if not dpt.tipo_dispositivo.dispositivo_de_articulacao %} {% endif %}{% endif %} + {% if dpt.ta_publicado_id %} {{ dpt.tipo_dispositivo.nota_automatica_prefixo_html|safe }} {% nota_automatica dpt ta_pub_list %} {{ dpt.tipo_dispositivo.nota_automatica_sufixo_html|safe }} {% endif %} +
    + {% if dpt.tipo_dispositivo.dispositivo_de_alteracao%} + {%with node=dpt template_name='compilacao/text_list_blocoalteracao.html' %} + {%include template_name%} + {%endwith%} + {% endif%}
    @@ -87,16 +98,16 @@
    {% if df.nivel > 1 %} - {% trans "Herança:" %} {% nomenclatura_heranca df 1 1 %} + {% trans "Herança:" %} {% heranca request df 1 0 %} {% endif %}
    - - {% if forloop.last %}{% endif %} {% endfor %} diff --git a/templates/compilacao/layout/dispositivo_radio.html b/templates/compilacao/layout/dispositivo_radio.html index 8d019ccdb..6f0891280 100644 --- a/templates/compilacao/layout/dispositivo_radio.html +++ b/templates/compilacao/layout/dispositivo_radio.html @@ -5,46 +5,35 @@
    {% include 'bootstrap/layout/field_errors_block.html' %} - - - {% for choice, dpt in field.field.choices %} {% ifchanged dpt.ta%} {% if not forloop.first %}{% endif %}
    + + {% if forloop.last %}{% endif %} {% endfor %} diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index 3e0bdfa66..bab5b89de 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -66,7 +66,7 @@
  • (C) Construtor Estrutural: Neste modo, o editor foca na inserção de Dispositivos e busca deixar mais acessíveis estas ações.
  • -
  • A Edição Avançada é complexa e sensível a erros de edição. É recomendável o uso cuidadoso e consciente das funcionalidades.
  • +
  • A Edição Avançada é complexa e sensível a erros de edição. É recomendável o uso cuidadoso e consciente das funcionalidades. Ela será tratada num tópico aparte.
  • Gere toda a estrutura básica sem adicionar texto, isso evitará erros estruturais e otimizará seu trabalho por:
    1. Facilitar o trabalho local aí, de seu navegador.
    2. @@ -105,6 +105,12 @@
  • +
    +

    Edição Avançada

    +
      +
    1. ... +
    2. +
    {% endblocktrans %} diff --git a/templates/compilacao/text_list_bloco.html b/templates/compilacao/text_list_bloco.html index c9e81d223..5ee5de08d 100644 --- a/templates/compilacao/text_list_bloco.html +++ b/templates/compilacao/text_list_bloco.html @@ -163,7 +163,7 @@ {% endif%}
    {% endspaceless %} - {% if dpt.tipo_dispositivo.class_css == 'bloco_alteracao'%} + {% if dpt.tipo_dispositivo.dispositivo_de_alteracao%} {%with node=dpt template_name='compilacao/text_list_blocoalteracao.html' %} {%include template_name%} {%endwith%} diff --git a/templates/compilacao/textoarticulado_menu_config.html b/templates/compilacao/textoarticulado_menu_config.html index d73ae5ac1..00fe6a1bf 100644 --- a/templates/compilacao/textoarticulado_menu_config.html +++ b/templates/compilacao/textoarticulado_menu_config.html @@ -6,10 +6,10 @@