From ff78abb928d5d0289a302a145a888aca5d1ac8b5 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Thu, 24 Dec 2015 20:29:50 -0200 Subject: [PATCH] Issue #76 em progresso MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Controles de Vigências e nomenclaturas de Norma para TextoArticulado --- compilacao/forms.py | 24 ++- .../migrations/0032_auto_20151213_1538.py | 3 +- .../migrations/0039_auto_20151224_1846.py | 19 ++ compilacao/models.py | 1 + compilacao/urls.py | 11 +- compilacao/utils.py | 10 + compilacao/views.py | 198 +++++++++++++++++- norma/migrations/0009_auto_20151224_1637.py | 49 +++++ norma/models.py | 10 +- norma/views.py | 5 +- sapl/crud.py | 8 + .../dispositivo_search_fragment_form.html | 4 +- .../compilacao/{index.html => text_list.html} | 8 +- ...{index_bloco.html => text_list_bloco.html} | 12 +- ...cao.html => text_list_blocoalteracao.html} | 2 +- .../compilacao/textoarticulado_detail.html | 17 +- 16 files changed, 345 insertions(+), 36 deletions(-) create mode 100644 compilacao/migrations/0039_auto_20151224_1846.py create mode 100644 norma/migrations/0009_auto_20151224_1637.py rename templates/compilacao/{index.html => text_list.html} (81%) rename templates/compilacao/{index_bloco.html => text_list_bloco.html} (89%) rename templates/compilacao/{index_bloco_alteracao.html => text_list_blocoalteracao.html} (66%) diff --git a/compilacao/forms.py b/compilacao/forms.py index 11bf4bc1d..e3e5b19f4 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -12,7 +12,7 @@ from django.utils.translation import ugettext_lazy as _ from compilacao import utils, models from compilacao.models import Dispositivo, Nota, TipoNota, TipoVide, Vide,\ TextoArticulado, TipoTextoArticulado -from compilacao.utils import to_row, to_column +from compilacao.utils import to_row, to_column, to_fieldsets from norma.models import TipoNormaJuridica @@ -31,6 +31,21 @@ ta_error_messages = { } +class FormLayout(Layout): + + def __init__(self, *fields): + buttons = Div( + HTML('%s' % _('Cancelar')), + Submit('submit', _('Enviar'), + css_class='button radius success right'), + css_class='radius clearfix' + ) + _fields = list(to_fieldsets(fields)) + \ + [Row(Column(buttons, css_class='clearfix'))] + super(FormLayout, self).__init__(*_fields) + + class TaForm(ModelForm): tipo_ta = forms.ModelChoiceField( label=_('Tipo do Texto Articulado'), @@ -84,15 +99,12 @@ class TaForm(ModelForm): ]) self.helper = FormHelper() - self.helper.layout = Layout( + self.helper.layout = FormLayout( Fieldset(_('Identificação Básica'), row1, css_class="large-12"), Fieldset(_('Ementa'), Column('ementa'), css_class="large-12"), Fieldset( _('Observações'), Column('observacao'), css_class="large-12"), - ButtonHolder( - Submit('submit', _('Salvar'), - css_class='radius') - ) + ) super(TaForm, self).__init__(*args, **kwargs) diff --git a/compilacao/migrations/0032_auto_20151213_1538.py b/compilacao/migrations/0032_auto_20151213_1538.py index db6a23ec7..3bd8555a7 100644 --- a/compilacao/migrations/0032_auto_20151213_1538.py +++ b/compilacao/migrations/0032_auto_20151213_1538.py @@ -13,6 +13,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterUniqueTogether( name='vide', - unique_together=set([('dispositivo_base', 'dispositivo_ref', 'tipo')]), + unique_together=set( + [('dispositivo_base', 'dispositivo_ref', 'tipo')]), ), ] diff --git a/compilacao/migrations/0039_auto_20151224_1846.py b/compilacao/migrations/0039_auto_20151224_1846.py new file mode 100644 index 000000000..51099c44f --- /dev/null +++ b/compilacao/migrations/0039_auto_20151224_1846.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('compilacao', '0038_auto_20151224_1429'), + ] + + operations = [ + migrations.AlterField( + model_name='textoarticulado', + name='tipo_ta', + field=models.ForeignKey(default=None, null=True, to='compilacao.TipoTextoArticulado', blank=True, verbose_name='Tipo de Texto Articulado'), + ), + ] diff --git a/compilacao/models.py b/compilacao/models.py index 2835141b1..908effd82 100644 --- a/compilacao/models.py +++ b/compilacao/models.py @@ -90,6 +90,7 @@ class TextoArticulado(TimestampedMixin): ano = models.PositiveSmallIntegerField(verbose_name=_('Ano')) tipo_ta = models.ForeignKey( TipoTextoArticulado, + blank=True, null=True, default=None, verbose_name=_('Tipo de Texto Articulado')) participacao_social = models.NullBooleanField( default=None, diff --git a/compilacao/urls.py b/compilacao/urls.py index 311c371a0..f6bde1928 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -10,6 +10,12 @@ urlpatterns_compilacao = [ views.TaUpdateView.as_view(), name='ta_edit'), url(r'^(?P[0-9]+)/delete$', views.TaDeleteView.as_view(), name='ta_delete'), + + + url(r'^(?P[0-9]+)/text', + views.TextoView.as_view(), name='ta_text'), + url(r'^(?P[0-9]+)/text/vigencia/(?P.+)/$', + views.TextoView.as_view(), name='ta_vigencia'), ] urlpatterns = [ @@ -18,13 +24,10 @@ urlpatterns = [ """ - url(r'^(?P[0-9]+)/compilacao$', - views.CompilacaoView.as_view(), name='compilacao'), url(r'^(?P[0-9]+)/compilacao/(?P[0-9]+)/$', views.DispositivoView.as_view(), name='dispositivo'), - url(r'^(?P[0-9]+)/compilacao/vigencia/(?P.+)/$', - views.CompilacaoView.as_view(), name='vigencia'), + url(r'^(?P[0-9]+)/compilacao/edit', views.CompilacaoEditView.as_view(), name='comp_edit'), diff --git a/compilacao/utils.py b/compilacao/utils.py index f07d47a07..b5a494ed8 100644 --- a/compilacao/utils.py +++ b/compilacao/utils.py @@ -14,6 +14,16 @@ def to_row(names_spans): return Row(*list(map(to_column, names_spans))) +def to_fieldsets(fields): + for field in fields: + if isinstance(field, list): + legend, *row_specs = field + rows = [to_row(name_span_list) for name_span_list in row_specs] + yield Fieldset(legend, *rows) + else: + yield field + + def make_choices(*choice_pairs): assert len(choice_pairs) % 2 == 0 ipairs = iter(choice_pairs) diff --git a/compilacao/views.py b/compilacao/views.py index b59cbd74b..50105e1dd 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -36,7 +36,7 @@ DISPOSITIVO_SELECT_RELATED = ( 'dispositivo_atualizador', 'dispositivo_atualizador__dispositivo_pai', 'dispositivo_atualizador__dispositivo_pai__ta', - 'dispositivo_atualizador__dispositivo_pai__ta__tipo', + 'dispositivo_atualizador__dispositivo_pai__ta__tipo_ta', 'dispositivo_pai', 'dispositivo_pai__tipo_dispositivo') @@ -102,3 +102,199 @@ class TaDeleteView(DeleteView): def get_success_url(self): return reverse_lazy('ta_list') + + +class TextoView(ListView): + template_name = 'compilacao/text_list.html' + + flag_alteradora = -1 + + flag_nivel_ini = 0 + flag_nivel_old = -1 + + itens_de_vigencia = {} + + inicio_vigencia = None + fim_vigencia = None + + def get_context_data(self, **kwargs): + context = super(TextoView, self).get_context_data(**kwargs) + + cita = Vide.objects.filter( + Q(dispositivo_base__ta_id=self.kwargs['ta_id'])).\ + select_related( + 'dispositivo_ref', + 'dispositivo_ref__ta', + 'dispositivo_ref__dispositivo_pai', + 'dispositivo_ref__dispositivo_pai__ta', 'tipo') + + context['cita'] = {} + for c in cita: + if str(c.dispositivo_base_id) not in context['cita']: + context['cita'][str(c.dispositivo_base_id)] = [] + context['cita'][str(c.dispositivo_base_id)].append(c) + + citado = Vide.objects.filter( + Q(dispositivo_ref__ta_id=self.kwargs['ta_id'])).\ + select_related( + 'dispositivo_base', + 'dispositivo_base__ta', + 'dispositivo_base__dispositivo_pai', + 'dispositivo_base__dispositivo_pai__ta', 'tipo') + + context['citado'] = {} + for c in citado: + if str(c.dispositivo_ref_id) not in context['citado']: + context['citado'][str(c.dispositivo_ref_id)] = [] + context['citado'][str(c.dispositivo_ref_id)].append(c) + + notas = Nota.objects.filter( + dispositivo__ta_id=self.kwargs['ta_id']).select_related( + 'owner', 'tipo') + + context['notas'] = {} + for n in notas: + if str(n.dispositivo_id) not in context['notas']: + context['notas'][str(n.dispositivo_id)] = [] + context['notas'][str(n.dispositivo_id)].append(n) + return context + + def get_queryset(self): + self.flag_alteradora = -1 + self.flag_nivel_ini = 0 + self.flag_nivel_old = -1 + + self.inicio_vigencia = None + self.fim_vigencia = None + if 'sign' in self.kwargs: + signer = Signer() + try: + string = signer.unsign(self.kwargs['sign']).split(',') + self.inicio_vigencia = parse_date(string[0]) + self.fim_vigencia = parse_date(string[1]) + except: + return{} + + return Dispositivo.objects.filter( + inicio_vigencia__lte=self.fim_vigencia, + ordem__gt=0, + ta_id=self.kwargs['ta_id'], + ).select_related(*DISPOSITIVO_SELECT_RELATED) + else: + + r = Dispositivo.objects.filter( + ordem__gt=0, + ta_id=self.kwargs['ta_id'], + ).select_related( + 'tipo_dispositivo', + 'ta_publicado', + 'ta', + 'dispositivo_atualizador', + 'dispositivo_atualizador__dispositivo_pai', + 'dispositivo_atualizador__dispositivo_pai__ta', + 'dispositivo_atualizador__dispositivo_pai__ta__tipo_ta', + 'dispositivo_pai', + 'dispositivo_pai__tipo_dispositivo') + + return r + + def get_vigencias(self): + itens = Dispositivo.objects.filter( + ta_id=self.kwargs['ta_id'], + ).order_by( + 'inicio_vigencia' + ).distinct( + 'inicio_vigencia' + ).select_related( + 'ta_publicado', + 'ta', + 'ta_publicado__tipo_ta', + 'ta__tipo_ta',) + + ajuste_datas_vigencia = [] + + for item in itens: + ajuste_datas_vigencia.append(item) + + lenLista = len(ajuste_datas_vigencia) + for i in range(lenLista): + if i + 1 < lenLista: + ajuste_datas_vigencia[ + i].fim_vigencia = ajuste_datas_vigencia[ + i + 1].inicio_vigencia - timedelta(days=1) + else: + ajuste_datas_vigencia[i].fim_vigencia = None + + self.itens_de_vigencia = {} + + idx = -1 + length = len(ajuste_datas_vigencia) + for item in ajuste_datas_vigencia: + idx += 1 + if idx == 0: + self.itens_de_vigencia[0] = [item, ] + continue + + if idx + 1 < length: + ano = item.ta_publicado.ano + if ano in self.itens_de_vigencia: + self.itens_de_vigencia[ano].append(item) + else: + self.itens_de_vigencia[ano] = [item, ] + else: + self.itens_de_vigencia[9999] = [item, ] + + if len(self.itens_de_vigencia.keys()) <= 1: + return {} + + self.itens_de_vigencia = OrderedDict( + sorted(self.itens_de_vigencia.items(), key=lambda t: t[0])) + + return self.itens_de_vigencia + + def get_ta(self): + return TextoArticulado.objects.select_related('tipo_ta').get( + pk=self.kwargs['ta_id']) + + def is_ta_alterador(self): + if self.flag_alteradora == -1: + self.flag_alteradora = Dispositivo.objects.select_related( + 'dispositivos_alterados_pelo_texto_articulado_set' + ).filter(ta_id=self.kwargs['ta_id']).count() + return self.flag_alteradora > 0 + + +class DispositivoView(TextoView): + # template_name = 'compilacao/index.html' + template_name = 'compilacao/text_list_bloco.html' + + def get_queryset(self): + self.flag_alteradora = -1 + self.flag_nivel_ini = 0 + self.flag_nivel_old = -1 + + try: + bloco = Dispositivo.objects.get(pk=self.kwargs['dispositivo_id']) + except Dispositivo.DoesNotExist: + return [] + + self.flag_nivel_old = bloco.nivel - 1 + self.flag_nivel_ini = bloco.nivel + + proximo_bloco = Dispositivo.objects.filter( + ordem__gt=bloco.ordem, + nivel__lte=bloco.nivel, + ta_id=self.kwargs['ta_id'])[:1] + + if proximo_bloco.count() == 0: + itens = Dispositivo.objects.filter( + ordem__gte=bloco.ordem, + ta_id=self.kwargs['ta_id'] + ).select_related(*DISPOSITIVO_SELECT_RELATED) + else: + itens = Dispositivo.objects.filter( + ordem__gte=bloco.ordem, + ordem__lt=proximo_bloco[0].ordem, + ta_id=self.kwargs['ta_id'] + ).select_related(*DISPOSITIVO_SELECT_RELATED) + return itens diff --git a/norma/migrations/0009_auto_20151224_1637.py b/norma/migrations/0009_auto_20151224_1637.py new file mode 100644 index 000000000..5de7416b2 --- /dev/null +++ b/norma/migrations/0009_auto_20151224_1637.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('compilacao', '0038_auto_20151224_1429'), + ('norma', '0008_normajuridica_texto_integral'), + ] + + operations = [ + migrations.AlterModelOptions( + name='normajuridica', + options={'verbose_name': 'Norma Jurídica', 'verbose_name_plural': 'Normas Jurídicas'}, + ), + migrations.RemoveField( + model_name='normajuridica', + name='ano', + ), + migrations.RemoveField( + model_name='normajuridica', + name='data', + ), + migrations.RemoveField( + model_name='normajuridica', + name='ementa', + ), + migrations.RemoveField( + model_name='normajuridica', + name='id', + ), + migrations.RemoveField( + model_name='normajuridica', + name='numero', + ), + migrations.RemoveField( + model_name='normajuridica', + name='observacao', + ), + migrations.AddField( + model_name='normajuridica', + name='textoarticulado_ptr', + field=models.OneToOneField(to='compilacao.TextoArticulado', primary_key=True, parent_link=True, auto_created=True, default=1, serialize=False), + preserve_default=False, + ), + ] diff --git a/norma/models.py b/norma/models.py index 66aefee18..cbbe1aeb4 100644 --- a/norma/models.py +++ b/norma/models.py @@ -2,6 +2,7 @@ from django.db import models from django.template import defaultfilters from django.utils.translation import ugettext_lazy as _ +from compilacao.models import TextoArticulado from materia.models import MateriaLegislativa from sapl.utils import YES_NO_CHOICES, make_choices @@ -61,7 +62,7 @@ def texto_upload_path(instance, filename): return get_norma_media_path(instance, instance.ano, filename) -class NormaJuridica(models.Model): +class NormaJuridica(TextoArticulado): ESFERA_FEDERACAO_CHOICES, ESTADUAL, FEDERAL, MUNICIPAL = make_choices( 'E', _('Estadual'), 'F', _('Federal'), @@ -74,13 +75,10 @@ class NormaJuridica(models.Model): verbose_name=_('Texto Integral')) tipo = models.ForeignKey(TipoNormaJuridica, verbose_name=_('Tipo')) materia = models.ForeignKey(MateriaLegislativa, blank=True, null=True) - numero = models.PositiveIntegerField(verbose_name=_('Número')) - ano = models.PositiveSmallIntegerField(verbose_name=_('Ano')) esfera_federacao = models.CharField( max_length=1, verbose_name=_('Esfera Federação'), choices=ESFERA_FEDERACAO_CHOICES) - data = models.DateField(blank=True, null=True, verbose_name=_('Data')) data_publicacao = models.DateField( blank=True, null=True, verbose_name=_('Data Publicação')) veiculo_publicacao = models.CharField( @@ -92,11 +90,8 @@ class NormaJuridica(models.Model): blank=True, null=True, verbose_name=_('Pg. Início')) pagina_fim_publicacao = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Pg. Fim')) - ementa = models.TextField(verbose_name=_('Ementa')) indexacao = models.TextField( blank=True, null=True, verbose_name=_('Indexação')) - observacao = models.TextField( - blank=True, null=True, verbose_name=_('Observação')) complemento = models.NullBooleanField( blank=True, verbose_name=_('Complementar ?'), choices=YES_NO_CHOICES) @@ -110,7 +105,6 @@ class NormaJuridica(models.Model): class Meta: verbose_name = _('Norma Jurídica') verbose_name_plural = _('Normas Jurídicas') - ordering = ['-data', '-numero'] def __str__(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { diff --git a/norma/views.py b/norma/views.py index a5e680213..11f4cffe7 100644 --- a/norma/views.py +++ b/norma/views.py @@ -12,13 +12,14 @@ from django.utils.translation import ugettext_lazy as _ from django.views.generic.edit import FormMixin from vanilla import GenericView -import sapl from materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.crud import build_crud +import sapl from .models import (AssuntoNorma, LegislacaoCitada, NormaJuridica, TipoNormaJuridica) + assunto_norma_crud = build_crud( AssuntoNorma, 'assunto_norma_juridica', [ @@ -59,7 +60,7 @@ norma_temporario_crud = build_crud( NormaJuridica, 'normajuridica', [ [_('Identificação Básica'), - [('tipo', 5), ('numero', 2), ('ano', 2), ('data', 3)], + [('tipo_ta', 3), ('tipo', 3), ('numero', 2), ('ano', 2), ('data', 2)], [('ementa', 12)]], ]) diff --git a/sapl/crud.py b/sapl/crud.py index e99772ead..69f5f5779 100644 --- a/sapl/crud.py +++ b/sapl/crud.py @@ -169,6 +169,14 @@ def build_crud(model, help_path, layout): _('O registro não foi criado.')) cancel_url = BaseMixin.list_url + def form_invalid(self, form): + """ + If the form is invalid, re-render the context data with the + data-filled form and errors. + """ + print(form.errors) + return self.render_to_response(self.get_context_data(form=form)) + def get_success_url(self): return self.detail_url diff --git a/templates/compilacao/dispositivo_search_fragment_form.html b/templates/compilacao/dispositivo_search_fragment_form.html index 19244586c..6de6ba32d 100644 --- a/templates/compilacao/dispositivo_search_fragment_form.html +++ b/templates/compilacao/dispositivo_search_fragment_form.html @@ -22,7 +22,7 @@
- {% nomenclatura_heranca dpt 1 1 %} + {% nomenclatura_heranca dpt 1 1 %}
{% endif%} @@ -34,7 +34,7 @@
- {% nomenclatura_heranca dpt 1 1 %} + {% nomenclatura_heranca dpt 1 1 %}
{% endif%} diff --git a/templates/compilacao/index.html b/templates/compilacao/text_list.html similarity index 81% rename from templates/compilacao/index.html rename to templates/compilacao/text_list.html index da97be8ac..1dbc71c46 100644 --- a/templates/compilacao/index.html +++ b/templates/compilacao/text_list.html @@ -41,11 +41,11 @@ {% endfor %} @@ -95,6 +95,6 @@ {% trans 'Vigência entre'%} {{view.inicio_vigencia}} {% trans 'e'%} {{view.fim_vigencia}}. {%endif%} -{% include 'compilacao/index_bloco.html'%} +{% include 'compilacao/text_list_bloco.html'%} {% endblock base_content %} diff --git a/templates/compilacao/index_bloco.html b/templates/compilacao/text_list_bloco.html similarity index 89% rename from templates/compilacao/index_bloco.html rename to templates/compilacao/text_list_bloco.html index 082544e09..c07b56d01 100644 --- a/templates/compilacao/index_bloco.html +++ b/templates/compilacao/text_list_bloco.html @@ -21,7 +21,7 @@
{{ 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%}{{ dpt.texto|safe }}{%else%} {%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 %} {{ dpt.tipo_dispositivo.nota_automatica_sufixo_html|safe }} @@ -69,9 +69,9 @@
Vide:
@@ -91,9 +91,9 @@
Citado em:
{% if dpt.is_relative_auto_insert %} - {{ vide.dispositivo_base.dispositivo_pai}} + {{ vide.dispositivo_base.dispositivo_pai}} {% else %} - {{ vide.dispositivo_base}} + {{ vide.dispositivo_base}} {% endif %} {% if vide.texto %} - {{vide.texto}}{% endif %}
@@ -163,7 +163,7 @@
{% endspaceless %} {% if view.is_ta_alterador and dpt.tipo_dispositivo.class_css == 'bloco_alteracao'%} - {%with node=dpt template_name='compilacao/index_bloco_alteracao.html' %} + {%with node=dpt template_name='compilacao/texto_list_blocoalteracao.html' %} {%include template_name%} {%endwith%} {% endif%} diff --git a/templates/compilacao/index_bloco_alteracao.html b/templates/compilacao/text_list_blocoalteracao.html similarity index 66% rename from templates/compilacao/index_bloco_alteracao.html rename to templates/compilacao/text_list_blocoalteracao.html index 8e72c15f8..0c099a22e 100644 --- a/templates/compilacao/index_bloco_alteracao.html +++ b/templates/compilacao/text_list_blocoalteracao.html @@ -4,7 +4,7 @@ {% if ch.visibilidade %}
- {{ 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 }}
{%endif%} diff --git a/templates/compilacao/textoarticulado_detail.html b/templates/compilacao/textoarticulado_detail.html index 321f51263..afe849a8d 100644 --- a/templates/compilacao/textoarticulado_detail.html +++ b/templates/compilacao/textoarticulado_detail.html @@ -5,9 +5,24 @@
{% trans 'Editar' %}
{% trans 'Excluir' %}
- {% endblock actions %} {% block sections_nav %}{% endblock %} + {% endblock actions %} + + + {% block sections_nav %} + + + {% endblock %} + + + + + {% block detail_content %} {# TODO replace fieldset for something semantically correct, but with similar visual grouping style #}