Browse Source

Ref funcionalidades dos Textos Articulados

- corrige problema no buscador de dispositivos
- armazena em localstorage o form de busca de dispositivos para futuras
buscas (
- muda para multi-seleção de dispositivos no buscador
- Impl de multi-seleção para registro de alteração... vários
dispostivos podem ser selecionados ao mesmo tempo sem a necessidade de
aberturas constantes do buscador de dispositivos.
- Impl revogação em bloco a multi-bloco
    - disponibiliza pergunta se será uma revogação em bloco ou não
    - como o buscador agora pode selelcionar vários dispositivos, se a
revogação for em bloco, cada dispositivo selecionado no buscador é um
bloco e tudo dentro dele será revogado. Exemplo:

Revogar em bloco [ X ] Sim    [  ] Não

[ X ]        Seção 1
[   ]   Art. 6º -
[   ]   Caput do art. 6º ...
[   ]   Parágrafo Único ...
[   ]        Seção 2
[   ]   Art. 7º -
[ X ]   Caput do art. 7º ...
[   ]   I - ...
[   ]   II - ...
[   ]   § 1º
[   ]   § 2º
O que a revogação em bloco revogará?

Existem dois dispositivos selecionados - Seção 1 e Caput do art. 7 - mas
foi marcado revogação em bloco... portanto,

Seção 1, Art. 6 e seu caput, Parágrafo único, o Caput do Art 7, Inciso
I, Inciso II...

seleções ambiguas são descartadas, por exemplo: se Seção 1 está marcada,
e o usuário marcou tb. o Parágrafo Único, o filtro de ambiguidade
 tranta a Seção 1 inteira, sendo que as seleções internas so
ambiguidades descatadas

revogação em bloco de multiplos blocos.
pull/2365/head
Leandro Roberto 6 years ago
parent
commit
be381b2401
  1. 15
      sapl/compilacao/forms.py
  2. 22
      sapl/compilacao/models.py
  3. 141
      sapl/compilacao/views.py
  4. 39
      sapl/static/js/app.js
  5. 51
      sapl/static/js/compilacao.js
  6. 41
      sapl/static/js/compilacao_edit.js
  7. 2
      sapl/templates/compilacao/ajax_form.html

15
sapl/compilacao/forms.py

@ -1343,7 +1343,7 @@ class DispositivoRegistroAlteracaoForm(Form):
'dispositivo_alterado',
data_sapl_ta='DispositivoSearch',
data_field='dispositivo_alterado',
data_type_selection='radio',
data_type_selection='checkbox',
template="compilacao/layout/dispositivo_radio.html")
layout.append(Fieldset(_('Registro de Alteração - '
@ -1378,6 +1378,14 @@ class DispositivoRegistroRevogacaoForm(Form):
required=False,
queryset=Dispositivo.objects.all())
revogacao_em_bloco = forms.ChoiceField(
label=_(
'Revogar todos os dispositivos internos dos '
'dispositivos abaixo selecionados?'),
choices=YES_NO_CHOICES,
widget=forms.RadioSelect(),
required=True)
dispositivo_search_form = forms.CharField(widget=forms.HiddenInput(),
required=False)
@ -1391,11 +1399,12 @@ class DispositivoRegistroRevogacaoForm(Form):
'dispositivo_revogado',
data_sapl_ta='DispositivoSearch',
data_field='dispositivo_revogado',
data_type_selection='radio',
data_type_selection='checkbox',
template="compilacao/layout/dispositivo_radio.html")
layout.append(Fieldset(_('Registro de Revogação - '
'Seleção do Dispositivo a ser Revogado'),
Field(InlineRadios('revogacao_em_bloco')),
row_dispositivo,
css_class="col-md-12"))
layout.append(Field('dispositivo_search_form'))
@ -1439,7 +1448,7 @@ class DispositivoRegistroInclusaoForm(Form):
'dispositivo_base_para_inclusao',
data_sapl_ta='DispositivoSearch',
data_field='dispositivo_base_para_inclusao',
data_type_selection='radio',
data_type_selection='checkbox',
template="compilacao/layout/dispositivo_radio.html")
layout.append(Fieldset(_('Registro de Inclusão - '

22
sapl/compilacao/models.py

@ -187,7 +187,7 @@ class TextoArticulado(TimestampedMixin):
ementa = models.TextField(verbose_name=_('Ementa'))
observacao = models.TextField(blank=True, verbose_name=_('Observação'))
numero = models.CharField(
max_length=8,verbose_name=_('Número'))
max_length=8, verbose_name=_('Número'))
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'))
tipo_ta = models.ForeignKey(
TipoTextoArticulado,
@ -1386,28 +1386,30 @@ class Dispositivo(BaseModel, TimestampedMixin):
return result
def criar_espaco(self, espaco_a_criar, local):
def criar_espaco(self, espaco_a_criar, local=None):
if local == 'json_add_next':
proximo_bloco = Dispositivo.objects.filter(
ordem__gt=self.ordem,
nivel__lte=self.nivel,
ta_id=self.ta_id)[:1]
ta_id=self.ta_id).first()
elif local == 'json_add_in':
# FIXME: o exclude não deve estar limitado a uma class_css caput e
# sim a qualquer filho de inserção automática
proximo_bloco = Dispositivo.objects.filter(
ordem__gt=self.ordem,
nivel__lte=self.nivel + 1,
ta_id=self.ta_id).exclude(
tipo_dispositivo__class_css='caput')[:1]
ta_id=self.ta_id).exclude(auto_inserido=True).first()
elif local == 'json_add_in_with_auto':
proximo_bloco = Dispositivo.objects.filter(
ordem__gt=self.ordem,
nivel__lte=self.nivel + 1,
ta_id=self.ta_id).first()
else:
proximo_bloco = Dispositivo.objects.filter(
ordem__gte=self.ordem,
ta_id=self.ta_id)[:1]
ta_id=self.ta_id).first()
if proximo_bloco.exists():
ordem = proximo_bloco[0].ordem
if proximo_bloco:
ordem = proximo_bloco.ordem
proximo_bloco = Dispositivo.objects.order_by('-ordem').filter(
ordem__gte=ordem,
ta_id=self.ta_id)

141
sapl/compilacao/views.py

@ -9,10 +9,12 @@ from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.core.signing import Signer
from django.core.urlresolvers import reverse, reverse_lazy
from django.db import transaction
from django.db.models import Q
from django.db.models.query import QuerySet
from django.http.response import (HttpResponse, HttpResponseRedirect,
JsonResponse, Http404)
from django.shortcuts import get_object_or_404, redirect
@ -1525,6 +1527,13 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
return data
def remover_dispositivo(self, base, bloco):
if base.tipo_dispositivo.dispositivo_de_alteracao:
bloco = False
for d in base.dispositivos_alterados_set.all():
d.refresh_from_db()
self.remover_dispositivo(d, bloco)
username = self.request.user.username
base_ordem = base.ordem
if base.dispositivo_subsequente or base.dispositivo_substituido:
@ -1836,7 +1845,10 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin):
dpts = base.dispositivos_alterados_set.all().order_by(
'-ordem_bloco_atualizador')
for dpt in dpts:
self.remover_dispositivo(dpt, False)
try:
self.remover_dispositivo(dpt, False)
except Exception as e:
print(e)
if base.pk:
"""
@ -2585,17 +2597,20 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
return self.json_add_next_registra_inclusao(
context, local_add='json_add_in')
def registra_revogacao(self, bloco_alteracao, dispositivo_a_revogar):
def registra_revogacao(self, bloco_alteracao, dsp_a_rev, em_bloco=False):
return self.registra_alteracao(
bloco_alteracao,
dispositivo_a_revogar,
revogacao=True
dsp_a_rev,
revogacao=True,
em_bloco=em_bloco
)
def registra_alteracao(self,
bloco_alteracao,
dispositivo_a_alterar,
revogacao=False):
dsp_a_alterar,
revogacao=False,
em_bloco=False):
"""
Caracteristicas:
1 - Se é um dispositivo simples e sem subsequente
@ -2621,14 +2636,69 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
data.update({'pk': bloco_alteracao.pk,
'pai': [bloco_alteracao.pk, ]})
history = dispositivo_a_alterar.history()
if isinstance(dsp_a_alterar, list):
dsps = Dispositivo.objects.filter(id__in=dsp_a_alterar)
dsps_ids = set()
for d in dsps:
ds = d
while ds.dispositivo_subsequente:
ds = ds.dispositivo_subsequente
dsps_ids.add(ds.pk)
if em_bloco:
proximo_bloco = Dispositivo.objects.filter(
ordem__gt=ds.ordem,
nivel__lte=ds.nivel,
ta_id=ds.ta_id).first()
params = {
'ta_id': ds.ta_id,
'nivel__gte': ds.nivel,
'ordem__gte': ds.ordem,
'dispositivo_subsequente__isnull': True
}
if proximo_bloco:
params['ordem__lt'] = proximo_bloco.ordem
bloco = Dispositivo.objects.filter(
**params).values_list('id', 'auto_inserido')
for id, auto in bloco:
if auto:
dsp_pai = Dispositivo.objects.filter(
pk=id
).values_list('dispositivo_pai', flat=True).first()
if dsp_pai in dsps_ids:
dsps_ids.remove(dsp_pai)
dsps_ids.add(id)
dsps_ids = Dispositivo.objects.filter(
id__in=dsps_ids
).values_list('id', flat="True")
for dsp in dsps_ids:
with transaction.atomic():
data.update(
self.registra_alteracao(
bloco_alteracao,
dsp,
revogacao
)
)
if 'message' in data and 'danger' in data['message']['type']:
return data
return data
dsp_a_alterar = Dispositivo.objects.get(
pk=dsp_a_alterar)
for d in history:
history = dsp_a_alterar.history()
for d in list(history):
if d.inicio_vigencia <= bloco_alteracao.inicio_vigencia:
dispositivo_a_alterar = d
dsp_a_alterar = d
break
if (dispositivo_a_alterar.inicio_vigencia >
if (dsp_a_alterar.inicio_vigencia >
bloco_alteracao.inicio_vigencia):
self.set_message(
data, 'danger',
@ -2637,7 +2707,7 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
'Alterador!'), time=10000)
return data
if dispositivo_a_alterar.tipo_dispositivo.dispositivo_de_articulacao\
if dsp_a_alterar.tipo_dispositivo.dispositivo_de_articulacao\
and not revogacao:
self.set_message(
data, 'warning',
@ -2647,13 +2717,13 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
'para o dispositivo que se quer alterar.'), modal=True)
ndp = Dispositivo.new_instance_based_on(
dispositivo_a_alterar, dispositivo_a_alterar.tipo_dispositivo)
ndp.auto_inserido = dispositivo_a_alterar.auto_inserido
ndp.rotulo = dispositivo_a_alterar.rotulo
dsp_a_alterar, dsp_a_alterar.tipo_dispositivo)
ndp.auto_inserido = dsp_a_alterar.auto_inserido
ndp.rotulo = dsp_a_alterar.rotulo
ndp.publicacao = bloco_alteracao.publicacao
if not revogacao:
ndp.texto = dispositivo_a_alterar.texto
ndp.texto = dsp_a_alterar.texto
else:
ndp.texto = Dispositivo.TEXTO_PADRAO_DISPOSITIVO_REVOGADO
ndp.dispositivo_de_revogacao = True
@ -2668,15 +2738,15 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
ndp.inicio_vigencia = bloco_alteracao.inicio_eficacia
try:
ordem = dispositivo_a_alterar.criar_espaco(
espaco_a_criar=1, local='json_add_in')
ordem = dsp_a_alterar.criar_espaco(
espaco_a_criar=1, local='json_add_in_with_auto')
ndp.ordem = ordem
ndp.dispositivo_atualizador = bloco_alteracao
ndp.ta_publicado = bloco_alteracao.ta
p = dispositivo_a_alterar
n = dispositivo_a_alterar.dispositivo_subsequente
p = dsp_a_alterar
n = dsp_a_alterar.dispositivo_subsequente
ndp.dispositivo_substituido = p
ndp.dispositivo_subsequente = n
@ -2711,7 +2781,7 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
n.dispositivo_substituido = ndp
n.save()
filhos_diretos = dispositivo_a_alterar.dispositivos_filhos_set
filhos_diretos = dsp_a_alterar.dispositivos_filhos_set
for d in filhos_diretos.all():
d.dispositivo_pai = ndp
d.save()
@ -2728,14 +2798,20 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
self.set_message(
data, 'success',
_('Dispositivo de Revogação adicionado com sucesso.'))
# data.update({'pk': ndp.pk,
# 'pai': [bloco_alteracao.pk, ]})
except ValidationError as ve:
self.set_message(
data, 'danger',
_('O dispositivo ({} - {}) já existe neste bloco.'.format(
ndp.tipo_dispositivo,
ndp.get_nomenclatura_completa())), time=10000)
except Exception as e:
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
print(e)
data.update({'pk': ndp.pk,
'pai': [bloco_alteracao.pk, ]})
self.set_message(
data, 'danger',
_('Não é foi possível registrar sua solicitação!'), time=10000)
return data
@ -2836,17 +2912,16 @@ class DispositivoDinamicEditView(
formtype = request.POST['formtype']
if formtype == 'get_form_alteracao':
dispositivo_a_alterar = Dispositivo.objects.get(
pk=request.POST['dispositivo_alterado'])
data = self.registra_alteracao(d, dispositivo_a_alterar)
data = self.registra_alteracao(
d, request.POST.getlist('dispositivo_alterado[]', []))
elif formtype == 'get_form_revogacao':
dispositivo_a_revogar = Dispositivo.objects.get(
pk=request.POST['dispositivo_revogado'])
data = self.registra_revogacao(d, dispositivo_a_revogar)
data = self.registra_revogacao(
d,
request.POST.getlist('dispositivo_revogado[]', []),
request.POST.get("revogacao_em_bloco") == "True"
)
if formtype == 'get_form_inclusao':

39
sapl/static/js/app.js

@ -178,30 +178,39 @@ function OptionalCustomFrontEnd() {
instance.customCheckBoxAndRadioWithoutLabel = function() {
$('[type=radio], [type=checkbox]').each(function() {
var _this = $(this);
var _label = _this.closest('label');
if (_label.length)
return;
let _this = $(this)
if (this.id === undefined || this.id.length === 0) {
return
}
let _label = _this.closest('label')
if (this.id)
if (_label.length === 0) {
_label = $('label[for='+this.id+']');
else {
_label = $('<label/>').insertBefore(this)
if (_label.length === 0) {
_label = $('<label[for='+this.id+']/>').insertBefore(this)
}
}
/*var _controls = _label.closest('.controls');
if (_label.length) {
/*var _controls = _label.closest('.controls');
if (!_controls.length) {
_controls = $('<div class="controls"/>').insertBefore(_label)
_controls.append(_label)
}*/
if (!_controls.length) {
_controls = $('<div class="controls"/>').insertBefore(_label)
_controls.append(_label)
}*/
if (this.type === "checkbox") {
_label.addClass('checkbox-inline');
_label.prepend(_this);
_this.checkbox();
}
else if (this.type === "radio") {
_label.addClass('radio-inline');
_label.prepend(_this);
_this.radio();
}
});
}
instance.init = function() {

51
sapl/static/js/compilacao.js

@ -24,6 +24,7 @@ function insertWaitAjax(element) {
function DispostivoSearch(opts) {
$(function() {
let formData = {}
var container_ds = $('body').children("#container_ds");
if (container_ds.length > 0)
$(container_ds).remove();
@ -67,6 +68,7 @@ function DispostivoSearch(opts) {
onChangeFieldSelects();
var onChangeParamTA = function(event) {
var tipo_ta = $("select[name='tipo_ta']").val();
var tipo_model = $("select[name='tipo_model']").val();
var num_ta = $("input[name='num_ta']").val();
@ -79,15 +81,22 @@ function DispostivoSearch(opts) {
if (rotulo_dispositivo.length > 0 || texto_dispositivo.length > 0) {
$("input[name='dispositivos_internos']").prop('disabled', false);
$("input[name='dispositivos_internos']").each((idx, element) => {
element.parentElement.classList.remove('disabled')
});
$("input[name='dispositivos_internos']").closest('#div_id_dispositivos_internos').css('opacity','1');
}
else {
$("input[name='dispositivos_internos']").filter('[value="False"]').prop('checked', true);
$("input[name='dispositivos_internos']").prop('disabled', true);
$("input[name='dispositivos_internos']").each((idx, element) => {
element.parentElement.classList.add('disabled')
});
$("input[name='dispositivos_internos']").closest('#div_id_dispositivos_internos').css('opacity','0.3');
dispositivos_internos = 'False';
}
var formData = {
formData = {
'tipo_ta' : tipo_ta,
'tipo_model' : tipo_model,
'num_ta' : num_ta,
@ -101,12 +110,15 @@ function DispostivoSearch(opts) {
'data_function' : data_function,
};
window.localStorage.setItem("dispositivo_search_form_data", JSON.stringify(formData))
url = '/ta/search_fragment_form';
$('.result-busca-dispositivo').html('');
insertWaitAjax('.result-busca-dispositivo')
$.get(url, formData).done(function( data ) {
$('.result-busca-dispositivo').html(data);
//OptionalCustomFrontEnd().init();
if (data_type_selection == 'checkbox') {
var tas = $('.result-busca-dispositivo').find('input[name="ta_select_all"]');
tas.off();
@ -125,11 +137,17 @@ function DispostivoSearch(opts) {
if (rotulo_dispositivo.length > 0 || texto_dispositivo.length > 0) {
$("input[name='dispositivos_internos']").prop('disabled', false);
$("input[name='dispositivos_internos']").each((idx, element) => {
element.parentElement.classList.remove('disabled')
});
$("input[name='dispositivos_internos']").closest('#div_id_dispositivos_internos').css('opacity','1');
}
else {
$("input[name='dispositivos_internos']").filter('[value="False"]').prop('checked', true);
$("input[name='dispositivos_internos']").prop('disabled', true);
$("input[name='dispositivos_internos']").each((idx, element) => {
element.parentElement.classList.add('disabled')
});
$("input[name='dispositivos_internos']").closest('#div_id_dispositivos_internos').css('opacity','0.3');
dispositivos_internos = 'False';
}
@ -150,6 +168,7 @@ function DispostivoSearch(opts) {
$.get(opts['url_form'], function(data) {
container_ds.html(data);
var modal_ds = $('#modal-ds');
OptionalCustomFrontEnd().init();
modal_ds.find("select[name='tipo_ta']").change(function(event) {
var url = '';
@ -166,6 +185,9 @@ function DispostivoSearch(opts) {
for (var i in data[item])
select.append($("<option>").attr('value',i).text(data[item][i]));
}
setTimeout(function() {
$("select[name='tipo_model']").val(formData.tipo_model);
}, 200)
//select.change(onChangeParamTA)
});
});
@ -222,8 +244,31 @@ function DispostivoSearch(opts) {
});
try {
formData = JSON.parse(window.localStorage.getItem("dispositivo_search_form_data"))
$("input[name='num_ta']").val(formData.num_ta);
$("input[name='ano_ta']").val(formData.ano_ta);
$("input[name='rotulo_dispositivo']").val(formData.rotulo);
$("input[name='texto_dispositivo']").val(formData.texto);
$("select[name='max_results']").val(formData.max_results);
} catch (e) {
}
setTimeout(function() {
try {
$("select[name='tipo_ta']").val(formData.tipo_ta);
$("select[name='tipo_ta']").trigger('change')
//modal_ds.find(".btn-busca").trigger('click')
//onChangeParamTA();
} catch (e) {
}
}, 200)
modal_ds.modal('show');
onChangeParamTA();
})
});
});

41
sapl/static/js/compilacao_edit.js

@ -167,6 +167,7 @@ function DispositivoEdit() {
instance.scrollTo(_this);
dpt_form.submit(instance.onSubmitFormRegistraRevogacao);
var btn_fechar = _this.find('.btn-fechar');
btn_fechar.on('click', function() {
instance.clearEditSelected();
@ -228,6 +229,7 @@ function DispositivoEdit() {
if (editortype == 'tinymce' ) {
initTinymce();
}
OptionalCustomFrontEnd().init();
}
dpt.trigger(trigger);
}).always(function() {
@ -304,16 +306,29 @@ function DispositivoEdit() {
instance.onSubmitFormRegistraAlteracao = function(event) {
var _this = this;
if (this.dispositivo_alterado === undefined) {
instance.modalMessage('Nenhum dispositivo selecionado', 'alert-info')
if (event != null)
event.preventDefault();
return
}
var dispositivo_alterado = this.dispositivo_alterado.length === undefined ? [this.dispositivo_alterado, ] : Array.from(this.dispositivo_alterado)
var form_data = {
'csrfmiddlewaretoken' : this['csrfmiddlewaretoken'].value,
'dispositivo_alterado' : this['dispositivo_alterado'].value,
'csrfmiddlewaretoken' : this.csrfmiddlewaretoken.value,
'dispositivo_alterado' : dispositivo_alterado.filter(
function(elem, idx, array) {
return elem.checked
}
).map(function(dsp) {
return dsp.value
}),
'formtype': 'get_form_alteracao',
};
var url = $(this).closest('.dpt').attr( "pk" )+'/refresh';
instance.waitShow();
$.post(url, form_data)
$.post(url, form_data, dataType="json")
.done(function(data) {
instance.clearEditSelected();
@ -364,11 +379,27 @@ function DispositivoEdit() {
instance.onSubmitFormRegistraRevogacao = function(event) {
var _this = this;
if (this.dispositivo_revogado === undefined) {
instance.modalMessage('Nenhum dispositivo selecionado', 'alert-info')
if (event != null)
event.preventDefault();
return
}
var dispositivo_revogado = this.dispositivo_revogado.length === undefined ? [this.dispositivo_revogado, ] : Array.from(this.dispositivo_revogado)
var form_data = {
'csrfmiddlewaretoken' : this['csrfmiddlewaretoken'].value,
'dispositivo_revogado' : this['dispositivo_revogado'].value,
'csrfmiddlewaretoken' : this.csrfmiddlewaretoken.value,
'dispositivo_revogado' : dispositivo_revogado.filter(
function(elem, idx, array) {
return elem.checked
}
).map(function(dsp) {
return dsp.value
}),
'revogacao_em_bloco': this.revogacao_em_bloco.value,
'formtype': 'get_form_revogacao',
};
var url = $(this).closest('.dpt').attr( "pk" )+'/refresh';
instance.waitShow();

2
sapl/templates/compilacao/ajax_form.html

@ -1,2 +1,2 @@
{% load crispy_forms_tags %}
{% crispy form form.helper%}
{% crispy form form.helper%}
Loading…
Cancel
Save