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.
 
 
 
 
 

524 lines
18 KiB

from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from django.template import defaultfilters
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.base.models import Autor
from sapl.compilacao.models import TextoArticulado
from sapl.materia.models import MateriaLegislativa, Orgao
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
restringe_tipos_de_arquivo_txt,
texto_upload_path,
get_settings_auth_user_model,
OverwriteStorage)
class AssuntoNorma(models.Model):
assunto = models.CharField(max_length=50, verbose_name=_('Assunto'))
descricao = models.CharField(
max_length=250, blank=True, verbose_name=_('Descrição'))
class Meta:
verbose_name = _('Assunto de Norma Jurídica')
verbose_name_plural = _('Assuntos de Normas Jurídicas')
ordering = ['assunto']
def __str__(self):
return self.assunto
class TipoNormaJuridica(models.Model):
# TODO transform into Domain Model and use an FK for the field
EQUIVALENTE_LEXML_CHOICES = ((name, name) for name in
('constituicao',
'ementa.constitucional',
'lei.complementar',
'lei.delegada',
'lei',
'decreto.lei',
'medida.provisoria',
'decreto',
'lei.organica',
'emenda.lei.organica',
'decreto.legislativo',
'resolucao',
'regimento.interno',
))
equivalente_lexml = models.CharField(
max_length=50,
blank=True,
verbose_name=_('Equivalente LexML'),
choices=EQUIVALENTE_LEXML_CHOICES)
sigla = models.CharField(max_length=3, verbose_name=_('Sigla'))
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
class Meta:
verbose_name = _('Tipo de Norma Jurídica')
verbose_name_plural = _('Tipos de Norma Jurídica')
ordering = ['descricao']
def __str__(self):
return self.descricao
def norma_upload_path(instance, filename):
return texto_upload_path(instance, filename, subpath=instance.ano)
class NormaJuridicaManager(models.Manager):
use_for_related_fields = True
def normas_sem_textos_articulados(self):
qs = self.get_queryset()
qs = qs.filter(texto_articulado__isnull=True)
return qs
def normas_com_textos_articulados_publicados(self):
qs = self.get_queryset()
qs = qs.filter(
texto_articulado__editable_only_by_owners=False,
texto_articulado__privacidade=0,
texto_articulado__isnull=False
)
return qs
def normas_com_textos_articulados_pendentes(self):
qs = self.get_queryset()
qs = qs.filter(
texto_articulado__editable_only_by_owners=False)
q = models.Q(
texto_articulado__privacidade=0
) | models.Q(
texto_articulado__isnull=True
)
qs = qs.exclude(q)
for n in qs:
ta = n.texto_articulado.first()
count = ta.dispositivos_set.count()
if count == 1:
count = 0
elif count == 2:
d = ta.dispositivos_set.last()
if d.auto_inserido or not d.texto or d.texto == n.ementa:
count = 0
elif count == 3:
ds = ta.dispositivos_set.all()
if ds[1].auto_inserido and \
not d[2].dispositivo_pai and\
d[2].tipo_dispositivo.dispositivo_de_articulacao:
count = 0
if not count:
ta.dispositivos_set.filter(
dispositivo_pai__isnull=False).delete()
ta.publicacao_set.all().delete()
ta.delete()
return qs
class NormaJuridica(models.Model):
objects = NormaJuridicaManager()
ESFERA_FEDERACAO_CHOICES = Choices(
('M', 'municipal', _('Municipal')),
('E', 'estadual', _('Estadual')),
('F', 'federal', _('Federal')),
)
texto_integral = models.FileField(
max_length=300,
blank=True,
null=True,
upload_to=norma_upload_path,
verbose_name=_('Texto Original'),
storage=OverwriteStorage(),
validators=[restringe_tipos_de_arquivo_txt])
tipo = models.ForeignKey(
TipoNormaJuridica,
on_delete=models.PROTECT,
verbose_name=_('Tipo da Norma Jurídica'))
materia = models.ForeignKey(
MateriaLegislativa, blank=True, null=True,
on_delete=models.PROTECT,
verbose_name=_('Matéria'),
related_name='normajuridica_set')
orgao = models.ForeignKey(
Orgao, blank=True, null=True,
on_delete=models.PROTECT, verbose_name=_('Órgão'))
numero = models.CharField(
max_length=8,
verbose_name=_('Número'))
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'),
choices=RANGE_ANOS)
esfera_federacao = models.CharField(
max_length=1,
verbose_name=_('Esfera Federação'),
choices=ESFERA_FEDERACAO_CHOICES)
data = models.DateField(blank=False, null=True, verbose_name=_('Data'))
data_publicacao = models.DateField(
blank=True, null=True, verbose_name=_('Data de Publicação'))
veiculo_publicacao = models.CharField(
max_length=200,
blank=True,
verbose_name=_('Veículo de Publicação'))
pagina_inicio_publicacao = models.PositiveIntegerField(
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, verbose_name=_('Indexação'))
observacao = models.TextField(
blank=True, verbose_name=_('Observação'))
complemento = models.BooleanField(
null=True,
blank=True,
default=False,
verbose_name=_('Complementar ?'),
choices=YES_NO_CHOICES
)
# XXX was a CharField (attention on migrate)
assuntos = models.ManyToManyField(
AssuntoNorma, blank=True,
verbose_name=_('Assuntos'))
data_vigencia = models.DateField(
blank=True, null=True, verbose_name=_('Data Fim Vigência'))
timestamp = models.DateTimeField(null=True)
texto_articulado = GenericRelation(
TextoArticulado, related_query_name='texto_articulado')
data_ultima_atualizacao = models.DateTimeField(
blank=True, null=True,
auto_now=True,
verbose_name=_('Data'))
autores = models.ManyToManyField(
Autor,
through='AutoriaNorma',
through_fields=('norma', 'autor'),
symmetrical=False)
user = models.ForeignKey(
get_settings_auth_user_model(),
verbose_name=_('Usuário'),
on_delete=models.PROTECT,
null=True,
blank=True
)
ip = models.CharField(
verbose_name=_('IP'),
max_length=60,
blank=True,
default=''
)
ultima_edicao = models.DateTimeField(
verbose_name=_('Data e Hora da Edição'),
blank=True, null=True
)
class Meta:
verbose_name = _('Norma Jurídica')
verbose_name_plural = _('Normas Jurídicas')
ordering = ['-data', '-numero']
def get_normas_relacionadas(self):
principais = NormaRelacionada.objects.filter(
norma_principal=self.id).order_by('norma_principal__data',
'norma_relacionada__data')
relacionadas = NormaRelacionada.objects.filter(
norma_relacionada=self.id).order_by('norma_principal__data',
'norma_relacionada__data')
return (principais, relacionadas)
def get_anexos_norma_juridica(self):
anexos = AnexoNormaJuridica.objects.filter(
norma=self.id)
return anexos
def __str__(self):
numero_norma = self.numero
if numero_norma.isnumeric():
numero_norma = '{0:,}'.format(int(self.numero)).replace(',', '.')
return _('%(tipo)s%(orgao_sigla)s%(numero)s, de %(data)s') % {
'tipo': self.tipo,
'orgao_sigla': f'-{self.orgao.sigla}' if self.orgao else '',
'numero': numero_norma,
'data': defaultfilters.date(self.data, "d \d\e F \d\e Y").lower()}
@property
def epigrafe(self):
return self.__str__()
@property
def epigrafe_simplificada(self):
numero_norma = self.numero
if numero_norma.isnumeric():
numero_norma = '{0:,}'.format(int(self.numero)).replace(',', '.')
return _('%(tipo)s%(numero)s, de %(data)s') % {
'tipo': self.tipo,
'numero': numero_norma,
'data': defaultfilters.date(self.data, "d \d\e F \d\e Y").lower()}
def delete(self, using=None, keep_parents=False):
texto_integral = self.texto_integral
result = super().delete(using=using, keep_parents=keep_parents)
if texto_integral:
texto_integral.delete(save=False)
return result
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if not self.pk and self.texto_integral:
texto_integral = self.texto_integral
self.texto_integral = None
models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
self.texto_integral = texto_integral
return models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
def get_ano_atual():
return timezone.now().year
class NormaEstatisticas(models.Model):
usuario = models.CharField(max_length=50)
horario_acesso = models.DateTimeField(
blank=True, null=True)
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'),
choices=RANGE_ANOS, default=get_ano_atual)
norma = models.ForeignKey(NormaJuridica,
on_delete=models.CASCADE)
class Meta:
ordering = ('id',)
def __str__(self):
return _('Usuário: %(usuario)s, Norma: %(norma)s') % {
'usuario': self.usuario, 'norma': self.norma}
class ViewNormasEstatisticas(models.Model):
mais_acessadas = models.PositiveSmallIntegerField(
verbose_name=_('Mais Acessadas'))
ano_est = models.PositiveSmallIntegerField(
verbose_name=_('Ano do Registro de Acesso'))
mes_est = models.PositiveSmallIntegerField(
verbose_name=_('Mês do Registro de Acesso'))
norma_id = models.BigIntegerField(verbose_name=_('Id da Norma'))
norma_count = models.PositiveSmallIntegerField(
verbose_name=_('Mês do Registro de Acesso'))
norma_numero = models.CharField(
max_length=8, verbose_name=_('Número da Norma'))
norma_ano = models.PositiveSmallIntegerField(
verbose_name=_('Ano da Norma'))
norma_ementa = models.TextField(verbose_name=_('Ementa'))
norma_observacao = models.TextField(
blank=True, verbose_name=_('Observação'))
norma_tipo_sigla = models.CharField(
max_length=3,
verbose_name=_('Sigla do Tipo da Norma'))
norma_tipo_descricao = models.CharField(
max_length=50, verbose_name=_('Descrição do Tipo da Norma'))
norma_data = models.DateField(verbose_name=_('Data da Norma'))
class Meta:
managed = False
db_table = "norma_viewnormasestatisticas"
class AutoriaNorma(models.Model):
autor = models.ForeignKey(Autor,
verbose_name=_('Autor'),
on_delete=models.CASCADE)
norma = models.ForeignKey(
NormaJuridica, on_delete=models.CASCADE,
verbose_name=_('Matéria Legislativa'))
primeiro_autor = models.BooleanField(verbose_name=_('Primeiro Autor'),
choices=YES_NO_CHOICES,
default=False)
class Meta:
verbose_name = _('Autoria')
verbose_name_plural = _('Autorias')
unique_together = (('autor', 'norma'), )
ordering = ('-primeiro_autor', 'autor__nome')
def __str__(self):
return _('Autoria: %(autor)s - %(norma)s') % {
'autor': self.autor, 'norma': self.norma}
class LegislacaoCitada(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
norma = models.ForeignKey(NormaJuridica, on_delete=models.CASCADE)
disposicoes = models.CharField(
max_length=15, blank=True, verbose_name=_('Disposição'))
parte = models.CharField(
max_length=8, blank=True, verbose_name=_('Parte'))
livro = models.CharField(
max_length=7, blank=True, verbose_name=_('Livro'))
titulo = models.CharField(
max_length=7, blank=True, verbose_name=_('Título'))
capitulo = models.CharField(
max_length=7, blank=True, verbose_name=_('Capítulo'))
secao = models.CharField(
max_length=7, blank=True, verbose_name=_('Seção'))
subsecao = models.CharField(
max_length=7, blank=True, verbose_name=_('Subseção'))
artigo = models.CharField(
max_length=4, blank=True, verbose_name=_('Artigo'))
paragrafo = models.CharField(
max_length=3, blank=True, verbose_name=_('Parágrafo'))
inciso = models.CharField(
max_length=10, blank=True, verbose_name=_('Inciso'))
alinea = models.CharField(
max_length=3, blank=True, verbose_name=_('Alínea'))
item = models.CharField(
max_length=3, blank=True, verbose_name=_('Item'))
class Meta:
verbose_name = _('Legislação')
verbose_name_plural = _('Legislações')
ordering = ('id',)
def __str__(self):
return str(self.norma)
class TipoVinculoNormaJuridica(models.Model):
sigla = models.CharField(
max_length=1, blank=True, verbose_name=_('Sigla'))
descricao_ativa = models.CharField(
max_length=50, blank=True, verbose_name=_('Descrição Ativa'))
descricao_passiva = models.CharField(
max_length=50, blank=True, verbose_name=_('Descrição Passiva'))
revoga_integralmente = models.BooleanField(verbose_name=_('Revoga Integralmente?'),
choices=YES_NO_CHOICES,
default=False)
class Meta:
verbose_name = _('Tipo de Vínculo entre Normas Jurídicas')
verbose_name_plural = _('Tipos de Vínculos entre Normas Jurídicas')
ordering = ('id',)
def __str__(self):
return self.descricao_ativa
class NormaRelacionada(models.Model):
norma_principal = models.ForeignKey(
NormaJuridica,
related_name='norma_principal',
on_delete=models.PROTECT,
verbose_name=_('Norma Principal'))
norma_relacionada = models.ForeignKey(
NormaJuridica,
related_name='norma_relacionada',
on_delete=models.PROTECT,
verbose_name=_('Norma Relacionada'))
tipo_vinculo = models.ForeignKey(
TipoVinculoNormaJuridica,
on_delete=models.PROTECT,
verbose_name=_('Tipo de Vínculo'))
resumo = models.TextField(
blank=True,
default="",
verbose_name=_('Resumo'),
)
class Meta:
verbose_name = _('Norma Relacionada')
verbose_name_plural = _('Normas Relacionadas')
ordering = ('norma_principal__data', 'norma_relacionada__data')
def __str__(self):
return _('Principal: %(norma_principal)s'
' - Relacionada: %(norma_relacionada)s') % {
'norma_principal': str(self.norma_principal),
'norma_relacionada': str(self.norma_relacionada)}
class AnexoNormaJuridica(models.Model):
norma = models.ForeignKey(
NormaJuridica,
related_name='norma',
on_delete=models.PROTECT,
verbose_name=_('Norma Juridica'))
assunto_anexo = models.TextField(
blank=True,
default="",
verbose_name=_('Assunto do Anexo'),
max_length=250
)
anexo_arquivo = models.FileField(
max_length=300,
blank=True,
null=True,
upload_to=norma_upload_path,
verbose_name=_('Arquivo Anexo'),
storage=OverwriteStorage(),
validators=[restringe_tipos_de_arquivo_txt])
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'),
choices=RANGE_ANOS)
class Meta:
verbose_name = _('Anexo da Norma Juridica')
verbose_name_plural = _('Anexos da Norma Juridica')
ordering = ('id',)
def __str__(self):
return _('Anexo: %(anexo)s da norma %(norma)s') % {
'anexo': self.anexo_arquivo, 'norma': self.norma}
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if not self.pk and self.anexo_arquivo:
anexo_arquivo = self.anexo_arquivo
self.anexo_arquivo = None
models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
self.anexo_arquivo = anexo_arquivo
return models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
def delete(self, using=None, keep_parents=False):
anexo_arquivo = self.anexo_arquivo
result = super().delete(using=using, keep_parents=keep_parents)
if anexo_arquivo:
anexo_arquivo.delete(save=False)
return result