Browse Source

Merge pull request #440 from interlegis/312-crud-proposição

Fix #312 crud proposição
pull/445/head
Eduardo Edson Batista Cordeiro Alves 9 years ago
parent
commit
87d83484ea
  1. 64
      materia/forms.py
  2. 19
      materia/layouts.yaml
  3. 5
      materia/tests/test_materia.py
  4. 8
      materia/tests/test_materia_urls.py
  5. 11
      materia/urls.py
  6. 204
      materia/views.py
  7. 4
      parlamentares/views.py
  8. 2
      templates/base.html
  9. 40
      templates/materia/proposicao/proposicao_list.html
  10. 14
      templates/materia/proposicao_detail.html
  11. 0
      templates/materia/proposicao_form.html

64
materia/forms.py

@ -1,6 +1,8 @@
from datetime import datetime
import django_filters import django_filters
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Submit from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from django import forms from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models from django.db import models
@ -52,43 +54,33 @@ class ProposicaoForm(ModelForm):
raise ValidationError("Arquivo muito grande. ( > 5mb )") raise ValidationError("Arquivo muito grande. ( > 5mb )")
return texto_original return texto_original
class Meta: def clean_data_envio(self):
model = Proposicao data_envio = self.cleaned_data.get('data_envio')
fields = ['tipo', 'data_envio', 'descricao', 'texto_original'] if (not data_envio) and bool(self.initial):
data_envio = datetime.now()
return data_envio
def __init__(self, excluir=False, *args, **kwargs): def clean(self):
more = [] cleaned_data = self.cleaned_data
if excluir: if 'tipo' in cleaned_data:
more = [Submit('Excluir', 'Excluir')] if cleaned_data['tipo'].descricao == 'Parecer':
try:
materia = MateriaLegislativa.objects.get(
tipo_id=cleaned_data['tipo_materia'],
ano=cleaned_data['ano_materia'],
numero=cleaned_data['numero_materia'])
except ObjectDoesNotExist:
msg = _('Matéria adicionada não existe!')
raise ValidationError(msg)
else:
cleaned_data['materia'] = materia
cleaned_data['autor'] = materia.autoria_set.first().autor
row1 = crispy_layout_mixin.to_row( return cleaned_data
[('tipo', 8), ('data_envio', 4)])
row2 = crispy_layout_mixin.to_row(
[('descricao', 12)])
row3 = crispy_layout_mixin.to_row(
[('tipo_materia', 4), ('numero_materia', 4), ('ano_materia', 4)])
row4 = crispy_layout_mixin.to_row(
[('texto_original', 12)])
self.helper = FormHelper() class Meta:
self.helper.layout = Layout( model = Proposicao
Fieldset(_('Incluir Proposição'), fields = ['tipo', 'data_envio', 'descricao', 'texto_original']
row1, row2, row3, row4,
HTML("""
<div class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.texto_original.value }}">
<br /><br />
<input type="submit"
name="remover-texto"
id="remover-texto"
class="btn btn-warning"
value="Remover Texto"/>
<p></p>
""", ),
form_actions(more=more))
)
super(ProposicaoForm, self).__init__(
*args, **kwargs)
class AcompanhamentoMateriaForm(ModelForm): class AcompanhamentoMateriaForm(ModelForm):
@ -121,8 +113,6 @@ class DocumentoAcessorioForm(ModelForm):
fields = ['tipo', 'nome', 'data', 'autor', 'ementa', 'arquivo'] fields = ['tipo', 'nome', 'data', 'autor', 'ementa', 'arquivo']
widgets = {'autor': forms.HiddenInput()} widgets = {'autor': forms.HiddenInput()}
widgets = {'autor': forms.HiddenInput()}
def clean_autor(self): def clean_autor(self):
autor_field = self.cleaned_data['autor'] autor_field = self.cleaned_data['autor']
try: try:

19
materia/layouts.yaml

@ -87,12 +87,23 @@ TipoProposicao:
- materia_ou_documento tipo_documento - materia_ou_documento tipo_documento
- modelo - modelo
ProposicaoCreate:
Proposição:
- tipo data_envio
- descricao
Materia:
- tipo_materia numero_materia ano_materia
Complemento:
- texto_original
Proposicao: Proposicao:
Proposição: Proposição:
- tipo dat_criacao_FIXME data_recebimento - tipo data_envio
- descricao_FIXME - descricao
- tip_id_basica_FIXME num_ident_basica_FIXME ano_ident_basica_FIXME Materia:
- nom_arquivo_FIXME modelo_FIXME - materia
Complemento:
- texto_original
StatusTramitacao: StatusTramitacao:
Status Tramitação: Status Tramitação:

5
materia/tests/test_materia.py

@ -416,7 +416,7 @@ def test_form_errors_relatoria(client):
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_proposicao_submit(client): def test_proposicao_submit(client):
response = client.post(reverse('materia:adicionar_proposicao'), response = client.post(reverse('materia:proposicao_create'),
{'tipo': mommy.make(TipoProposicao, pk=3).pk, {'tipo': mommy.make(TipoProposicao, pk=3).pk,
'descricao': 'Teste proposição', 'descricao': 'Teste proposição',
'salvar': 'salvar'}, 'salvar': 'salvar'},
@ -432,10 +432,9 @@ def test_proposicao_submit(client):
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_form_errors_proposicao(client): def test_form_errors_proposicao(client):
response = client.post(reverse('materia:adicionar_proposicao'), response = client.post(reverse('materia:proposicao_create'),
{'salvar': 'salvar'}, {'salvar': 'salvar'},
follow=True) follow=True)
assert (response.context_data['form'].errors['tipo'] == assert (response.context_data['form'].errors['tipo'] ==
['Este campo é obrigatório.']) ['Este campo é obrigatório.'])
assert (response.context_data['form'].errors['descricao'] == assert (response.context_data['form'].errors['descricao'] ==

8
materia/tests/test_materia_urls.py

@ -9,11 +9,11 @@ from django.core.urlresolvers import reverse
('materia:tramitacao_update', ('materia:tramitacao_update',
{'pk': '8'}, {'pk': '8'},
'/materia/tramitacao/8/edit'), '/materia/tramitacao/8/edit'),
('materia:adicionar_proposicao', {}, '/materia/proposicao'), ('materia:proposicao_create', {}, '/proposicao/create'),
('materia:editar_proposicao', ('materia:proposicao_update',
{'pk': '3'}, {'pk': '3'},
'/materia/proposicao/3/edit'), '/proposicao/3/edit'),
('materia:list_proposicao', {}, '/materia/proposicao_list'), ('materia:proposicao_list', {}, '/proposicao/'),
]) ])
def test_reverse(test_input, kwargs, expected): def test_reverse(test_input, kwargs, expected):
assert reverse(test_input, kwargs=kwargs) == expected assert reverse(test_input, kwargs=kwargs) == expected

11
materia/urls.py

@ -8,8 +8,7 @@ from materia.views import (AcompanhamentoConfirmarView,
MateriaLegislativaCrud, MateriaLegislativaCrud,
MateriaLegislativaPesquisaView, MateriaTaView, MateriaLegislativaPesquisaView, MateriaTaView,
NumeracaoCrud, OrgaoCrud, OrigemCrud, NumeracaoCrud, OrgaoCrud, OrigemCrud,
ProposicaoEditView, ProposicaoListView, ProposicaoCrud, ProposicaoTaView,
ProposicaoTaView, ProposicaoView,
RegimeTramitacaoCrud, RelatoriaCrud, RegimeTramitacaoCrud, RelatoriaCrud,
StatusTramitacaoCrud, TipoAutorCrud, StatusTramitacaoCrud, TipoAutorCrud,
TipoDocumentoCrud, TipoFimRelatoriaCrud, TipoDocumentoCrud, TipoFimRelatoriaCrud,
@ -31,6 +30,8 @@ urlpatterns = [
RelatoriaCrud.get_urls() + RelatoriaCrud.get_urls() +
DocumentoAcessorioCrud.get_urls())), DocumentoAcessorioCrud.get_urls())),
url(r'proposicao/', include(ProposicaoCrud.get_urls())),
# Integração com Compilação # Integração com Compilação
url(r'^materia/(?P<pk>[0-9]+)/ta$', url(r'^materia/(?P<pk>[0-9]+)/ta$',
MateriaTaView.as_view(), name='materia_ta'), MateriaTaView.as_view(), name='materia_ta'),
@ -55,12 +56,6 @@ urlpatterns = [
url(r'^sistema/materia/status-tramitacao/', url(r'^sistema/materia/status-tramitacao/',
include(StatusTramitacaoCrud.get_urls())), include(StatusTramitacaoCrud.get_urls())),
url(r'^sistema/materia/orgao/', include(OrgaoCrud.get_urls())), url(r'^sistema/materia/orgao/', include(OrgaoCrud.get_urls())),
url(r'^materia/proposicao$',
ProposicaoView.as_view(), name='adicionar_proposicao'),
url(r'^materia/proposicao_list$',
ProposicaoListView.as_view(), name='list_proposicao'),
url(r'^materia/proposicao/(?P<pk>[0-9]+)/edit$',
ProposicaoEditView.as_view(), name='editar_proposicao'),
url(r'^materia/pesquisar-materia$', url(r'^materia/pesquisar-materia$',
MateriaLegislativaPesquisaView.as_view(), name='pesquisar_materia'), MateriaLegislativaPesquisaView.as_view(), name='pesquisar_materia'),
url(r'^materia/(?P<pk>\d+)/acompanhar-materia/$', url(r'^materia/(?P<pk>\d+)/acompanhar-materia/$',

204
materia/views.py

@ -1,7 +1,7 @@
import os
from datetime import datetime from datetime import datetime
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
from crispy_layout_mixin import form_actions
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button from crispy_forms.layout import HTML, Button
@ -10,10 +10,9 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import send_mail from django.core.mail import send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect
from django.template import Context, loader from django.template import Context, loader
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic import CreateView, TemplateView, UpdateView
from django_filters.views import FilterView from django_filters.views import FilterView
import crispy_layout_mixin import crispy_layout_mixin
@ -53,11 +52,58 @@ TipoAutorCrud = Crud.build(TipoAutor, 'tipo_autor')
AutorCrud = Crud.build(Autor, 'autor') AutorCrud = Crud.build(Autor, 'autor')
OrgaoCrud = Crud.build(Orgao, 'orgao') OrgaoCrud = Crud.build(Orgao, 'orgao')
TipoProposicaoCrud = Crud.build(TipoProposicao, 'tipo_proposicao') TipoProposicaoCrud = Crud.build(TipoProposicao, 'tipo_proposicao')
ProposicaoCrud = Crud.build(Proposicao, '')
StatusTramitacaoCrud = Crud.build(StatusTramitacao, 'status_tramitacao') StatusTramitacaoCrud = Crud.build(StatusTramitacao, 'status_tramitacao')
UnidadeTramitacaoCrud = Crud.build(UnidadeTramitacao, 'unidade_tramitacao') UnidadeTramitacaoCrud = Crud.build(UnidadeTramitacao, 'unidade_tramitacao')
class ProposicaoCrud(Crud):
model = Proposicao
help_path = ''
class BaseMixin(crud.base.CrudBaseMixin):
list_field_names = ['data_envio', 'descricao', 'tipo']
class CreateView(crud.base.CrudCreateView):
form_class = ProposicaoForm
@property
def layout_key(self):
return 'ProposicaoCreate'
class UpdateView(crud.base.CrudUpdateView):
form_class = ProposicaoForm
@property
def layout_key(self):
return 'ProposicaoCreate'
class ListView(crud.base.CrudListView):
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...'
return [self._as_row(obj) for obj in object_list]
class DeleteView(MasterDetailCrud.DeleteView):
def delete(self, request, *args, **kwargs):
proposicao = Proposicao.objects.get(id=self.kwargs['pk'])
if not proposicao.data_envio:
proposicao.delete()
return HttpResponseRedirect(reverse('materia:proposicao_list'))
else:
proposicao.data_envio = None
proposicao.save()
return HttpResponseRedirect(
reverse('materia:proposicao_detail',
kwargs={'pk': proposicao.pk}))
class RelatoriaCrud(MasterDetailCrud): class RelatoriaCrud(MasterDetailCrud):
model = Relatoria model = Relatoria
parent_field = 'materia' parent_field = 'materia'
@ -325,6 +371,42 @@ class MateriaLegislativaCrud(Crud):
list_field_names = ['tipo', 'numero', 'ano', 'data_apresentacao'] list_field_names = ['tipo', 'numero', 'ano', 'data_apresentacao']
class DocumentoAcessorioView(CreateView):
template_name = "materia/documento_acessorio.html"
form_class = DocumentoAcessorioForm
def get(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
docs = DocumentoAcessorio.objects.filter(
materia_id=kwargs['pk']).order_by('data')
form = DocumentoAcessorioForm()
return self.render_to_response(
{'object': materia,
'form': form,
'docs': docs})
def post(self, request, *args, **kwargs):
form = self.get_form()
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
docs_list = DocumentoAcessorio.objects.filter(
materia_id=kwargs['pk'])
if form.is_valid():
documento_acessorio = form.save(commit=False)
documento_acessorio.materia = materia
documento_acessorio.save()
return self.form_valid(form)
else:
return self.render_to_response({'form': form,
'object': materia,
'docs': docs_list})
def get_success_url(self):
pk = self.kwargs['pk']
return reverse('materia:documento_acessorio', kwargs={'pk': pk})
class AcompanhamentoConfirmarView(TemplateView): class AcompanhamentoConfirmarView(TemplateView):
def get_redirect_url(self): def get_redirect_url(self):
@ -556,27 +638,6 @@ def do_envia_email_tramitacao(request, materia):
return None return None
class ProposicaoListView(ListView):
template_name = "materia/proposicao/proposicao_list.html"
paginate_by = 10
model = Proposicao
def get_queryset(self):
return Proposicao.objects.all().order_by('data_envio',
'tipo',
'descricao')
def get_context_data(self, **kwargs):
context = super(ProposicaoListView, self).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
return context
class MateriaLegislativaPesquisaView(FilterView): class MateriaLegislativaPesquisaView(FilterView):
model = MateriaLegislativa model = MateriaLegislativa
filterset_class = MateriaLegislativaFilterSet filterset_class = MateriaLegislativaFilterSet
@ -651,99 +712,6 @@ class MateriaLegislativaPesquisaView(FilterView):
return self.render_to_response(context) return self.render_to_response(context)
class ProposicaoView(CreateView):
template_name = "materia/proposicao/proposicao.html"
form_class = ProposicaoForm
def get_success_url(self):
return reverse('materia:list_proposicao')
def get(self, request, *args, **kwargs):
return self.render_to_response({'form': self.get_form()})
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
proposicao = form.save(commit=False)
tipo = TipoProposicao.objects.get(id=form.data['tipo'])
if tipo.descricao == 'Parecer':
try:
materia = MateriaLegislativa.objects.get(
tipo_id=int(form.data['tipo_materia']),
ano=int(form.data['ano_materia']),
numero=int(form.data['numero_materia']))
except ObjectDoesNotExist:
msg = _('Matéria adicionada não existe!')
messages.add_message(request, messages.INFO, msg)
return self.render_to_response({'form': form})
else:
proposicao.autor = materia.autoria_set.first().autor
proposicao.materia = materia
proposicao.save()
return redirect(self.get_success_url())
else:
return self.render_to_response({'form': form})
class ProposicaoEditView(CreateView):
template_name = "materia/proposicao/proposicao.html"
form_class = ProposicaoForm
def get_success_url(self):
return reverse('materia:list_proposicao')
def get(self, request, *args, **kwargs):
proposicao = Proposicao.objects.get(id=kwargs['pk'])
return self.render_to_response({'form': ProposicaoForm(
excluir=True,
instance=proposicao)})
def post(self, request, *args, **kwargs):
form = self.get_form()
proposicao = Proposicao.objects.get(id=kwargs['pk'])
if form.is_valid():
if 'Excluir' in request.POST:
if proposicao.data_envio:
proposicao.data_envio = None
proposicao.save()
else:
proposicao.delete()
if 'salvar' or "remover-foto" in request.POST:
if 'texto_original' in request.FILES:
# if os.unlink(proposicao.texto_original.path):
# proposicao.texto_original = None
proposicao.texto_original = request.FILES['texto_original']
tipo = TipoProposicao.objects.get(id=form.data['tipo'])
proposicao.tipo = tipo
proposicao.descricao = form.data['descricao']
if tipo.descricao == 'Parecer':
try:
materia = MateriaLegislativa.objects.get(
tipo_id=int(form.data['tipo_materia']),
ano=int(form.data['ano_materia']),
numero=int(form.data['numero_materia']))
except ObjectDoesNotExist:
msg = _('Matéria adicionada não existe!')
messages.add_message(request, messages.INFO, msg)
return self.render_to_response({'form': form})
else:
proposicao.autor = materia.autoria_set.first().autor
proposicao.materia = materia
if not proposicao.data_envio:
proposicao.data_envio = datetime.now()
if "remover-texto" in request.POST:
try:
os.unlink(proposicao.texto_original.path)
except OSError:
pass # Should log this error!!!!!
proposicao.texto_original = None
proposicao.save()
return redirect(self.get_success_url())
else:
return self.render_to_response({'form': form})
class MateriaTaView(IntegracaoTaView): class MateriaTaView(IntegracaoTaView):
model = MateriaLegislativa model = MateriaLegislativa
model_type_foreignkey = TipoMateriaLegislativa model_type_foreignkey = TipoMateriaLegislativa

4
parlamentares/views.py

@ -88,8 +88,8 @@ class ParlamentarCrud(Crud):
def get_rows(self, object_list): def get_rows(self, object_list):
parlamentares = [] parlamentares = []
for m in object_list: for m in object_list:
ultima_filiacao = m.parlamentar.filiacao_set.\ ultima_filiacao = m.parlamentar.filiacao_set.order_by(
order_by('-data').first() '-data').first()
if ultima_filiacao and not ultima_filiacao.data_desfiliacao: if ultima_filiacao and not ultima_filiacao.data_desfiliacao:
partido = ultima_filiacao.partido.sigla partido = ultima_filiacao.partido.sigla
else: else:

2
templates/base.html

@ -67,7 +67,7 @@
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Atividade Legislativa <span class="caret"></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Atividade Legislativa <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'materia:list_proposicao' %}">Proposições</a></li> <li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'materia:proposicao_list' %}">Proposições</a></li>
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'materia:materialegislativa_list' %}">Matérias Legislativas</a></li> <li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'materia:materialegislativa_list' %}">Matérias Legislativas</a></li>
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sessao:sessaoplenaria_list' %}">Sessões Plenárias</a></li> <li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sessao:sessaoplenaria_list' %}">Sessões Plenárias</a></li>
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sessao:list_pauta_sessao' %}">Pautas das Sessões</a></li> <li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'sessao:list_pauta_sessao' %}">Pautas das Sessões</a></li>

40
templates/materia/proposicao/proposicao_list.html

@ -1,40 +0,0 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %}
{% block sections_nav %}
{% endblock %}
{% block detail_content %}
<h2><b>Proposições</b></h2>
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'materia:adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a>
</div>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<th>Enviada em</th>
<th>Tipo</th>
<th>Descrição</th>
<th>Incorporada?</th>
</tr>
</thead>
{% for proposicao in page_obj %}
<tr>
{% if proposicao.data_envio %}
<td><a href="{% url 'materia:editar_proposicao' proposicao.id %}"><b>{{ proposicao.data_envio|date:'d/m/Y H:i' }}</b></a></td>
{% else %}
<td><a href="{% url 'materia:editar_proposicao' proposicao.id %}"><b>Em elaboração...</b></a></td>
{% endif %}
<td>{{ proposicao.tipo }}</td>
<td>{{ proposicao.descricao|safe }}</td>
<td>{% if proposicao.materia %} Sim {% else %} Não {% endif %}</td>
</tr>
{% endfor %}
</table>
{% include "paginacao.html" %}
{% endblock %}

14
templates/materia/proposicao_detail.html

@ -0,0 +1,14 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
{% if proposicao.data_envio %}
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar Proposição' %}</a>
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Retornar Proposição Enviada' %}</a>
{% else %}
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Enviar/Editar Proposição' %}</a>
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Excluir Proposição' %}</a>
{% endif %}
</div>
{% endblock actions %}

0
templates/materia/proposicao/proposicao.html → templates/materia/proposicao_form.html

Loading…
Cancel
Save