diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py index 2d0d8450a..c4e4dce43 100644 --- a/sapl/compilacao/forms.py +++ b/sapl/compilacao/forms.py @@ -1207,3 +1207,55 @@ class TextNotificacoesForm(Form): self.helper.layout = Layout(field_type_notificacoes) super(TextNotificacoesForm, self).__init__(*args, **kwargs) + + +class DispositivoRegistroAlteracaoForm(Form): + + dispositivo_alterado = forms.ModelChoiceField( + label=_('Dispositivo a ser alterado'), + required=False, + queryset=Dispositivo.objects.all()) + + dispositivo_search_form = forms.CharField(widget=forms.HiddenInput(), + required=False) + + def __init__(self, *args, **kwargs): + + layout = [] + kwargs.pop('instance') + kwargs['initial'].pop('editor_type') + + row_dispositivo = Field( + 'dispositivo_alterado', + data_sapl_ta='DispositivoSearch', + data_field='dispositivo_alterado', + data_type_selection='radio', + template="compilacao/layout/dispositivo_radio.html") + + layout.append(Fieldset(_('Registro de Alteração - Seleção do Dispositivo a ser alterado'), + row_dispositivo, + css_class="col-md-12")) + layout.append(Field('dispositivo_search_form')) + + more = [ + HTML('%s' % + _('Cancelar')), + ] + more.append(Submit('salvar', _('Salvar'), css_class='pull-right')) + + buttons = FormActions(*more, css_class='form-group') + + _fields = [Div(*layout, css_class="row-fluid")] + \ + [to_row([(buttons, 12)])] + + self.helper = FormHelper() + self.helper.layout = Layout(*_fields) + + super(DispositivoRegistroAlteracaoForm, self).__init__(*args, **kwargs) + + self.fields['dispositivo_alterado'].choices = [] + + def save(self): + super(DispositivoRegistroAlteracaoForm, self).save() + + data = self.cleaned_data diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py index df7491d13..129e88d44 100644 --- a/sapl/compilacao/models.py +++ b/sapl/compilacao/models.py @@ -930,6 +930,8 @@ class Dispositivo(BaseModel, TimestampedMixin): nivel__lte=self.nivel, ta_id=self.ta_id)[:1] 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, @@ -951,7 +953,7 @@ class Dispositivo(BaseModel, TimestampedMixin): ordem=F('ordem') + ( Dispositivo.INTERVALO_ORDEM * espaco_a_criar - 1)) else: - # inserção no fim da ta + # inserção no fim do ta ordem_max = Dispositivo.objects.order_by( 'ordem').filter( ta_id=self.ta_id).aggregate( @@ -1167,7 +1169,7 @@ class Dispositivo(BaseModel, TimestampedMixin): else: dp.inicio_eficacia = dispositivo_base.inicio_eficacia dp.inicio_vigencia = dispositivo_base.inicio_vigencia - dp.fim_eficacia = dispositivo_base.inicio_eficacia + dp.fim_eficacia = dispositivo_base.fim_eficacia dp.fim_vigencia = dispositivo_base.fim_vigencia dp.ordem = dispositivo_base.ordem diff --git a/sapl/compilacao/views.py b/sapl/compilacao/views.py index 1e88fc942..1d913c0df 100644 --- a/sapl/compilacao/views.py +++ b/sapl/compilacao/views.py @@ -30,7 +30,7 @@ from sapl.compilacao.forms import ( DispositivoEdicaoVigenciaForm, DispositivoSearchModalForm, NotaForm, PublicacaoForm, TaForm, TextNotificacoesForm, - TipoTaForm, VideForm) + TipoTaForm, VideForm, DispositivoRegistroAlteracaoForm) from sapl.compilacao.models import ( Dispositivo, Nota, PerfilEstruturalTextoArticulado, Publicacao, @@ -1162,11 +1162,9 @@ class ActionDeleteDispositivoMixin(ActionsCommonsMixin): data['pai'] = [base.get_raiz().pk] - """nivel = sys.maxsize - for b in bases_atualizacao: - if b.nivel < nivel: - data['pai'].append(b.pk) - nivel = b.nivel""" + if ta_base.id != int(self.kwargs['ta_id']): + data['pai'] = [base.dispositivo_atualizador.pk] + data['pk'] = base.dispositivo_atualizador.pk try: with transaction.atomic(): @@ -2052,12 +2050,103 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin, return perfis[0].pk return None + def registra_alteracao(self, bloco_alteracao, dispositivo_a_alterar): + """ + Caracteristicas: + 1 - Se é um dispositivo simples e sem subsequente + - filhos devem ser transferidos + + 2 - Se é um dispositivo simples com subsequente + - não deveria ter filhos locais + - substituidos e subsequentes devem ser religados + + 3 - Se é um dispositivo articulado e sem subsequente + - filhos automáticos não podem ser transferidos + - filhos locais devem ser transferidos + + 4 - Se é um dispositivo articulado com subsequente + - filhos automáticos não devem ser transferidos + - não deveria ter filhos locais + """ + + perfil_pk = self.request.session['perfil_estrutural'] + + """Se o usuário selecionar um dispositivo de auto inserção, + como um caput, por exemplo, a alteração é + migrada para o pai imediato""" + if dispositivo_a_alterar.is_relative_auto_insert(perfil_pk=perfil_pk): + dispositivo_a_alterar = dispositivo_a_alterar.dispositivo_pai + + if dispositivo_a_alterar.tipo_dispositivo.dispositivo_de_articulacao: + pass + + else: + ndp = Dispositivo.new_instance_based_on( + dispositivo_a_alterar, dispositivo_a_alterar.tipo_dispositivo) + + ndp.rotulo = dispositivo_a_alterar.rotulo + ndp.texto = dispositivo_a_alterar.texto + ndp.publicacao = bloco_alteracao.publicacao + + ndp.dispositivo_vigencia = bloco_alteracao.dispositivo_vigencia + if ndp.dispositivo_vigencia: + ndp.inicio_eficacia = ndp.dispositivo_vigencia.inicio_eficacia + ndp.inicio_vigencia = ndp.dispositivo_vigencia.inicio_vigencia + else: + ndp.inicio_eficacia = bloco_alteracao.inicio_eficacia + ndp.inicio_vigencia = bloco_alteracao.inicio_vigencia + + try: + with transaction.atomic(): + ordem = dispositivo_a_alterar.criar_espaco( + espaco_a_criar=1, local='json_add_in') + + ndp.ordem = ordem + ndp.dispositivo_atualizador = bloco_alteracao + ndp.ta_publicado = bloco_alteracao.ta + + p = dispositivo_a_alterar + n = dispositivo_a_alterar.dispositivo_subsequente + + ndp.dispositivo_substituido = p + ndp.dispositivo_subsequente = n + + if n: + ndp.fim_eficacia = n.inicio_eficacia - \ + timedelta(days=1) + ndp.fim_vigencia = n.inicio_vigencia - \ + timedelta(days=1) + ndp.save() + + p.dispositivo_subsequente = ndp + p.fim_eficacia = ndp.inicio_eficacia - timedelta(days=1) + p.fim_vigencia = ndp.inicio_vigencia - timedelta(days=1) + p.save() + + if n: + n.dispositivo_substituido = ndp + n.save() + + filhos_diretos = dispositivo_a_alterar.dispositivos_filhos_set + for d in filhos_diretos.all(): + d.dispositivo_pai = ndp + d.save() + + except Exception as e: + print(e) + + data = {'pk': ndp.pk, + 'pai': [bloco_alteracao.pk, ]} + + return data + class DispositivoDinamicEditView( CompMixin, ActionsEditMixin, TextEditView, UpdateView): template_name = 'compilacao/text_edit_bloco.html' model = Dispositivo form_class = DispositivoEdicaoBasicaForm + contador = -1 def get_initial(self): initial = UpdateView.get_initial(self) @@ -2066,21 +2155,38 @@ class DispositivoDinamicEditView( if 'action' in self.request.GET: initial.update({'editor_type': self.request.GET['action']}) + + initial.update({'dispositivo_search_form': reverse_lazy( + 'sapl.compilacao:dispositivo_search_form')}) return initial + def get_form(self, form_class=None): + + if self.action and self.action.startswith('get_form_'): + if form_class is None: + form_class = self.get_form_class() + return form_class(**self.get_form_kwargs()) + else: + return None + def get(self, request, *args, **kwargs): + if 'action' not in request.GET: + self.action = None self.template_name = 'compilacao/text_edit_bloco.html' return TextEditView.get(self, request, *args, **kwargs) self.template_name = 'compilacao/ajax_form.html' - action = request.GET['action'] + self.action = request.GET['action'] - if action.startswith('get_form_'): - self.form_class = DispositivoEdicaoBasicaForm + if self.action.startswith('get_form_'): + if self.action.endswith('_base'): + self.form_class = DispositivoEdicaoBasicaForm + elif self.action.endswith('_alteracao'): + self.form_class = DispositivoRegistroAlteracaoForm context = self.get_context_data() return self.render_to_response(context) - elif action.startswith('get_actions'): + elif self.action.startswith('get_actions'): self.form_class = None self.template_name = 'compilacao/ajax_actions_dinamic_edit.html' self.object = Dispositivo.objects.get( @@ -2101,7 +2207,7 @@ class DispositivoDinamicEditView( return self.render_to_response(context) - elif action.startswith('json_'): + elif self.action.startswith('json_'): context = self.get_context_data() return self.render_to_json_response(context) @@ -2112,56 +2218,68 @@ class DispositivoDinamicEditView( d = Dispositivo.objects.get( pk=self.kwargs['dispositivo_id']) - texto = request.POST['texto'].strip() - texto_atualizador = request.POST['texto_atualizador'].strip() - texto_atualizador = texto_atualizador \ - if texto != texto_atualizador else '' - visibilidade = request.POST['visibilidade'] - - # if d.texto != '': - # d.texto = texto - # d.save() - # return self.get(request, *args, **kwargs) - d_texto = d.texto - d.texto = texto.strip() - d.texto_atualizador = texto_atualizador.strip() - d.visibilidade = not visibilidade or visibilidade == 'True' - d.save() - - if texto != '' and d.ta_id == int(self.kwargs['ta_id']): - dnext = Dispositivo.objects.filter( - ta_id=d.ta_id, - ordem__gt=d.ordem, - texto='', - tipo_dispositivo__dispositivo_de_articulacao=False)[:1] - - if not dnext.exists(): - dnext = [] - dnext.append(d) - pais = [d.dispositivo_pai_id, ] - else: - - if dnext[0].nivel > d.nivel: - pais = [d.pk, ] + 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) + + self.set_message( + data, 'success', + _('Dispositivo de Alteração adicionado com sucesso.')) + elif formtype == 'get_form_base': + texto = request.POST['texto'].strip() + texto_atualizador = request.POST['texto_atualizador'].strip() + texto_atualizador = texto_atualizador \ + if texto != texto_atualizador else '' + visibilidade = request.POST['visibilidade'] + + # if d.texto != '': + # d.texto = texto + # d.save() + # return self.get(request, *args, **kwargs) + d_texto = d.texto + d.texto = texto.strip() + d.texto_atualizador = texto_atualizador.strip() + d.visibilidade = not visibilidade or visibilidade == 'True' + d.save() + + if texto != '' and d.ta_id == int(self.kwargs['ta_id']): + dnext = Dispositivo.objects.filter( + ta_id=d.ta_id, + ordem__gt=d.ordem, + texto='', + tipo_dispositivo__dispositivo_de_articulacao=False)[:1] + + if not dnext.exists(): + dnext = [] + dnext.append(d) + pais = [d.dispositivo_pai_id, ] else: - if dnext[0].dispositivo_pai_id == d.dispositivo_pai_id: - pais = [dnext[0].dispositivo_pai_id, ] + + if dnext[0].nivel > d.nivel: + pais = [d.pk, ] else: - pais = [ - dnext[0].dispositivo_pai_id, - d.dispositivo_pai_id] - - data = {'pk': dnext[0].pk - if not d_texto else 0, 'pai': pais} - elif d.ta_id != int(self.kwargs['ta_id']): - data = {'pk': 0, - 'pai': [d.dispositivo_atualizador_id, ]} - else: - data = {'pk': d.pk - if not d_texto or not d.texto else 0, 'pai': [d.pk, ]} + if dnext[0].dispositivo_pai_id == d.dispositivo_pai_id: + pais = [dnext[0].dispositivo_pai_id, ] + else: + pais = [ + dnext[0].dispositivo_pai_id, + d.dispositivo_pai_id] + + data = {'pk': dnext[0].pk + if not d_texto else 0, 'pai': pais} + elif d.ta_id != int(self.kwargs['ta_id']): + data = {'pk': 0, + 'pai': [d.dispositivo_atualizador_id, ]} + else: + data = {'pk': d.pk + if not d_texto or not d.texto else 0, 'pai': [d.pk, ]} - self.set_message(data, 'success', - _('Dispositivo alterado com sucesso.')) + self.set_message(data, 'success', + _('Dispositivo alterado com sucesso.')) return JsonResponse(data, safe=False) diff --git a/sapl/static/js/compilacao_edit.js b/sapl/static/js/compilacao_edit.js index c0c84d76d..f653dce3c 100644 --- a/sapl/static/js/compilacao_edit.js +++ b/sapl/static/js/compilacao_edit.js @@ -35,23 +35,24 @@ function DispositivoEdit() { 'variacao' : this.getAttribute('variacao'), }; - if (pk !== undefined) { - var url = pk+'/refresh'; - instance.waitShow(); + var url = pk+'/refresh'; + instance.waitShow(); - $.get(url, form_data).done(function(data) { - instance.clearEditSelected(); - instance.waitHide(); - if (data.pk != null) { - if (data.message === undefined) - instance.refreshScreenFocusPk(data); - else if (instance.modalMessage(data.message.value, 'alert-'+data.message.type, function() { - //instance.waitHide(); - })) - instance.refreshScreenFocusPk(data); + $.get(url, form_data).done(function(data) { + instance.clearEditSelected(); + instance.waitHide(); + if (data.pk != null) { + if (data.message !== undefined) { + if (data.message.type == 'danger') + instance.modalMessage(data.message.value, 'alert-'+data.message.type, null); + else { + instance.message(data) + } } - }); - } + instance.refreshScreenFocusPk(data); + } + }).fail(instance.waitHide) + .always(instance.waitHide); } instance.clearEditSelected = function() { @@ -81,10 +82,7 @@ function DispositivoEdit() { instance.loadActionsEdit(dpt); var formtype = dpt.attr('formtype'); - - dpt.on(formtype, instance[formtype]); - instance.loadForm(dpt, formtype); } @@ -104,11 +102,33 @@ function DispositivoEdit() { }); var btns_excluir = _this.find('.btns-excluir'); - _this.find('.dpt-actions-bottom').last().append(btns_excluir); + _this.find('.dpt-actions-bottom').first().append(btns_excluir); btns_excluir.find('.btn-excluir').on('click', instance.bindActionsClick); } + instance.get_form_alteracao = function () { + var _this = $(this); + _this.off('get_form_alteracao'); + $('.dpt-actions, .dpt-actions-bottom').html(''); + + var dpt_form = _this.children().filter('.dpt-form').children().first(); + var url_search = dpt_form[0]['id_dispositivo_search_form'].value; + DispostivoSearch({ + 'url_form': url_search, + 'text_button': 'Selecionar' + }); + + instance.scrollTo(_this); + dpt_form.submit(instance.onSubmitFormRegistraAlteracao); + + var btn_fechar = _this.find('.btn-fechar'); + btn_fechar.on('click', function() { + instance.clearEditSelected(); + instance.triggerBtnDptEdit(_this.attr('pk')); + }); + } + instance.loadActionsEdit = function(dpt) { var pk = dpt.attr('pk'); var url = pk+'/refresh?action=get_actions'; @@ -116,13 +136,19 @@ function DispositivoEdit() { dpt.find('.dpt-actions').first().html(data); dpt.find('.btn-inserts').on('click', instance.bindActionsClick); dpt.find('.btn-perfis').on('click', instance.bindActionsClick); + dpt.find('.btn-compila').on('click', instance.loadFormsCompilacao); dpt.find('.btn-editor-type').on('click', instance.bindActionsEditorType); if (editortype == 'construct') dpt.find('.btn-group-inserts').first().addClass('open'); + dpt.find('.btn-group-inserts button').mouseenter(function(event) { + dpt.find('.btn-group-inserts').removeClass('open'); + $(this.parentElement).addClass('open') + }); }); } + instance.loadForm = function(dpt, trigger) { var pk = dpt.attr('pk'); var dpt_form = dpt.children().filter('.dpt-form'); @@ -142,6 +168,13 @@ function DispositivoEdit() { } } + instance.loadFormsCompilacao = function(event) { + var dpt = $(this).closest('.dpt'); + var formtype = this.getAttribute('action'); + dpt.on(formtype, instance[formtype]); + instance.loadForm(dpt, formtype); + } + instance.modalMessage = function(message, alert, closeFunction) { if (message != null && message != '') { $('#modal-message #message').html(message); @@ -184,6 +217,38 @@ function DispositivoEdit() { objects = $(container).find('.btn-dpt-edit'); objects.on('click', instance.editDispositivo); } + + instance.onSubmitFormRegistraAlteracao = function(event) { + var _this = this; + + var form_data = { + 'csrfmiddlewaretoken' : this['csrfmiddlewaretoken'].value, + 'dispositivo_alterado' : this['dispositivo_alterado'].value, + 'formtype': 'get_form_alteracao', + }; + var url = $(this).closest('.dpt').attr( "pk" )+'/refresh'; + + instance.waitShow(); + + $.post(url, form_data) + .done(function(data) { + instance.clearEditSelected(); + + if (data.pk != null) { + instance.refreshScreenFocusPk(data); + instance.message(data); + } + else { + alert('Erro na resposta!'); + } + + }).always(function() { + instance.waitHide(); + }); + if (event != null) + event.preventDefault(); + + } instance.onSubmitEditFormBase = function(event) { var _this = this; @@ -210,7 +275,8 @@ function DispositivoEdit() { 'csrfmiddlewaretoken' : this['csrfmiddlewaretoken'].value, 'texto' : texto, 'texto_atualizador' : texto_atualizador, - 'visibilidade' : visibilidade + 'visibilidade' : visibilidade, + 'formtype': 'get_form_base', }; var url = $(this).closest('.dpt').attr( "pk" )+'/refresh'; diff --git a/sapl/static/styles/compilacao.scss b/sapl/static/styles/compilacao.scss index 553b0efb9..839fc6677 100644 --- a/sapl/static/styles/compilacao.scss +++ b/sapl/static/styles/compilacao.scss @@ -537,6 +537,10 @@ a:link:after, a:visited:after { } .btn-dpt-edit.btn-default { color: #333; + &:hover { + color: #fff; + background-color: #02baf2; + } } } & > .dpt-actions, & > .dpt-actions-bottom { @@ -545,6 +549,7 @@ a:link:after, a:visited:after { & > .dpt-text { cursor: pointer; min-height: 30px; + border: 1px solid transparent; &:hover { background-color: rgba(0, 0, 0, 0.01); color: $color_buttons; @@ -639,9 +644,10 @@ a:link:after, a:visited:after { border-radius: 3px; z-index: 4; & > .dpt-text { + border: 1px solid transparent; &:hover { + border: 1px solid transparent; background-color: rgba(0, 0, 0, 0.0); - border: 0px solid #eee; } } & > .dpt-form { @@ -671,17 +677,18 @@ a:link:after, a:visited:after { } .dpt-block { border-top: 1px solid #e5e5e5 !important; - opacity: 0.3; + opacity: 0.6; + transition: opacity 0.4s ease; &:hover { opacity: 1; } } .dpt { &:only-child { - border-bottom: 1px solid #e5e5e5 !important; + /*border-bottom: 1px solid #e5e5e5 !important;*/ } &:not(:last-child) { - border-bottom: 1px solid #e5e5e5 !important; + /*border-bottom: 1px solid #e5e5e5 !important;*/ } } .dpt-text { @@ -1388,8 +1395,10 @@ a:link:after, a:visited:after { clear:both; } -.mce-panel { - /*border: 0px solid #ccc !important;*/ +.mce-tinymce.mce-container { + border: 1px solid #ccc !important; + + margin-right: 2px; } .mce-btn button:hover { background-color: rgba(0,0,0,0.1) !important; diff --git a/sapl/templates/compilacao/ajax_actions_dinamic_edit.html b/sapl/templates/compilacao/ajax_actions_dinamic_edit.html index be75c28e9..45c3f284c 100644 --- a/sapl/templates/compilacao/ajax_actions_dinamic_edit.html +++ b/sapl/templates/compilacao/ajax_actions_dinamic_edit.html @@ -4,13 +4,13 @@ {% if object.tipo_dispositivo.dispositivo_de_articulacao and object.tipo_dispositivo.dispositivo_de_alteracao %}