Browse Source

Adiciona a model, forms e views da reunião de comissão

pull/1614/head
Mariana Mendes 8 years ago
parent
commit
8884eb2184
  1. 46
      sapl/comissoes/forms.py
  2. 44
      sapl/comissoes/migrations/0003_reuniao.py
  3. 118
      sapl/comissoes/models.py
  4. 3
      sapl/comissoes/urls.py
  5. 80
      sapl/comissoes/views.py

46
sapl/comissoes/forms.py

@ -3,11 +3,14 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import transaction from django.db import transaction
from django.db.models import Q from django.db.models import Q
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar
from .models import Reuniao
class ParticipacaoCreateForm(forms.ModelForm): class ParticipacaoCreateForm(forms.ModelForm):
@ -142,3 +145,46 @@ class ComissaoForm(forms.ModelForm):
nome=nome nome=nome
) )
return comissao return comissao
class ReuniaoForm(ModelForm):
class Meta:
model = Reuniao
exclude = ['cod_andamento_sessao']
def clean(self):
super(ReuniaoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
instance = self.instance
num = self.cleaned_data['numero']
com = self.cleaned_data['comissao']
tipo = self.cleaned_data['tipo']
periodo = self.cleaned_data['periodo']
error = ValidationError(
"Número de Reunião já existente "
"para a Comissão, Período e Tipo informados. "
"Favor escolher um número distinto.")
reunioes = Reuniao.objects.filter(numero=num,
comissao=com,
periodo=periodo,
tipo=tipo).\
values_list('id', flat=True)
qtd_reunioes = len(reunioes)
if qtd_reunioes > 0:
if instance.pk: # update
if instance.pk not in reunioes or qtd_reunioes > 1:
raise error
else: # create
raise error
return self.cleaned_data

44
sapl/comissoes/migrations/0003_reuniao.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2017-11-23 13:07
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import sapl.comissoes.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('comissoes', '0002_auto_20170809_1236'),
]
operations = [
migrations.CreateModel(
name='Reuniao',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('numero', models.PositiveIntegerField(verbose_name='Número')),
('nome', models.CharField(max_length=100, verbose_name='Nome da Reunião')),
('tema', models.CharField(max_length=100, verbose_name='Tema da Reunião')),
('data', models.DateField(verbose_name='Data')),
('hora_inicio', models.CharField(max_length=5, verbose_name='Horário (hh:mm)')),
('hora_fim', models.CharField(max_length=5, verbose_name='Horário (hh:mm)')),
('local_reuniao', models.CharField(blank=True, max_length=100, verbose_name='Local Reunião')),
('observacao', models.CharField(blank=True, max_length=150, verbose_name='Observação')),
('url_audio', models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)')),
('url_video', models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)')),
('upload_pauta', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.pauta_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Pauta da Reunião')),
('upload_ata', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.ata_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Ata da Reunião')),
('upload_anexo', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.anexo_upload_path, verbose_name='Anexo da Reunião')),
('comissao', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.Comissao', verbose_name='Comissão')),
('periodo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.Periodo', verbose_name='Periodo da Composicão da Comissão')),
('tipo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.TipoComissao', verbose_name='Tipo')),
],
options={
'verbose_name': 'Reunião de Comissão',
'verbose_name_plural': 'Reuniões de Comissão',
},
),
]

118
sapl/comissoes/models.py

@ -5,7 +5,8 @@ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.utils import YES_NO_CHOICES, SaplGenericRelation from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation,
restringe_tipos_de_arquivo_txt, texto_upload_path)
@reversion.register() @reversion.register()
@ -182,3 +183,118 @@ class Participacao(models.Model): # ComposicaoComissao
def __str__(self): def __str__(self):
return '%s : %s' % (self.cargo, self.parlamentar) return '%s : %s' % (self.cargo, self.parlamentar)
def get_comissao_media_path(instance, subpath, filename):
return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename)
def pauta_upload_path(instance, filename):
return texto_upload_path(
instance, filename, subpath='pauta', pk_first=True)
def ata_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath='ata', pk_first=True)
def anexo_upload_path(instance, filename):
return texto_upload_path(
instance, filename, subpath='anexo', pk_first=True)
class Reuniao(models.Model):
periodo = models. ForeignKey(
Periodo,
on_delete=models.PROTECT,
verbose_name=_('Periodo da Composicão da Comissão'))
comissao = models.ForeignKey(
Comissao,
on_delete=models.PROTECT,
verbose_name=_('Comissão'))
tipo = models.ForeignKey(
TipoComissao,
on_delete=models.PROTECT,
verbose_name=_('Tipo'))
numero = models.PositiveIntegerField(verbose_name=_('Número'))
nome = models.CharField(
max_length=100, verbose_name=_('Nome da Reunião'))
tema = models.CharField(
max_length=100, verbose_name=_('Tema da Reunião'))
data = models.DateField(verbose_name=_('Data'))
hora_inicio = models.CharField(
max_length=5, verbose_name=_('Horário (hh:mm)'))
hora_fim = models.CharField(
max_length=5, verbose_name=_('Horário (hh:mm)'))
local_reuniao = models.CharField(
max_length=100, blank=True, verbose_name=_('Local Reunião'))
observacao = models.CharField(
max_length=150, blank=True, verbose_name=_('Observação'))
url_audio = models.URLField(
max_length=150, blank=True,
verbose_name=_('URL Arquivo Áudio (Formatos MP3 / AAC)'))
url_video = models.URLField(
max_length=150, blank=True,
verbose_name=_('URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)'))
upload_pauta = models.FileField(
blank=True,
null=True,
upload_to=pauta_upload_path,
verbose_name=_('Pauta da Reunião'),
validators=[restringe_tipos_de_arquivo_txt])
upload_ata = models.FileField(
blank=True,
null=True,
upload_to=ata_upload_path,
verbose_name=_('Ata da Reunião'),
validators=[restringe_tipos_de_arquivo_txt])
upload_anexo = models.FileField(
blank=True,
null=True,
upload_to=anexo_upload_path,
verbose_name=_('Anexo da Reunião'))
class Meta:
verbose_name = _('Reunião de Comissão')
verbose_name_plural = _('Reuniões de Comissão')
def __str__(self):
return self.nome
def delete(self, using=None, keep_parents=False):
if self.upload_pauta:
self.upload_pauta.delete()
if self.upload_ata:
self.upload_ata.delete()
if self.upload_anexo:
self.upload_anexo.delete()
return models.Model.delete(
self, using=using, keep_parents=keep_parents)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if not self.pk and (self.upload_pauta or self.upload_ata or
self.upload_anexo):
upload_pauta = self.upload_pauta
upload_ata = self.upload_ata
upload_anexo = self.upload_anexo
self.upload_pauta = None
self.upload_ata = None
self.upload_anexo = None
models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
self.upload_pauta = upload_pauta
self.upload_ata = upload_ata
self.upload_anexo = upload_anexo
return models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)

3
sapl/comissoes/urls.py

@ -1,7 +1,7 @@
from django.conf.urls import include, url from django.conf.urls import include, url
from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud, from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud,
MateriasTramitacaoListView, ParticipacaoCrud, MateriasTramitacaoListView, ParticipacaoCrud,
PeriodoComposicaoCrud, TipoComissaoCrud) PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud)
from .apps import AppConfig from .apps import AppConfig
@ -10,6 +10,7 @@ app_name = AppConfig.name
urlpatterns = [ urlpatterns = [
url(r'^comissao/', include(ComissaoCrud.get_urls() + url(r'^comissao/', include(ComissaoCrud.get_urls() +
ComposicaoCrud.get_urls() + ComposicaoCrud.get_urls() +
ReuniaoCrud.get_urls() +
ParticipacaoCrud.get_urls())), ParticipacaoCrud.get_urls())),
url(r'^comissao/(?P<pk>\d+)/materias-em-tramitacao$', url(r'^comissao/(?P<pk>\d+)/materias-em-tramitacao$',

80
sapl/comissoes/views.py

@ -3,13 +3,23 @@ from django.core.urlresolvers import reverse
from django.db.models import F from django.db.models import F
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import ListView from django.views.generic import ListView
from django.views.generic.base import RedirectView
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from sapl.base.models import AppConfig as AppsAppConfig
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud,
CrudAux, MasterDetailCrud,
PermissionRequiredForAppCrudMixin)
from sapl.comissoes.forms import ParticipacaoCreateForm, ParticipacaoEditForm from sapl.comissoes.forms import ParticipacaoCreateForm, ParticipacaoEditForm
from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud
from sapl.materia.models import MateriaLegislativa, Tramitacao from sapl.materia.models import MateriaLegislativa, Tramitacao
from .forms import ComissaoForm from .forms import ReuniaoForm, ComissaoForm
from .models import (CargoComissao, Comissao, Composicao, Participacao, from .models import (CargoComissao, Comissao, Composicao, Participacao,
Periodo, TipoComissao) Periodo, TipoComissao, Reuniao)
from sapl.comissoes.apps import AppConfig
def pegar_url_composicao(pk): def pegar_url_composicao(pk):
@ -136,3 +146,67 @@ class MateriasTramitacaoListView(ListView):
MateriasTramitacaoListView, self).get_context_data(**kwargs) MateriasTramitacaoListView, self).get_context_data(**kwargs)
context['object'] = Comissao.objects.get(id=self.kwargs['pk']) context['object'] = Comissao.objects.get(id=self.kwargs['pk'])
return context return context
class ReuniaoCrud(Crud):
model = Reuniao
class BaseMixin(Crud.BaseMixin):
list_field_names = ['data', 'comissao', 'tipo']
@property
def list_url(self):
return ''
@property
def search_url(self):
namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'pesquisar_reuniao'))
class ListView(Crud.ListView, RedirectView):
def get_redirect_url(self, *args, **kwargs):
namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'pesquisar_reuniao'))
# arrumar a url
def get(self, request, *args, **kwargs):
return RedirectView.get(self, request, *args, **kwargs)
class UpdateView(Crud.UpdateView):
form_class = ReuniaoForm
def get_initial(self):
return {'comissao': self.object.comissao}
class CreateView(Crud.CreateView):
form_class = ReuniaoForm
@property
def cancel_url(self):
return self.search_url
def get_initial(self):
comissao = Comissao.objects.order_by('-data').first()
if comissao:
return {
'comissao': comissao
}
else:
msg = _('Cadastre alguma comissão antes de adicionar ' +
'uma reunião!')
messages.add_message(self.request, messagesself.ERROR, msg)
return {}
class DeleteView(Crud.DeleteView, RedirectView):
def get_success_url(self):
namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'reuniao_list'))
class ReuniaoPermissionMixin(PermissionRequiredForAppCrudMixin,
FormMixin,
DetailView):
model = Reuniao
app_label = AppConfig.label,

Loading…
Cancel
Save