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 %} - {% endif %} {% 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 @@