Sistema de Apoio ao Processo Legislativo
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

547 lines
20 KiB

import reversion
from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.base.models import Autor
from sapl.materia.models import MateriaLegislativa
from sapl.parlamentares.models import (CargoMesa, Legislatura, Parlamentar,
Partido, SessaoLegislativa)
from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation,
get_settings_auth_user_model,
restringe_tipos_de_arquivo_txt, texto_upload_path)
@reversion.register()
class CargoBancada(models.Model):
nome_cargo = models.CharField(max_length=80,
verbose_name=_('Cargo de Bancada'))
cargo_unico = models.BooleanField(default=False,
choices=YES_NO_CHOICES,
verbose_name=_('Cargo Único ?'))
class Meta:
verbose_name = _('Cargo de Bancada')
verbose_name_plural = _('Cargos de Bancada')
def __str__(self):
return self.nome_cargo
@reversion.register()
class Bancada(models.Model):
legislatura = models.ForeignKey(Legislatura,
on_delete=models.PROTECT,
verbose_name=_('Legislatura'))
nome = models.CharField(
max_length=80,
verbose_name=_('Nome da Bancada'))
partido = models.ForeignKey(Partido,
blank=True,
null=True,
on_delete=models.PROTECT,
verbose_name=_('Partido'))
data_criacao = models.DateField(blank=False, null=True,
verbose_name=_('Data Criação'))
data_extincao = models.DateField(blank=True, null=True,
verbose_name=_('Data Extinção'))
descricao = models.TextField(blank=True, verbose_name=_('Descrição'))
# campo conceitual de reversão genérica para o model Autor que dá a
# o meio possível de localização de tipos de autores.
autor = SaplGenericRelation(Autor, related_query_name='bancada_set',
fields_search=(
('nome', '__icontains'),
('descricao', '__icontains'),
('partido__sigla', '__icontains'),
('partido__nome', '__icontains'),
))
class Meta:
verbose_name = _('Bancada Parlamentar')
verbose_name_plural = _('Bancadas Parlamentares')
ordering = ('-legislatura__numero', )
def __str__(self):
return self.nome
@reversion.register()
class TipoSessaoPlenaria(models.Model):
nome = models.CharField(max_length=30, verbose_name=_('Tipo'))
quorum_minimo = models.PositiveIntegerField(
verbose_name=_('Quórum mínimo'))
class Meta:
verbose_name = _('Tipo de Sessão Plenária')
verbose_name_plural = _('Tipos de Sessão Plenária')
ordering = ['nome']
def __str__(self):
return self.nome
def get_sessao_media_path(instance, subpath, filename):
return './sapl/sessao/%s/%s/%s' % (instance.numero, subpath, filename)
def pauta_upload_path(instance, filename):
return texto_upload_path(
instance, filename, subpath='pauta', pk_first=True)
# return get_sessao_media_path(instance, 'pauta', filename)
def ata_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath='ata', pk_first=True)
# return get_sessao_media_path(instance, 'ata', filename)
def anexo_upload_path(instance, filename):
return texto_upload_path(
instance, filename, subpath='anexo', pk_first=True)
# return get_sessao_media_path(instance, 'anexo', filename)
@reversion.register()
class SessaoPlenaria(models.Model):
# TODO trash??? Seems to have been a FK in the past. Would be:
# andamento_sessao = models.ForeignKey(
# AndamentoSessao, blank=True, null=True)
# TODO analyze querying all hosted databases !
cod_andamento_sessao = models.PositiveIntegerField(blank=True, null=True)
painel_aberto = models.BooleanField(blank=True, default=False,
verbose_name=_('Painel está aberto?'))
tipo = models.ForeignKey(TipoSessaoPlenaria,
on_delete=models.PROTECT,
verbose_name=_('Tipo'))
sessao_legislativa = models.ForeignKey(
SessaoLegislativa,
on_delete=models.PROTECT,
verbose_name=_('Sessão Legislativa'))
legislatura = models.ForeignKey(Legislatura,
on_delete=models.PROTECT,
verbose_name=_('Legislatura'))
# XXX seems to be empty
data_inicio = models.DateField(verbose_name=_('Abertura'))
hora_inicio = models.CharField(
max_length=5, verbose_name=_('Horário (hh:mm)'))
hora_fim = models.CharField(
max_length=5, blank=True, verbose_name=_('Horário (hh:mm)'))
numero = models.PositiveIntegerField(verbose_name=_('Número'))
data_fim = models.DateField(
blank=True, null=True, verbose_name=_('Encerramento'))
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 Sessão'),
validators=[restringe_tipos_de_arquivo_txt])
upload_ata = models.FileField(
blank=True,
null=True,
upload_to=ata_upload_path,
verbose_name=_('Ata da Sessão'),
validators=[restringe_tipos_de_arquivo_txt])
upload_anexo = models.FileField(
blank=True,
null=True,
upload_to=anexo_upload_path,
verbose_name=_('Anexo da Sessão'))
iniciada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão iniciada?'))
finalizada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão finalizada?'))
interativa = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão interativa'))
class Meta:
verbose_name = _('Sessão Plenária')
verbose_name_plural = _('Sessões Plenárias')
def __str__(self):
return _('%(numero)sª Sessão %(tipo_nome)s'
' da %(sessao_legislativa_numero)sª Sessão Legislativa'
' da %(legislatura_id)sª Legislatura') % {
'numero': self.numero,
'tipo_nome': self.tipo.nome,
'sessao_legislativa_numero': self.sessao_legislativa.numero,
# XXX check if it shouldn't be legislatura.numero
'legislatura_id': self.legislatura.numero}
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)
@reversion.register()
class AbstractOrdemDia(models.Model):
TIPO_VOTACAO_CHOICES = Choices(
(1, 'simbolica', (('Simbólica'))),
(2, 'nominal', (('Nominal'))),
(3, 'secreta', (('Secreta'))),
)
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
materia = models.ForeignKey(MateriaLegislativa,
on_delete=models.PROTECT,
verbose_name=_('Matéria'))
data_ordem = models.DateField(verbose_name=_('Data da Sessão'))
observacao = models.TextField(
blank=True, verbose_name=_('Ementa'))
numero_ordem = models.PositiveIntegerField(verbose_name=_('Nº Ordem'))
resultado = models.TextField(blank=True, verbose_name=_('Resultado'))
tipo_votacao = models.PositiveIntegerField(
verbose_name=_('Tipo de votação'), choices=TIPO_VOTACAO_CHOICES)
votacao_aberta = models.NullBooleanField(
blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Votação iniciada?'))
class Meta:
abstract = True
def __str__(self):
return '%s - %s' % (self.numero_ordem, self.sessao_plenaria)
@reversion.register()
class ExpedienteMateria(AbstractOrdemDia):
class Meta:
verbose_name = _('Matéria do Expediente')
verbose_name_plural = _('Matérias do Expediente')
ordering = ['numero_ordem']
@reversion.register()
class TipoExpediente(models.Model):
nome = models.CharField(max_length=100, verbose_name=_('Tipo'))
class Meta:
verbose_name = _('Tipo de Expediente')
verbose_name_plural = _('Tipos de Expediente')
ordering = ['nome']
def __str__(self):
return self.nome
@reversion.register()
class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
tipo = models.ForeignKey(TipoExpediente, on_delete=models.PROTECT)
conteudo = models.TextField(
blank=True, verbose_name=_('Conteúdo do expediente'))
class Meta:
verbose_name = _('Expediente de Sessão Plenaria')
verbose_name_plural = _('Expedientes de Sessão Plenaria')
def __str__(self):
return '%s - %s' % (self.tipo, self.sessao_plenaria)
@reversion.register()
class IntegranteMesa(models.Model): # MesaSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
cargo = models.ForeignKey(CargoMesa, on_delete=models.PROTECT)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
class Meta:
verbose_name = _('Participação em Mesa de Sessão Plenaria')
verbose_name_plural = _('Participações em Mesas de Sessão Plenaria')
def __str__(self):
return '%s - %s' % (self.cargo, self.parlamentar)
@reversion.register()
class AbstractOrador(models.Model): # Oradores
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
parlamentar = models.ForeignKey(Parlamentar,
on_delete=models.PROTECT,
verbose_name=_('Parlamentar'))
numero_ordem = models.PositiveIntegerField(
verbose_name=_('Ordem de pronunciamento'))
url_discurso = models.URLField(
max_length=150, blank=True, verbose_name=_('URL Vídeo'))
observacao = models.CharField(
max_length=150, blank=True, verbose_name=_('Observação'))
class Meta:
abstract = True
def __str__(self):
return _('%(nome)s (%(numero)sº orador)') % {
'nome': self.parlamentar,
'numero': self.numero_ordem}
@reversion.register()
class Orador(AbstractOrador): # Oradores
class Meta:
verbose_name = _('Orador das Explicações Pessoais')
verbose_name_plural = _('Oradores das Explicações Pessoais')
@reversion.register()
class OradorExpediente(AbstractOrador): # OradoresExpediente
class Meta:
verbose_name = _('Orador do Expediente')
verbose_name_plural = _('Oradores do Expediente')
@reversion.register()
class OrdemDia(AbstractOrdemDia):
class Meta:
verbose_name = _('Matéria da Ordem do Dia')
verbose_name_plural = _('Matérias da Ordem do Dia')
ordering = ['numero_ordem']
@reversion.register()
class PresencaOrdemDia(models.Model): # OrdemDiaPresenca
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
class Meta:
verbose_name = _('Presença da Ordem do Dia')
verbose_name_plural = _('Presenças da Ordem do Dia')
ordering = ['parlamentar__nome_parlamentar']
def __str__(self):
# FIXME ambigous
return _('Sessão: %(sessao)s Parlamentar: %(parlamentar)s') % {
'sessao': self.sessao_plenaria,
'parlamentar': self.parlamentar}
@reversion.register()
class TipoResultadoVotacao(models.Model):
nome = models.CharField(max_length=100, verbose_name=_('Nome do Tipo'))
natureza = models.CharField(max_length=100,
blank=True,
choices=(('A', 'Aprovado'),
('R', 'Rejeitado')),
verbose_name=_('Natureza do Tipo'))
class Meta:
verbose_name = _('Tipo de Resultado de Votação')
verbose_name_plural = _('Tipos de Resultado de Votação')
def __str__(self):
return self.nome
@reversion.register()
class RegistroVotacao(models.Model):
tipo_resultado_votacao = models.ForeignKey(
TipoResultadoVotacao,
on_delete=models.PROTECT,
verbose_name=_('Resultado da Votação'))
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.PROTECT)
ordem = models.ForeignKey(OrdemDia,
blank=True,
null=True,
on_delete=models.PROTECT)
expediente = models.ForeignKey(ExpedienteMateria,
blank=True,
null=True,
on_delete=models.PROTECT)
numero_votos_sim = models.PositiveIntegerField(verbose_name=_('Sim'))
numero_votos_nao = models.PositiveIntegerField(verbose_name=_('Não'))
numero_abstencoes = models.PositiveIntegerField(
verbose_name=_('Abstenções'))
observacao = models.TextField(
blank=True, verbose_name=_('Observações'))
data_hora_criacao = models.DateTimeField(
blank=True, null=True,
auto_now_add=True,
verbose_name=_('Data Criação'))
data_hora_atualizacao = models.DateTimeField(
blank=True, null=True,
auto_now=True,
verbose_name=_('Data'))
class Meta:
verbose_name = _('Votação')
verbose_name_plural = _('Votações')
def __str__(self):
return _('Ordem: %(ordem)s - Votação: %(votacao)s - '
'Matéria: %(materia)s') % {
'ordem': self.ordem,
'votacao': self.tipo_resultado_votacao,
'materia': self.materia}
@reversion.register()
class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar
'''
As colunas ordem e expediente são redundantes, levando em consideração
que RegistroVotacao já possui ordem/expediente. Entretanto, para
viabilizar a votação interativa, uma vez que ela é feita antes de haver
um RegistroVotacao, é preciso identificar o voto por ordem/expediente.
'''
votacao = models.ForeignKey(RegistroVotacao,
blank=True,
null=True)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
voto = models.CharField(max_length=10)
user = models.ForeignKey(get_settings_auth_user_model(),
on_delete=models.PROTECT,
null=True,
blank=True)
ip = models.CharField(verbose_name=_('IP'),
max_length=30,
blank=True,
default='')
data_hora = models.DateTimeField(
verbose_name=_('Data/Hora'),
auto_now_add=True,
blank=True,
null=True)
ordem = models.ForeignKey(OrdemDia,
blank=True,
null=True)
expediente = models.ForeignKey(ExpedienteMateria,
blank=True,
null=True)
class Meta:
verbose_name = _('Registro de Votação de Parlamentar')
verbose_name_plural = _('Registros de Votações de Parlamentares')
def __str__(self):
return _('Votação: %(votacao)s - Parlamentar: %(parlamentar)s') % {
'votacao': self.votacao, 'parlamentar': self.parlamentar}
@reversion.register()
class SessaoPlenariaPresenca(models.Model):
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.PROTECT)
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT)
data_sessao = models.DateField(blank=True, null=True)
class Meta:
verbose_name = _('Presença em Sessão Plenária')
verbose_name_plural = _('Presenças em Sessões Plenárias')
ordering = ['parlamentar__nome_parlamentar']
@reversion.register()
class Bloco(models.Model):
'''
* blocos podem existir por mais de uma legislatura
'''
nome = models.CharField(
max_length=80, verbose_name=_('Nome do Bloco'))
partidos = models.ManyToManyField(
Partido, blank=True, verbose_name=_('Partidos'))
data_criacao = models.DateField(
blank=False, null=True, verbose_name=_('Data Criação'))
data_extincao = models.DateField(
blank=True, null=True, verbose_name=_('Data Dissolução'))
descricao = models.TextField(blank=True, verbose_name=_('Descrição'))
# campo conceitual de reversão genérica para o model Autor que dá a
# o meio possível de localização de tipos de autores.
autor = SaplGenericRelation(Autor,
related_query_name='bloco_set',
fields_search=(
('nome', '__icontains'),
('descricao', '__icontains'),
('partidos__sigla', '__icontains'),
('partidos__nome', '__icontains'),
))
class Meta:
verbose_name = _('Bloco Parlamentar')
verbose_name_plural = _('Blocos Parlamentares')
def __str__(self):
return self.nome
@reversion.register()
class ResumoOrdenacao(models.Model):
'''
Tabela para registrar em qual ordem serão renderizados os componentes
da tela de resumo de uma sessão
'''
primeiro = models.CharField(max_length=30)
segundo = models.CharField(max_length=30)
terceiro = models.CharField(max_length=30)
quarto = models.CharField(max_length=30)
quinto = models.CharField(max_length=30)
sexto = models.CharField(max_length=30)
setimo = models.CharField(max_length=30)
oitavo = models.CharField(max_length=30)
nono = models.CharField(max_length=30)
decimo = models.CharField(max_length=30)
class Meta:
verbose_name = _('Ordenação do Resumo de uma Sessão')
verbose_name_plural = _('Ordenação do Resumo de uma Sessão')
def __str__(self):
return 'Ordenação do Resumo de uma Sessão'