Browse Source

Cria front e back para incl de Proposição

Conclui construção do form de inclusão de Proposições contidas pelo
Autor logado, via containers do Crud, com redirecionamento para
Textos Articulados mediante configuração de ativação desta rotina em
configurações.
pull/752/head
LeandroRoberto 8 years ago
parent
commit
101e9c26bc
  1. 4
      sapl/api/forms.py
  2. 2
      sapl/api/pagination.py
  3. 4
      sapl/api/permissions.py
  4. 25
      sapl/api/serializers.py
  5. 17
      sapl/api/urls.py
  6. 38
      sapl/api/views.py
  7. 14
      sapl/base/forms.py
  8. 9
      sapl/base/views.py
  9. 26
      sapl/crud/base.py
  10. 127
      sapl/materia/forms.py
  11. 19
      sapl/materia/migrations/0059_auto_20161016_1333.py
  12. 22
      sapl/materia/migrations/0060_auto_20161017_0050.py
  13. 20
      sapl/materia/migrations/0061_auto_20161017_1655.py
  14. 5
      sapl/materia/models.py
  15. 50
      sapl/materia/views.py
  16. 2
      sapl/static/js/app.js
  17. 14
      sapl/templates/bootstrap3/layout/checkboxselectmultiple.html
  18. 11
      sapl/templates/materia/layouts.yaml
  19. 49
      sapl/templates/materia/proposicao_form.html
  20. 8
      sapl/templates/materia/tipoproposicao_form.html

4
sapl/api/forms.py

@ -56,3 +56,7 @@ class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet):
fields = ['q', fields = ['q',
'tipo', 'tipo',
'nome', ] 'nome', ]
def filter_q(self, queryset, value):
return SaplGenericRelationSearchFilterSet.filter_q(
self, queryset, value).order_by('nome')

2
sapl/api/pagination.py

@ -30,5 +30,5 @@ class StandardPagination(pagination.PageNumberPagination):
'total_pages': self.page.paginator.num_pages, 'total_pages': self.page.paginator.num_pages,
'page': self.page.number, 'page': self.page.number,
}, },
'models': data, 'results': data,
}) })

4
sapl/api/permissions.py

@ -1,4 +1,4 @@
from rest_framework.permissions import DjangoModelPermissions from rest_framework.permissions import DjangoModelPermissions, BasePermission
class DjangoModelPermissions(DjangoModelPermissions): class DjangoModelPermissions(DjangoModelPermissions):
@ -14,4 +14,4 @@ class DjangoModelPermissions(DjangoModelPermissions):
'PUT': ['%(app_label)s.change_%(model_name)s'], 'PUT': ['%(app_label)s.change_%(model_name)s'],
'PATCH': ['%(app_label)s.change_%(model_name)s'], 'PATCH': ['%(app_label)s.change_%(model_name)s'],
'DELETE': ['%(app_label)s.delete_%(model_name)s'], 'DELETE': ['%(app_label)s.delete_%(model_name)s'],
} }

25
sapl/api/serializers.py

@ -2,7 +2,7 @@ from django.contrib.contenttypes.fields import GenericRel
from rest_framework import serializers from rest_framework import serializers
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.utils import SaplGenericRelation from sapl.materia.models import MateriaLegislativa
class ChoiceSerializer(serializers.Serializer): class ChoiceSerializer(serializers.Serializer):
@ -25,25 +25,30 @@ class ModelChoiceSerializer(ChoiceSerializer):
return obj.id return obj.id
class ModelChoiceObjectRelatedField(serializers.RelatedField):
def to_representation(self, value):
return ModelChoiceSerializer(value).data
class AutorChoiceSerializer(ModelChoiceSerializer): class AutorChoiceSerializer(ModelChoiceSerializer):
def get_value(self, obj): def get_text(self, obj):
return obj.id return obj.nome
class Meta: class Meta:
model = Autor model = Autor
fields = ['id', 'nome'] fields = ['id', 'nome']
class AutorObjectRelatedField(serializers.RelatedField): class AutorSerializer(serializers.ModelSerializer):
autor_related = ModelChoiceObjectRelatedField(read_only=True)
def to_representation(self, value): class Meta:
return str(value) model = Autor
class AutorSerializer(serializers.ModelSerializer): class MateriaLegislativaSerializer(serializers.ModelSerializer):
autor_related = AutorObjectRelatedField(read_only=True)
class Meta: class Meta:
model = Autor model = MateriaLegislativa
fields = ['id', 'tipo', 'nome', 'object_id', 'autor_related', 'user']

17
sapl/api/urls.py

@ -1,27 +1,27 @@
from django.conf import settings from django.conf import settings
from django.conf.urls import url, include from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from sapl.api.views import AutorListView, ModelChoiceView from sapl.api.views import AutorListView, ModelChoiceView,\
MateriaLegislativaViewSet
from .apps import AppConfig from .apps import AppConfig
app_name = AppConfig.name app_name = AppConfig.name
# router = DefaultRouter() router = DefaultRouter()
router.register(r'materia', MateriaLegislativaViewSet)
# urlpatterns += router.urls urlpatterns_router = router.urls
urlpatterns_api = [ urlpatterns_api = [
# url(r'^$', api_root), # url(r'^$', api_root),
url(r'^autor', AutorListView.as_view(), name='autor_list'), url(r'^autor', AutorListView.as_view(), name='autor_list'),
url(r'^model/(?P<content_type>\d+)$', url(r'^model/(?P<content_type>\d+)/(?P<pk>\d*)$',
ModelChoiceView.as_view(), name='model_list'), ModelChoiceView.as_view(), name='model_list'),
] ]
if settings.DEBUG: if settings.DEBUG:
@ -29,5 +29,6 @@ if settings.DEBUG:
url(r'^docs', include('rest_framework_docs.urls')), ] url(r'^docs', include('rest_framework_docs.urls')), ]
urlpatterns = [ urlpatterns = [
url(r'^api/', include(urlpatterns_api)) url(r'^api/', include(urlpatterns_api)),
url(r'^api/', include(urlpatterns_router))
] ]

38
sapl/api/views.py

@ -5,32 +5,37 @@ from django.http import Http404
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework.filters import DjangoFilterBackend from rest_framework.filters import DjangoFilterBackend
from rest_framework.generics import ListAPIView from rest_framework.generics import ListAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.generics import ListAPIView, get_object_or_404 from rest_framework.viewsets import GenericViewSet
from rest_framework.viewsets import ModelViewSet
from sapl.api.forms import AutorChoiceFilterSet from sapl.api.forms import AutorChoiceFilterSet
from sapl.api.serializers import ChoiceSerializer, AutorSerializer,\ from sapl.api.serializers import ChoiceSerializer, AutorSerializer,\
AutorChoiceSerializer, ModelChoiceSerializer AutorChoiceSerializer, ModelChoiceSerializer, MateriaLegislativaSerializer
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.materia.models import MateriaLegislativa
from sapl.utils import SaplGenericRelation, sapl_logger from sapl.utils import SaplGenericRelation, sapl_logger
class ModelChoiceView(ListAPIView): class ModelChoiceView(ListAPIView):
# FIXME aplicar permissão correta de usuário # FIXME aplicar permissão correta de usuário
permission_classes = (AllowAny,) permission_classes = (IsAuthenticated,)
serializer_class = ModelChoiceSerializer serializer_class = ModelChoiceSerializer
def get_queryset(self): def get(self, request, *args, **kwargs):
self.model = ContentType.objects.get_for_id(
self.kwargs['content_type']).model_class()
try: pagination = request.GET.get('pagination', '')
ct = ContentType.objects.get_for_id(self.kwargs['content_type'])
except: if pagination == 'False':
raise Http404 self.pagination_class = None
return ListAPIView.get(self, request, *args, **kwargs)
return ct.model_class().objects.all() def get_queryset(self):
return self.model.objects.all()
class AutorListView(ListAPIView): class AutorListView(ListAPIView):
@ -77,7 +82,7 @@ class AutorListView(ListAPIView):
TR_AUTOR_SERIALIZER = 3 TR_AUTOR_SERIALIZER = 3
# FIXME aplicar permissão correta de usuário # FIXME aplicar permissão correta de usuário
permission_classes = (AllowAny,) permission_classes = (IsAuthenticated,)
queryset = Autor.objects.all() queryset = Autor.objects.all()
model = Autor model = Autor
@ -187,3 +192,14 @@ class AutorListView(ListAPIView):
if tipos.count() > 1: if tipos.count() > 1:
r.sort(key=lambda x: x[1].upper()) r.sort(key=lambda x: x[1].upper())
return r return r
class MateriaLegislativaViewSet(ListModelMixin,
RetrieveModelMixin,
GenericViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = MateriaLegislativaSerializer
queryset = MateriaLegislativa.objects.all()
filter_backends = (DjangoFilterBackend,)
filter_fields = ('numero', 'ano', 'tipo', )

14
sapl/base/forms.py

@ -150,26 +150,17 @@ class AutorForm(ModelForm):
StrictButton( StrictButton(
_('Filtrar'), css_class='btn-default btn-filtrar-autor', _('Filtrar'), css_class='btn-default btn-filtrar-autor',
type='button')), type='button')),
<<<<<<< 2a44eb455a5caa1a6edb588021e46fb34b1160e7
=======
>>>>>>> Alt backend de perm e pag de drf e ref layout topo
css_class='hidden', css_class='hidden',
data_action='create', data_action='create',
data_application='AutorSearch', data_application='AutorSearch',
data_field='autor_related') data_field='autor_related')
<<<<<<< 2a44eb455a5caa1a6edb588021e46fb34b1160e7
autor_select = Row(to_column(('tipo', 3)), autor_select = Row(to_column(('tipo', 3)),
Div(to_column(('nome', 5)), Div(to_column(('nome', 5)),
to_column(('cargo', 4)), css_class="div_nome_cargo"), to_column(('cargo', 4)), css_class="div_nome_cargo"),
to_column((autor_related, 9)), to_column((autor_related, 9)),
=======
autor_select = Row(to_column(('tipo', 4)),
to_column(('nome', 8)),
to_column((autor_related, 8)),
>>>>>>> Alt backend de perm e pag de drf e ref layout topo
to_column((Div( to_column((Div(
Field('autor_related'), Field('autor_related'),
css_class='radiogroup-autor-related hidden'), css_class='radiogroup-autor-related hidden'),
@ -204,7 +195,8 @@ class AutorForm(ModelForm):
self.fields['autor_related'].choices = [ self.fields['autor_related'].choices = [
(self.instance.autor_related.pk, (self.instance.autor_related.pk,
self.instance.autor_related)] self.instance.autor_related)]
self.fields['q'].initial = self.instance.nome self.fields['autor_related'].initial = self.instance.object_id
self.fields['q'].initial = ''
if self.instance.user: if self.instance.user:
self.fields['username'].initial = self.instance.user.username self.fields['username'].initial = self.instance.user.username

9
sapl/base/views.py

@ -49,6 +49,7 @@ class AutorCrud(CrudAux):
class BaseMixin(CrudAux.BaseMixin): class BaseMixin(CrudAux.BaseMixin):
list_field_names = ['tipo', 'nome', 'user__username'] list_field_names = ['tipo', 'nome', 'user__username']
ordering = ('tipo__descricao', )
class DeleteView(CrudAux.DeleteView): class DeleteView(CrudAux.DeleteView):
@ -65,10 +66,6 @@ class AutorCrud(CrudAux):
layout_key = None layout_key = None
form_class = AutorForm form_class = AutorForm
def form_valid(self, form):
# devido a implement do form o form_valid do Crud deve ser pulado
return super(CrudAux.UpdateView, self).form_valid(form)
def get_success_url(self): def get_success_url(self):
# FIXME try except - testar envio de emails # FIXME try except - testar envio de emails
@ -111,10 +108,6 @@ class AutorCrud(CrudAux):
form_class = AutorForm form_class = AutorForm
layout_key = None layout_key = None
def form_valid(self, form):
# devido a implement do form o form_valid do Crud deve ser pulado
return super(CrudAux.CreateView, self).form_valid(form)
def get_success_url(self): def get_success_url(self):
pk_autor = self.object.id pk_autor = self.object.id
try: try:

26
sapl/crud/base.py

@ -7,11 +7,14 @@ from crispy_forms.helper import FormHelper
from crispy_forms.layout import Field, Layout from crispy_forms.layout import Field, Layout
from django import forms from django import forms
from django.conf.urls import url from django.conf.urls import url
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models from django.db import models
from django.db.models.fields.related import ForeignKey from django.db.models.fields.related import ForeignKey
from django.http.response import Http404 from django.http.response import Http404
from django.shortcuts import redirect
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -193,6 +196,24 @@ class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin):
if not self.model.objects.filter(**params).exists(): if not self.model.objects.filter(**params).exists():
raise Http404() raise Http404()
elif self.container_field:
container = self.container_field.split('__')
if len(container) > 1:
# TODO: implementar caso o user for o próprio o container
container_model = getattr(
self.model, container[0]).field.related_model
params = {}
params['__'.join(
container[1:])] = request.user.pk
if not container_model.objects.filter(**params).exists():
messages.error(
request,
'O Usuário (%s) não possui registro de %s.' % (
request.user, container_model._meta.verbose_name))
return redirect('/')
return super(PermissionRequiredMixin, self).dispatch( return super(PermissionRequiredMixin, self).dispatch(
request, *args, **kwargs) request, *args, **kwargs)
@ -585,7 +606,7 @@ class CrudCreateView(PermissionRequiredContainerCrudMixin,
return super(CrudCreateView, self).get_context_data(**kwargs) return super(CrudCreateView, self).get_context_data(**kwargs)
def form_valid(self, form): def form_valid(self, form):
self.object = form.save(commit=False) self.object = form.instance
try: try:
self.object.owner = self.request.user self.object.owner = self.request.user
self.object.modifier = self.request.user self.object.modifier = self.request.user
@ -596,6 +617,7 @@ class CrudCreateView(PermissionRequiredContainerCrudMixin,
container = self.container_field.split('__') container = self.container_field.split('__')
if len(container) > 1: if len(container) > 1:
# TODO: implementar caso o user for próprio o container
container_model = getattr( container_model = getattr(
self.model, container[0]).field.related_model self.model, container[0]).field.related_model
@ -773,7 +795,7 @@ class CrudUpdateView(PermissionRequiredContainerCrudMixin,
permission_required = (RP_CHANGE, ) permission_required = (RP_CHANGE, )
def form_valid(self, form): def form_valid(self, form):
self.object = form.save(commit=False) self.object = form.instance
try: try:
self.object.modifier = self.request.user self.object.modifier = self.request.user
except: except:

127
sapl/materia/forms.py

@ -1,6 +1,9 @@
from cProfile import label
from datetime import datetime from datetime import datetime
import django_filters import django_filters
from crispy_forms.bootstrap import InlineRadios, InlineField, Alert,\
InlineCheckboxes
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Row,\ from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Row,\
Div, Field Div, Field
@ -10,9 +13,10 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models, transaction from django.db import models, transaction
from django.db.models import Max from django.db.models import Max
from django.forms import ModelForm from django.forms import ModelForm, widgets
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl import base
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.crispy_layout_mixin import form_actions, to_row, to_column,\ from sapl.crispy_layout_mixin import form_actions, to_row, to_column,\
@ -87,7 +91,7 @@ class UnidadeTramitacaoForm(ModelForm):
return cleaned_data return cleaned_data
class ProposicaoForm(ModelForm): class ProposicaoOldForm(ModelForm):
tipo_materia = forms.ModelChoiceField( tipo_materia = forms.ModelChoiceField(
label=_('Matéria Vinculada'), label=_('Matéria Vinculada'),
@ -135,7 +139,7 @@ class ProposicaoForm(ModelForm):
return cleaned_data return cleaned_data
def save(self, commit=False): def save(self, commit=False):
proposicao = super(ProposicaoForm, self).save(commit) proposicao = super(ProposicaoOldForm, self).save(commit)
if 'materia' in self.cleaned_data: if 'materia' in self.cleaned_data:
proposicao.materia = self.cleaned_data['materia'] proposicao.materia = self.cleaned_data['materia']
proposicao.save() proposicao.save()
@ -784,11 +788,12 @@ class TipoProposicaoForm(ModelForm):
tipo_conteudo_related_radio = ChoiceWithoutValidationField( tipo_conteudo_related_radio = ChoiceWithoutValidationField(
label="Seleção de Tipo", label="Seleção de Tipo",
required=True, required=False,
widget=forms.RadioSelect()) widget=forms.RadioSelect())
tipo_conteudo_related = forms.IntegerField( tipo_conteudo_related = forms.IntegerField(
widget=forms.HiddenInput()) widget=forms.HiddenInput(),
required=True)
class Meta: class Meta:
model = TipoProposicao model = TipoProposicao
@ -801,9 +806,10 @@ class TipoProposicaoForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
tipo_select = Row(to_column(('descricao', 5)), tipo_select = Fieldset(TipoProposicao._meta.verbose_name,
to_column(('conteudo', 7)), to_column(('descricao', 5)),
to_column(('tipo_conteudo_related_radio', 12))) to_column(('conteudo', 7)),
to_column(('tipo_conteudo_related_radio', 12)))
self.helper = FormHelper() self.helper = FormHelper()
self.helper.layout = SaplFormLayout(tipo_select) self.helper.layout = SaplFormLayout(tipo_select)
@ -840,6 +846,7 @@ class TipoProposicaoForm(ModelForm):
@transaction.atomic @transaction.atomic
def save(self, commit=False): def save(self, commit=False):
tipo_proposicao = super(TipoProposicaoForm, self).save(commit) tipo_proposicao = super(TipoProposicaoForm, self).save(commit)
assert tipo_proposicao.conteudo assert tipo_proposicao.conteudo
@ -849,4 +856,108 @@ class TipoProposicaoForm(ModelForm):
).objects.get(pk=self.cleaned_data['tipo_conteudo_related']) ).objects.get(pk=self.cleaned_data['tipo_conteudo_related'])
tipo_proposicao.save() tipo_proposicao.save()
return tipo_proposicao return tipo_proposicao
class ProposicaoCreateForm(forms.ModelForm):
TIPO_TEXTO_CHOICE = [
('D', _('Arquivo Digital')),
('T', _('Texto Articulado'))
]
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
required=False,
queryset=TipoMateriaLegislativa.objects.all(),
empty_label='Selecione')
numero_materia = forms.CharField(
label='Número', required=False)
ano_materia = forms.CharField(
label='Ano', required=False)
tipo_texto = forms.MultipleChoiceField(
label=_('Tipo do Texto da Proposição'),
required=False,
choices=TIPO_TEXTO_CHOICE,
widget=widgets.CheckboxSelectMultiple())
class Meta:
model = Proposicao
fields = ['tipo',
'descricao',
'texto_original',
'tipo_materia',
'numero_materia',
'ano_materia',
'tipo_texto']
def __init__(self, *args, **kwargs):
self.texto_articulado_proposicao = base.models.AppConfig.attr(
'texto_articulado_proposicao')
if not self.texto_articulado_proposicao:
self.tipo_texto = None
self.TIPO_TEXTO_CHOICE = None
if 'tipo_texto' in self.Meta.fields:
self.Meta.fields.remove('tipo_texto')
fields = [
to_column((Fieldset(
TipoProposicao._meta.verbose_name, Field('tipo')), 3)),
Fieldset(_('Vincular a Matéria Legislativa Existente'),
to_column(('tipo_materia', 4)),
to_column(('numero_materia', 4)),
to_column(('ano_materia', 4))
),
to_column(
(Alert('teste',
css_class="ementa_materia hidden alert-info",
dismiss=False), 12)),
to_column(('descricao', 12)),
]
if self.texto_articulado_proposicao:
fields.append(
to_column((InlineCheckboxes('tipo_texto'), 5)),)
fields.append(
to_column(('texto_original', 7)),)
self.helper = FormHelper()
self.helper.layout = SaplFormLayout(*fields)
super(ProposicaoCreateForm, self).__init__(*args, **kwargs)
def clean_texto_original(self):
texto_original = self.cleaned_data.get('texto_original', False)
if texto_original:
if texto_original.size > MAX_DOC_UPLOAD_SIZE:
raise ValidationError("Arquivo muito grande. ( > 5mb )")
return texto_original
def clean(self):
cd = self.cleaned_data
tm, am, nm = (cd.get('tipo_materia', ''),
cd.get('ano_materia', ''),
cd.get('numero_materia', ''))
if tm and am and nm:
try:
materia = MateriaLegislativa.objects.get(
tipo_id=tm,
ano=am,
numero=nm
)
except ObjectDoesNotExist:
msg = _('Matéria Vinculada não existe!')
raise ValidationError(msg)
else:
cd['materia'] = materia
return cd

19
sapl/materia/migrations/0059_auto_20161016_1333.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-16 15:33
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('materia', '0058_auto_20161016_0329'),
]
operations = [
migrations.AlterUniqueTogether(
name='tipoproposicao',
unique_together=set([('conteudo', 'object_id')]),
),
]

22
sapl/materia/migrations/0060_auto_20161017_0050.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-17 02:50
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.materia.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('materia', '0059_auto_20161016_1333'),
]
operations = [
migrations.AlterField(
model_name='proposicao',
name='texto_original',
field=models.FileField(blank=True, null=True, upload_to=sapl.materia.models.texto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Original'),
),
]

20
sapl/materia/migrations/0061_auto_20161017_1655.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-17 18:55
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0060_auto_20161017_0050'),
]
operations = [
migrations.AlterField(
model_name='proposicao',
name='descricao',
field=models.TextField(verbose_name='Descrição'),
),
]

5
sapl/materia/models.py

@ -53,6 +53,7 @@ class TipoProposicao(models.Model):
class Meta: class Meta:
verbose_name = _('Tipo de Proposição') verbose_name = _('Tipo de Proposição')
verbose_name_plural = _('Tipos de Proposições') verbose_name_plural = _('Tipos de Proposições')
unique_together = (('conteudo', 'object_id'), )
def __str__(self): def __str__(self):
return self.descricao return self.descricao
@ -460,7 +461,7 @@ class Proposicao(models.Model):
data_devolucao = models.DateTimeField( data_devolucao = models.DateTimeField(
blank=True, null=True, verbose_name=_('Data de Devolução')) blank=True, null=True, verbose_name=_('Data de Devolução'))
descricao = models.TextField(max_length=100, verbose_name=_('Descrição')) descricao = models.TextField(verbose_name=_('Descrição'))
justificativa_devolucao = models.CharField( justificativa_devolucao = models.CharField(
max_length=200, max_length=200,
blank=True, blank=True,
@ -489,6 +490,8 @@ class Proposicao(models.Model):
texto_original = models.FileField( texto_original = models.FileField(
upload_to=texto_upload_path, upload_to=texto_upload_path,
blank=True,
null=True,
verbose_name=_('Texto Original'), verbose_name=_('Texto Original'),
validators=[restringe_tipos_de_arquivo_txt]) validators=[restringe_tipos_de_arquivo_txt])

50
sapl/materia/views.py

@ -30,7 +30,7 @@ from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL,
make_pagination) make_pagination)
from sapl.materia import apps from sapl.materia import apps
from sapl.materia.forms import AnexadaForm, LegislacaoCitadaForm,\ from sapl.materia.forms import AnexadaForm, LegislacaoCitadaForm,\
TipoProposicaoForm TipoProposicaoForm, ProposicaoCreateForm
from sapl.norma.models import LegislacaoCitada from sapl.norma.models import LegislacaoCitada
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url, autor_modal, gerar_hash_arquivo, get_base_url,
@ -41,7 +41,7 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
ConfirmarProposicaoForm, DocumentoAcessorioForm, ConfirmarProposicaoForm, DocumentoAcessorioForm,
MateriaLegislativaFilterSet, MateriaLegislativaFilterSet,
PrimeiraTramitacaoEmLoteFilterSet, ProposicaoForm, PrimeiraTramitacaoEmLoteFilterSet, ProposicaoOldForm,
ReceberProposicaoForm, TramitacaoEmLoteFilterSet, ReceberProposicaoForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino, filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status, filtra_tramitacao_destino_and_status,
@ -325,6 +325,48 @@ class ConfirmarProposicao(PermissionRequiredMixin, CreateView):
class ProposicaoCrud(Crud): class ProposicaoCrud(Crud):
model = Proposicao
help_path = ''
container_field = 'autor__user'
class BaseMixin(Crud.BaseMixin):
list_field_names = ['data_envio', 'descricao',
'tipo', 'data_recebimento']
class ListView(Crud.ListView):
ordering = ['-data_envio', 'descricao']
def get_rows(self, object_list):
for obj in object_list:
if obj.data_envio is None:
obj.data_envio = 'Em elaboração...'
else:
obj.data_envio = obj.data_envio.strftime("%d/%m/%Y %H:%M")
if obj.data_recebimento is None:
obj.data_recebimento = 'Não recebida'
else:
obj.data_recebimento = obj.data_recebimento.strftime(
"%d/%m/%Y %H:%M")
return [self._as_row(obj) for obj in object_list]
class CreateView(Crud.CreateView):
form_class = ProposicaoCreateForm
layout_key = None
def get_success_url(self):
tipo_texto = self.request.POST.get('tipo_texto', '')
if tipo_texto != 'T':
return Crud.CreateView.get_success_url(self)
else:
return reverse('sapl.materia:proposicao_ta',
kwargs={'pk': self.object.pk})
class ProposicaoOldCrud(Crud):
""" """
TODO: Entre outros comportamento gerais, mesmo que um usuário tenha TODO: Entre outros comportamento gerais, mesmo que um usuário tenha
Perfil de Autor o Crud de proposição não deverá permitir acesso a Perfil de Autor o Crud de proposição não deverá permitir acesso a
@ -339,7 +381,7 @@ class ProposicaoCrud(Crud):
'tipo', 'data_recebimento'] 'tipo', 'data_recebimento']
class CreateView(Crud.CreateView): class CreateView(Crud.CreateView):
form_class = ProposicaoForm form_class = ProposicaoOldForm
@property @property
def layout_key(self): def layout_key(self):
@ -366,7 +408,7 @@ class ProposicaoCrud(Crud):
return {'autor': autor_id} return {'autor': autor_id}
class UpdateView(Crud.UpdateView): class UpdateView(Crud.UpdateView):
form_class = ProposicaoForm form_class = ProposicaoOldForm
def get_initial(self): def get_initial(self):
initial = self.initial.copy() initial = self.initial.copy()

2
sapl/static/js/app.js

@ -104,7 +104,7 @@ function autorModal() {
'<select id="resultados" \ '<select id="resultados" \
style="min-width: 90%; max-width:90%;" size="5"/>'); style="min-width: 90%; max-width:90%;" size="5"/>');
data.models.forEach(function(item, index) { data.results.forEach(function(item, index) {
select.append($("<option>").attr('value', item.value).text(item.text)); select.append($("<option>").attr('value', item.value).text(item.text));
}); });

14
sapl/templates/bootstrap3/layout/checkboxselectmultiple.html

@ -1,14 +0,0 @@
{% load crispy_forms_filters %}
{% load l10n %}
<div class="controls controls-checkbox {{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap3/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
<label class="checkbox{% if field.field.inline_class %} checkbox-inline{% endif %}{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked{% endif %}" for="id_{{ field.html_name }}_{{ forloop.counter }}">
<span class="icons"><span class="first-icon"></span><span class="second-icon fa fa-check"></span></span>
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% endfor %}
{% include 'bootstrap3/layout/help_text.html' %}
</div>

11
sapl/templates/materia/layouts.yaml

@ -77,17 +77,6 @@ TipoProposicao:
- descricao conteudo - descricao conteudo
- tipo_conteudo_related - tipo_conteudo_related
ProposicaoCreate:
{% trans 'Proposição' %}:
- tipo data_envio
- descricao
{% trans 'Materia' %}:
- tipo_materia numero_materia ano_materia
{% trans 'Complemento' %}:
- texto_original
Proposicao: Proposicao:
{% trans 'Proposição' %}: {% trans 'Proposição' %}:
- tipo data_envio - tipo data_envio

49
sapl/templates/materia/proposicao_form.html

@ -5,35 +5,34 @@
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function(){ $(document).ready(function(){
if($("#id_data_envio").val() != ''){
$("#submit-id-excluir").val('Retornar proposição enviada');
}else{
$("#submit-id-excluir").val('Excluir proposição');
}
});
function disable_fields() { $("input[name=tipo_texto]").change(function(event) {
$("#id_tipo_materia").attr("disabled", "disabled"); if (this.value == 'D' && this.checked)
$("#id_numero_materia").attr("disabled", "disabled"); $("#div_id_texto_original").removeClass('hidden');
$("#id_ano_materia").attr("disabled", "disabled"); else if (this.value == 'D' && !this.checked)
$("#id_data_envio").attr("disabled", "disabled"); $("#div_id_texto_original").addClass('hidden');
} });
function enable_fields() { $("select[name=tipo_materia], input[name=numero_materia], input[name=ano_materia]").change(function(event) {
$("#id_tipo_materia").removeAttr('disabled'); var url = '{% url 'sapl.api:materialegislativa-list'%}'
$("#id_numero_materia").removeAttr('disabled');
$("#id_ano_materia").removeAttr('disabled');
}
$(function () { var formData = {
disable_fields(); 'tipo' : $("select[name=tipo_materia]").val(),
$("#id_tipo").change(function() { 'ano' : $("input[name=ano_materia]").val(),
if ($('#id_tipo option:selected').text() == 'Parecer') { // parecer 'numero' : $("input[name=numero_materia]").val(),
enable_fields(); }
}else { if (formData.tipo == '' || formData.ano == '' || formData.numero == '')
disable_fields(); return;
} $.get(url, formData).done(function(data) {
if (data.pagination.total_entries == 1)
$(".ementa_materia").html(data.results[0].ementa).removeClass('hidden');
else
$(".ementa_materia").html('').addClass('hidden');
});
}); });
$("input[name=tipo_texto], select[name=tipo_materia]").trigger('change');
}); });
</script> </script>
{% endblock %} {% endblock %}

8
sapl/templates/materia/tipoproposicao_form.html

@ -10,20 +10,18 @@ $(document).ready(function(){
$("input[name=tipo_conteudo_related]").remove(); $("input[name=tipo_conteudo_related]").remove();
$('#id_conteudo').change(function(event) { $('#id_conteudo').change(function(event) {
var pk = this[event.target.selectedIndex].value; var pk = this[event.target.selectedIndex].value;
var url = '{% url 'sapl.api:model_list' 0 ''%}'
var url = '{% url 'sapl.api:model_list' 0 %}' url = url.replace('0', pk) + '?pagination=False'
url = url.replace('0', pk)
$.get(url).done(function(data) { $.get(url).done(function(data) {
var radios = $("#div_id_tipo_conteudo_related_radio .controls").html(''); var radios = $("#div_id_tipo_conteudo_related_radio .controls").html('');
data.models.forEach(function (val, index) { data.forEach(function (val, index) {
var html_radio = '<label class="radio'+(initial_select==val.value?' checked':'')+'"><span class="icons"><span class="first-icon"></span><span class="second-icon"></span></span><input type="radio" name="tipo_conteudo_related" id="id_tipo_conteudo_related_'+index+'" value="'+val.value+'"'+(initial_select?' checked="checked"':'')+'>'+val.text+'</label>'; var html_radio = '<label class="radio'+(initial_select==val.value?' checked':'')+'"><span class="icons"><span class="first-icon"></span><span class="second-icon"></span></span><input type="radio" name="tipo_conteudo_related" id="id_tipo_conteudo_related_'+index+'" value="'+val.value+'"'+(initial_select?' checked="checked"':'')+'>'+val.text+'</label>';
radios.append(html_radio); radios.append(html_radio);
}); });
initial_select=''; initial_select='';
}); });
}); });
$('#id_conteudo').trigger('change'); $('#id_conteudo').trigger('change');

Loading…
Cancel
Save