class AnexoNormaJuridica(CountPageMixin): FIELDFILE_NAME = ('anexo_arquivo', ) metadata = JSONField(verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) norma = models.ForeignKey(NormaJuridica, related_name='anexos_set', 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 = PortalFileField( blank=True, null=True, upload_to=norma_upload_path, verbose_name=_('Arquivo Anexo'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_midias]) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) class Meta: verbose_name = _('Anexo da Norma Juridica') verbose_name_plural = _('Anexos da Norma Juridica') 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)
class DocumentoAcessorioAdministrativo(CommonMixin): FIELDFILE_NAME = ('arquivo', ) metadata = JSONField( verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) documento = models.ForeignKey(DocumentoAdministrativo, on_delete=models.PROTECT) tipo = models.ForeignKey( TipoDocumentoAdministrativo, on_delete=models.PROTECT, verbose_name=_('Tipo')) nome = models.CharField(max_length=30, verbose_name=_('Nome')) arquivo = PortalFileField( blank=True, null=True, upload_to=texto_upload_path, storage=OverwriteStorage(), verbose_name=_('Arquivo'), max_length=512) data = models.DateField(blank=True, null=True, verbose_name=_('Data')) autor = models.CharField( max_length=50, blank=True, verbose_name=_('Autor')) assunto = models.TextField( blank=True, verbose_name=_('Assunto')) indexacao = models.TextField(blank=True) class Meta: verbose_name = _('Documento Acessório') verbose_name_plural = _('Documentos Acessórios') def __str__(self): return self.nome def delete(self, using=None, keep_parents=False): if self.arquivo: self.arquivo.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.arquivo: arquivo = self.arquivo self.arquivo = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.arquivo = arquivo return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
class DocumentoAdministrativo(CommonMixin): #related_objects = DocumentoAdministrativoManager() #objects = models.Manager() FIELDFILE_NAME = ('texto_integral', ) STATUS_DOC_ADM_PUBLICO = 99 STATUS_DOC_ADM_RESTRITO = 49 STATUS_DOC_ADM_PRIVADO = 0 PRIVACIDADE_DOC_ADM_STATUS = ( # Só o usuário da Area de trabalho pode ver e não deve ser # listado através do link share (STATUS_DOC_ADM_PRIVADO, _('Privado')), (STATUS_DOC_ADM_RESTRITO, _('Restrito')), (STATUS_DOC_ADM_PUBLICO, _('Público')), ) class Meta: verbose_name = _('Documento Administrativo') verbose_name_plural = _('Documentos Administrativos') ordering = ('-ano', ('-id')) #base_manager_name = 'related_objects' permissions = ( ('link_share_create_documentoadministrativo', _('Gerar Link Público')), ) metadata = JSONField( verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) tipo = models.ForeignKey( TipoDocumentoAdministrativo, on_delete=models.PROTECT, verbose_name=_('Tipo Documento')) numero = models.PositiveIntegerField(verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) protocolo = models.ForeignKey( Protocolo, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_('Protocolo')) protocolo_gr = GenericRelation( 'protocoloadm.Protocolo', object_id_field='conteudo_object_id', content_type_field='conteudo_content_type', related_query_name='protocolo_gr') diariosoficiais = GenericRelation( VinculoDocDiarioOficial, related_query_name='diariosoficiais',) materia = models.ForeignKey( MateriaLegislativa, blank=True, null=True, on_delete=models.PROTECT, related_name='documentoadministrativo_set', verbose_name=_('Matéria Vinculada') ) data = models.DateField(verbose_name=_('Data')) temp_migracao_doc_acessorio = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Field temporário para migração dos docs acessórios da procuradoria')) temp_migracao_sislegis = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Field temporário para migração dos docs adms do sislegis')) old_path = models.TextField( verbose_name=_('Path antigo para Sislegis - Publicações'), blank=True, null=True, default=None) old_json = JSONField( verbose_name=_('Json from origin import'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) epigrafe = models.CharField( max_length=1000, blank=True, verbose_name=_('Epigrafe / Título')) interessado = models.CharField( max_length=1000, blank=True, verbose_name=_('Interessado')) email = models.EmailField( blank=True, verbose_name=_('Email')) autor = models.ForeignKey(Autor, blank=True, null=True, on_delete=models.PROTECT) dias_prazo = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Dias Prazo')) data_fim_prazo = models.DateField( blank=True, null=True, verbose_name=_('Data Fim Prazo')) data_vencimento = models.DateField( blank=True, null=True, verbose_name=_('Data de Vencimento')) tramitacao = models.BooleanField( verbose_name=_('Em Tramitação?'), choices=YES_NO_CHOICES, default=False) assunto = models.TextField( blank=True, null=True, verbose_name=_('Assunto')) numero_externo = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Número Externo')) observacao = models.TextField( blank=True, verbose_name=_('Resumo')) texto_integral = PortalFileField( blank=True, null=True, storage=OverwriteStorage(), upload_to=texto_upload_path, verbose_name=_('Texto Integral'), max_length=512) anexados = models.ManyToManyField( 'self', blank=True, through='Anexado', symmetrical=False, related_name='anexo_de', through_fields=( 'documento_principal', 'documento_anexado' ) ) workspace = models.ForeignKey( AreaTrabalho, verbose_name=_('Área de Trabalho'), related_name='documentoadministrativo_set', blank=True, null=True, on_delete=PROTECT) # Todo Documento é privado, a não ser que a Área de Trabalho seja pub visibilidade = models.PositiveIntegerField( verbose_name=_('Visibilidade'), choices=PRIVACIDADE_DOC_ADM_STATUS, default=STATUS_DOC_ADM_PRIVADO) link_share = models.CharField( _('Link de Compartilhamento'), max_length=128, blank=True, null=True, default=None) data_ultima_atualizacao = models.DateTimeField( blank=True, null=True, auto_now=True, verbose_name=_('Data')) auditlog = GenericRelation( 'core.AuditLog', object_id_field='object_id', content_type_field='content_type', related_query_name='auditlog') _certidao = GenericRelation( CertidaoPublicacao, related_query_name='documentoadministrativo_cert') _diario = GenericRelation( VinculoDocDiarioOficial, related_query_name='documentoadministrativo_diario') @property def certidao(self): return self._certidao.all().first() @property def diariooficial(self): try: return self._diario.all().first().diario except: return None @property def is_signed(self): try: return self.metadata and self.metadata['signs'] and \ self.metadata['signs']['texto_integral'] and \ self.metadata['signs']['texto_integral']['signs'] except: return False @property def __descr__(self): return self.assunto def __str__(self): if self.epigrafe: return '%s' % self.epigrafe return _('%(sigla)s - %(tipo)s nº %(numero)s/%(ano)s %(interessado)s') % { 'sigla': self.tipo.sigla, 'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano, 'interessado': ('(%s)' % self.interessado) if self.interessado else '' } def delete(self, using=None, keep_parents=False): texto_integral = self.texto_integral result = models.Model.delete( self, 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 if self.visibilidade != self.STATUS_DOC_ADM_PUBLICO: self.link_share = '' r = models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) return r def link_share_create(self): md5 = hashlib.md5() data = '{}{}'.format( timezone.localtime(), serializers.serialize('json', [self])) md5.update(data.encode()) self.link_share = md5.hexdigest() self.visibilidade = self.STATUS_DOC_ADM_PUBLICO self.save()
class SessaoPlenaria(models.Model): FIELDFILE_NAME = ('upload_pauta', 'upload_ata', 'upload_anexo') metadata = JSONField(verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) 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.CASCADE, 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 = PortalFileField(blank=True, null=True, upload_to=pauta_upload_path, verbose_name=_('Pauta da Sessão'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt]) upload_ata = PortalFileField(blank=True, null=True, upload_to=ata_upload_path, storage=OverwriteStorage(), verbose_name=_('Ata da Sessão'), validators=[restringe_tipos_de_arquivo_txt]) upload_anexo = PortalFileField(blank=True, null=True, storage=OverwriteStorage(), 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?'), default=True) finalizada = models.NullBooleanField(blank=True, choices=YES_NO_CHOICES, verbose_name=_('Sessão finalizada?'), default=False) interativa = models.NullBooleanField(blank=True, choices=YES_NO_CHOICES, verbose_name=_('Sessão interativa')) tema_solene = models.TextField(blank=True, max_length=500, verbose_name=_('Tema da Sessão Solene')) data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) class Meta: verbose_name = _('Sessão Plenária') verbose_name_plural = _('Sessões Plenárias') def __str__(self): tnc = self.tipo.TIPO_NUMERACAO_CHOICES base = '{}ª {}'.format(self.numero, self.tipo.nome) if self.tipo.tipo_numeracao == tnc.quizenal: base += ' da {}ª Quinzena'.format( 1 if self.data_inicio.day <= 15 else 2) if self.tipo.tipo_numeracao <= tnc.mensal: base += ' do mês de {}'.format( formats.date_format(self.data_inicio, 'F')) if self.tipo.tipo_numeracao <= tnc.anual: base += ' de {}'.format(self.data_inicio.year) if self.tipo.tipo_numeracao <= tnc.sessao_legislativa: base += ' da {}ª Sessão Legislativa'.format( self.sessao_legislativa.numero) if self.tipo.tipo_numeracao <= tnc.legislatura: base += ' da {}ª Legislatura'.format(self.legislatura.numero) return base """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 str_short(self): tnc = self.tipo.TIPO_NUMERACAO_CHOICES base = '{}ª {}'.format(self.numero, self.tipo.nome) if self.tipo.tipo_numeracao == tnc.quizenal: base += ' da {}ª Quinzena'.format( 1 if self.data_inicio.day <= 15 else 2) if self.tipo.tipo_numeracao <= tnc.mensal: base += ' do mês de {}'.format( formats.date_format(self.data_inicio, 'F')) if self.tipo.tipo_numeracao <= tnc.anual: base += ' de {}'.format(self.data_inicio.year) return base 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) @property def ano(self): return self.data_inicio.year
class Proposicao(CommonMixin): FIELDFILE_NAME = ('texto_original', ) metadata = JSONField(verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) autor = models.ForeignKey(Autor, null=True, blank=True, on_delete=models.PROTECT) tipo = models.ForeignKey(TipoProposicao, on_delete=models.PROTECT, blank=False, null=True, verbose_name=_('Tipo')) # XXX data_envio was not null, but actual data said otherwise!!! data_envio = models.DateTimeField(blank=False, null=True, verbose_name=_('Data de Envio')) data_recebimento = models.DateTimeField( blank=True, null=True, verbose_name=_('Data de Recebimento')) data_devolucao = models.DateTimeField(blank=True, null=True, verbose_name=_('Data de Devolução')) descricao = models.TextField(verbose_name=_('Descrição')) justificativa_devolucao = models.CharField( max_length=200, blank=True, verbose_name=_('Justificativa da Devolução')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), default=None, blank=True, null=True, choices=RANGE_ANOS) numero_proposicao = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('Número')) numero_materia_futuro = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Número Matéria')) hash_code = models.CharField(verbose_name=_('Código do Documento'), max_length=200, blank=True) """ FIXME Campo não é necessário na modelagem e implementação atual para o módulo de proposições. E - Enviada é tratado pela condição do campo data_envio - se None n enviado se possui uma data, enviada R - Recebida é uma condição do campo data_recebimento - se None não receb. se possui uma data, enviada, recebida e incorporada I - A incorporação é automática ao ser recebida e ainda possui a condição de Devolvida onde o campo data_devolucao é direfente de None, fornecedo a informação para o usuário da data que o responsável devolveu bem como a justificativa da devolução. Essa informação fica disponível para o Autor até que ele envie novamente sua proposição ou resolva excluir. """ # ind_enviado and ind_devolvido collapsed as char field (status) status = models.CharField(blank=True, max_length=1, choices=(('E', 'Enviada'), ('R', 'Recebida'), ('I', 'Incorporada')), verbose_name=_('Status Proposição')) texto_original = PortalFileField( upload_to=materia_upload_path, blank=True, null=True, verbose_name=_('Texto Original'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt], max_length=512) texto_articulado = GenericRelation(TextoArticulado, related_query_name='texto_articulado') materia_de_vinculo = models.ForeignKey(MateriaLegislativa, blank=True, null=True, on_delete=models.CASCADE, verbose_name=_('Matéria anexadora'), related_name=_('proposicao_set')) proposicao_vinculada = models.ForeignKey( 'self', blank=True, null=True, on_delete=models.CASCADE, verbose_name=_('Proposição Vinculada'), related_name=_('proposicao_vinculada_set')) content_type = models.ForeignKey(ContentType, default=None, blank=True, null=True, verbose_name=_('Tipo de Material Gerado'), on_delete=PROTECT) object_id = models.PositiveIntegerField(blank=True, null=True, default=None) conteudo_gerado_related = SaplGenericForeignKey( 'content_type', 'object_id', verbose_name=_('Conteúdo Gerado')) observacao = models.TextField(blank=True, verbose_name=_('Observação')) cancelado = models.BooleanField(verbose_name=_('Cancelada ?'), choices=YES_NO_CHOICES, default=False) """# Ao ser recebida, irá gerar uma nova matéria ou um documento acessorio # de uma já existente materia_gerada = models.ForeignKey( MateriaLegislativa, blank=True, null=True, related_name=_('materia_gerada')) documento_gerado = models.ForeignKey( DocumentoAcessorio, blank=True, null=True)""" 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=30, blank=True, default='') ultima_edicao = models.DateTimeField( verbose_name=_('Data e Hora da Edição'), blank=True, null=True) @property def perfis(self): return self.tipo.perfis.all() @property def title_type(self): return '%s nº _____ %s' % (self.tipo, formats.date_format( self.data_envio if self.data_envio else timezone.now(), "\d\e d \d\e F \d\e Y")) class Meta: ordering = ['-data_recebimento'] verbose_name = _('Proposição') verbose_name_plural = _('Proposições') unique_together = (('content_type', 'object_id'), ) permissions = ( ('detail_proposicao_enviada', _('Pode acessar detalhes de uma proposição enviada.')), ('detail_proposicao_devolvida', _('Pode acessar detalhes de uma proposição devolvida.')), ('detail_proposicao_incorporada', _('Pode acessar detalhes de uma proposição incorporada.')), ) def __str__(self): if self.ano and self.numero_proposicao: return '%s %s/%s' % (Proposicao._meta.verbose_name, self.numero_proposicao, self.ano) else: if len(self.descricao) < 30: descricao = self.descricao[:28] + ' ...' else: descricao = self.descricao return '%s %s/%s' % (Proposicao._meta.verbose_name, self.id, descricao) @property def epigrafe(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero_proposicao, 'data': defaultfilters.date( self.data_envio if self.data_envio else timezone.now(), "d \d\e F \d\e Y") } def delete(self, using=None, keep_parents=False): if self.texto_original: self.texto_original.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.texto_original: texto_original = self.texto_original self.texto_original = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.texto_original = texto_original return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
class DocumentoAcessorio(CommonMixin): FIELDFILE_NAME = ('arquivo', ) metadata = JSONField(verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE) tipo = models.ForeignKey(TipoDocumento, on_delete=models.PROTECT, verbose_name=_('Tipo')) nome = models.CharField(max_length=50, verbose_name=_('Título do Documento')) data = models.DateField(blank=True, null=True, default=None, verbose_name=_('Data')) autor = models.CharField(max_length=200, blank=True, verbose_name=_('Autor')) ementa = models.TextField(blank=True, verbose_name=_('Ementa')) indexacao = models.TextField(blank=True) arquivo = PortalFileField(blank=True, null=True, upload_to=anexo_upload_path, verbose_name=_('Texto Integral'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt], max_length=512) proposicao = GenericRelation('Proposicao', related_query_name='proposicao') protocolo_gr = GenericRelation('protocoloadm.Protocolo', object_id_field='conteudo_object_id', content_type_field='conteudo_content_type', related_query_name='protocolo_gr') data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) @property def ano(self): return self.data.year @property def epigrafe_short(self): return self.nome class Meta: verbose_name = _('Documento Acessório') verbose_name_plural = _('Documentos Acessórios') ordering = 'data', 'id' @property def is_signed(self): try: return self.metadata and self.metadata['signs'] and \ self.metadata['signs']['arquivo'] and \ self.metadata['signs']['arquivo']['signs'] except: return False def __str__(self): return _('%(tipo)s - %(nome)s de %(data)s por %(autor)s') % { 'tipo': self.tipo, 'nome': self.nome, 'data': formats.date_format(self.data, "SHORT_DATE_FORMAT") if self.data else '', 'autor': self.autor } def delete(self, using=None, keep_parents=False): for p in self.proposicao.all(): p.conteudo_gerado_related = None p.save() for p in self.protocolo_gr.all(): p.conteudo_protocolado = None p.save() arquivo = self.arquivo try: r = models.Model.delete(self, using=using, keep_parents=keep_parents) except Exception as e: for p in self.proposicao.all(): p.conteudo_gerado_related = self p.save() raise Exception(e) if arquivo: arquivo.delete(save=False) return r def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if not self.pk and self.arquivo: arquivo = self.arquivo self.arquivo = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.arquivo = arquivo return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
class MateriaLegislativa(CommonMixin): objects = MateriaLegislativaManager() FIELDFILE_NAME = ('texto_original', ) metadata = JSONField(verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) tipo = models.ForeignKey( TipoMateriaLegislativa, on_delete=models.PROTECT, verbose_name=TipoMateriaLegislativa._meta.verbose_name) numero = models.PositiveIntegerField(verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) numero_protocolo = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Número do Protocolo')) data_apresentacao = models.DateField( verbose_name=_('Data de Apresentação')) tipo_apresentacao = models.CharField( max_length=1, blank=True, verbose_name=_('Tipo de Apresentação'), choices=TIPO_APRESENTACAO_CHOICES) regime_tramitacao = models.ForeignKey(RegimeTramitacao, on_delete=models.PROTECT, verbose_name=_('Regime Tramitação')) data_publicacao = models.DateField(blank=True, null=True, verbose_name=_('Data de Publicação')) tipo_origem_externa = models.ForeignKey( TipoMateriaLegislativa, blank=True, null=True, related_name='tipo_origem_externa_set', on_delete=models.PROTECT, verbose_name=_('Tipo')) numero_origem_externa = models.CharField(max_length=10, blank=True, verbose_name=_('Número')) ano_origem_externa = models.PositiveSmallIntegerField( blank=True, null=True, verbose_name=_('Ano'), choices=RANGE_ANOS) data_origem_externa = models.DateField(blank=True, null=True, verbose_name=_('Data')) local_origem_externa = models.ForeignKey(Origem, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_('Local de Origem')) apelido = models.CharField(max_length=50, blank=True, verbose_name=_('Apelido')) dias_prazo = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('Dias Prazo')) data_fim_prazo = models.DateField(blank=True, null=True, verbose_name=_('Data Fim Prazo')) em_tramitacao = models.BooleanField(verbose_name=_('Em Tramitação?'), default=False, choices=YES_NO_CHOICES) polemica = models.NullBooleanField(blank=True, verbose_name=_('Matéria Polêmica?')) objeto = models.CharField(max_length=150, blank=True, verbose_name=_('Objeto')) complementar = models.NullBooleanField(blank=True, verbose_name=_('É Complementar?')) ementa = models.TextField(verbose_name=_('Ementa')) indexacao = models.TextField(blank=True, verbose_name=_('Indexação')) observacao = models.TextField(blank=True, verbose_name=_('Observação')) resultado = models.TextField(blank=True) # XXX novo anexadas = models.ManyToManyField('self', blank=True, through='Anexada', symmetrical=False, related_name='anexo_de', through_fields=('materia_principal', 'materia_anexada')) texto_original = PortalFileField( blank=True, null=True, upload_to=materia_upload_path, verbose_name=_('Texto Original'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt], max_length=512) texto_articulado = GenericRelation(TextoArticulado, related_query_name='texto_articulado') proposicao = GenericRelation('Proposicao', related_query_name='proposicao') protocolo_gr = GenericRelation('protocoloadm.Protocolo', object_id_field='conteudo_object_id', content_type_field='conteudo_content_type', related_query_name='protocolo_gr') diariosoficiais = GenericRelation(VinculoDocDiarioOficial, related_query_name='diariosoficiais') autores = models.ManyToManyField( Autor, through='Autoria', through_fields=('materia', 'autor'), symmetrical=False, ) data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) 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=30, blank=True, default='') arquivado = models.BooleanField(verbose_name=_('Arquivamento completo?'), default=False, choices=YES_NO_CHOICES) checkcheck = models.BooleanField( verbose_name=_('Processo Legislativo Auditado?'), default=False, choices=YES_NO_CHOICES) url_video = models.URLField( max_length=150, blank=True, verbose_name=_('URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)')) _certidao = GenericRelation(CertidaoPublicacao, related_query_name='materialegislativa_cert') _diario = GenericRelation(VinculoDocDiarioOficial, related_query_name='materialegislativa_diario') class Meta: verbose_name = _('Matéria Legislativa') verbose_name_plural = _('Matérias Legislativas') unique_together = (("tipo", "numero", "ano"), ) ordering = ['-id'] permissions = ( ("can_access_impressos", "Can access impressos"), ("can_check_complete", "Pode checar conclusão de processo"), ) @property def __descr__(self): return str(self.ementa) @property def certidao(self): return self._certidao.all().first() @property def diariooficial(self): try: return self._diario.all().first().diario except: return None def __str__(self): return _('%(tipo)s nº %(numero)s de %(ano)s') % { 'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano } @property def is_signed(self): try: return self.metadata and self.metadata['signs'] and \ self.metadata['signs']['texto_original'] and \ self.metadata['signs']['texto_original']['signs'] except: return False @property def epigrafe(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero, 'data': defaultfilters.date(self.data_apresentacao, "d \d\e F \d\e Y") } @property def epigrafe_short(self): return '{} {:03d}/{}'.format(self.tipo.sigla, self.numero, self.ano) def data_entrada_protocolo(self): ''' hack: recuperar a data de entrada do protocolo sem gerar dependência circular ''' from sapl.protocoloadm.models import Protocolo if self.ano and self.numero_protocolo: protocolo = Protocolo.objects.filter( ano=self.ano, numero=self.numero_protocolo).first() if protocolo: if protocolo.timestamp: return protocolo.timestamp.date() elif protocolo.timestamp_data_hora_manual: return protocolo.timestamp_data_hora_manual.date() elif protocolo.data: return protocolo.data return '' def delete(self, using=None, keep_parents=False): if self.texto_original: self.texto_original.delete() for p in self.proposicao.all(): p.conteudo_gerado_related = None p.cancelado = True p.save() for p in self.protocolo_gr.all(): p.conteudo_protocolado = None p.save() 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.texto_original: texto_original = self.texto_original self.texto_original = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.texto_original = texto_original return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) def autografo(self): return self.normajuridica_set.filter(tipo_id=27).first() def normajuridica(self): return self.normajuridica_set.exclude(tipo_id=27).first() def autografovinculado_a_normajuridica(self): nr = self.normajuridica_set.exclude( tipo_id=27).first().norma_principal.filter( norma_relacionada__tipo_id=27).first() if nr: return nr.norma_relacionada return ''
class NormaJuridica(CommonMixin): FIELDFILE_NAME = ('texto_integral', ) ESFERA_FEDERACAO_CHOICES = Choices( ('M', 'municipal', _('Municipal')), ('E', 'estadual', _('Estadual')), ('F', 'federal', _('Federal')), ) metadata = JSONField( verbose_name=_('Metadados'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) texto_integral = PortalFileField( blank=True, null=True, upload_to=norma_upload_path, verbose_name=_('Texto Integral'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt], max_length=512) 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')) 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')) 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.NullBooleanField( blank=True, 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') diariosoficiais = GenericRelation( VinculoDocDiarioOficial, related_query_name='diariosoficiais') 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) norma_de_destaque = models.BooleanField(verbose_name=_('Norma de Destaque ?'), choices=YES_NO_CHOICES, default=False) apelido = models.TextField( blank=True, verbose_name=_('Apelido')) 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=30, blank=True, default='' ) checkcheck = models.BooleanField( verbose_name=_('Registro de Norma Jurídica Auditado?'), default=False, choices=YES_NO_CHOICES) _certidao = GenericRelation( CertidaoPublicacao, related_query_name='normajuridica_cert') _diario = GenericRelation( VinculoDocDiarioOficial, related_query_name='normajuridica_diario') 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 @property def is_signed(self): try: return self.metadata and self.metadata['signs'] and \ self.metadata['signs']['texto_integral'] and \ self.metadata['signs']['texto_integral']['signs'] except: return False @property def certidao(self): return self._certidao.all().first() @property def diariooficial(self): try: return self._diario.all().first().diario except: return None @property def __descr__(self): return self.ementa def __str__(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")} @property def epigrafe(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y")} def delete(self, using=None, keep_parents=False): if self.texto_integral: self.texto_integral.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.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)
class DocumentoAcessorio(models.Model): materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE) tipo = models.ForeignKey(TipoDocumento, on_delete=models.PROTECT, verbose_name=_('Tipo')) nome = models.CharField(max_length=50, verbose_name=_('Nome')) data = models.DateField(blank=True, null=True, default=None, verbose_name=_('Data')) autor = models.CharField(max_length=200, blank=True, verbose_name=_('Autor')) ementa = models.TextField(blank=True, verbose_name=_('Ementa')) indexacao = models.TextField(blank=True) arquivo = PortalFileField(blank=True, null=True, max_length=255, upload_to=anexo_upload_path, verbose_name=_('Texto Integral'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt]) proposicao = GenericRelation('Proposicao', related_query_name='proposicao') data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) @property def ano(self): return self.data.year class Meta: verbose_name = _('Documento Acessório') verbose_name_plural = _('Documentos Acessórios') ordering = 'data', 'id' def __str__(self): return _('%(tipo)s - %(nome)s de %(data)s por %(autor)s') % { 'tipo': self.tipo, 'nome': self.nome, 'data': formats.date_format(self.data, "SHORT_DATE_FORMAT") if self.data else '', 'autor': self.autor } def delete(self, using=None, keep_parents=False): for p in self.proposicao.all(): p.conteudo_gerado_related = None p.save() arquivo = self.arquivo try: r = models.Model.delete(self, using=using, keep_parents=keep_parents) except Exception as e: for p in self.proposicao.all(): p.conteudo_gerado_related = self p.save() raise Exception(e) if arquivo: arquivo.delete(save=False) return r def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if not self.pk and self.arquivo: arquivo = self.arquivo self.arquivo = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.arquivo = arquivo return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
class MateriaLegislativa(models.Model): tipo = models.ForeignKey( TipoMateriaLegislativa, on_delete=models.PROTECT, verbose_name=TipoMateriaLegislativa._meta.verbose_name) numero = models.PositiveIntegerField(verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) numero_protocolo = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Número do Protocolo')) data_apresentacao = models.DateField( verbose_name=_('Data de Apresentação')) tipo_apresentacao = models.CharField( max_length=1, blank=True, verbose_name=_('Tipo de Apresentação'), choices=TIPO_APRESENTACAO_CHOICES) regime_tramitacao = models.ForeignKey(RegimeTramitacao, on_delete=models.PROTECT, verbose_name=_('Regime Tramitação')) data_publicacao = models.DateField(blank=True, null=True, verbose_name=_('Data de Publicação')) tipo_origem_externa = models.ForeignKey( TipoMateriaLegislativa, blank=True, null=True, related_name='tipo_origem_externa_set', on_delete=models.PROTECT, verbose_name=_('Tipo')) numero_origem_externa = models.CharField(max_length=10, blank=True, verbose_name=_('Número')) ano_origem_externa = models.PositiveSmallIntegerField( blank=True, null=True, verbose_name=_('Ano'), choices=RANGE_ANOS) data_origem_externa = models.DateField(blank=True, null=True, verbose_name=_('Data')) local_origem_externa = models.ForeignKey(Origem, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_('Local de Origem')) apelido = models.CharField(max_length=50, blank=True, verbose_name=_('Apelido')) dias_prazo = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('Dias Prazo')) data_fim_prazo = models.DateField(blank=True, null=True, verbose_name=_('Data Fim Prazo')) em_tramitacao = models.BooleanField(verbose_name=_('Em Tramitação?'), default=False, choices=YES_NO_CHOICES) polemica = models.NullBooleanField(blank=True, verbose_name=_('Matéria Polêmica?')) objeto = models.CharField(max_length=150, blank=True, verbose_name=_('Objeto')) complementar = models.NullBooleanField(blank=True, verbose_name=_('É Complementar?')) ementa = models.TextField(verbose_name=_('Ementa')) indexacao = models.TextField(blank=True, verbose_name=_('Indexação')) observacao = models.TextField(blank=True, verbose_name=_('Observação')) resultado = models.TextField(blank=True) # XXX novo anexadas = models.ManyToManyField('self', blank=True, through='Anexada', symmetrical=False, related_name='anexo_de', through_fields=('materia_principal', 'materia_anexada')) texto_original = PortalFileField( blank=True, null=True, upload_to=materia_upload_path, verbose_name=_('Texto Original'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt]) texto_articulado = GenericRelation(TextoArticulado, related_query_name='texto_articulado') proposicao = GenericRelation('Proposicao', related_query_name='proposicao') autores = models.ManyToManyField( Autor, through='Autoria', through_fields=('materia', 'autor'), symmetrical=False, ) data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) 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=30, blank=True, default='') arquivado = models.BooleanField(verbose_name=_('Arquivamento completo?'), default=False, choices=YES_NO_CHOICES) checkcheck = models.BooleanField( verbose_name=_('Processo Legislativo Auditado?'), default=False, choices=YES_NO_CHOICES) class Meta: verbose_name = _('Matéria Legislativa') verbose_name_plural = _('Matérias Legislativas') unique_together = (("tipo", "numero", "ano"), ) ordering = ['-id'] permissions = (("can_access_impressos", "Can access impressos"), ) def __str__(self): return _('%(tipo)s nº %(numero)s de %(ano)s') % { 'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano } @property def epigrafe(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero, 'data': defaultfilters.date(self.data_apresentacao, "d \d\e F \d\e Y") } def data_entrada_protocolo(self): ''' hack: recuperar a data de entrada do protocolo sem gerar dependência circular ''' from sapl.protocoloadm.models import Protocolo if self.ano and self.numero_protocolo: protocolo = Protocolo.objects.filter( ano=self.ano, numero=self.numero_protocolo).first() if protocolo: if protocolo.timestamp: return protocolo.timestamp.date() elif protocolo.timestamp_data_hora_manual: return protocolo.timestamp_data_hora_manual.date() elif protocolo.data: return protocolo.data return '' def delete(self, using=None, keep_parents=False): if self.texto_original: self.texto_original.delete() for p in self.proposicao.all(): p.conteudo_gerado_related = None p.cancelado = True p.save() 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.texto_original: texto_original = self.texto_original self.texto_original = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.texto_original = texto_original return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) def autografo(self): return self.normajuridica_set.filter(tipo_id=27).first() def normajuridica(self): return self.normajuridica_set.exclude(tipo_id=27).first()
class DocumentoAdministrativo(models.Model): tipo = models.ForeignKey(TipoDocumentoAdministrativo, on_delete=models.PROTECT, verbose_name=_('Tipo Documento')) numero = models.PositiveIntegerField(verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) protocolo = models.ForeignKey(Protocolo, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_('Protocolo')) materia = models.ForeignKey(MateriaLegislativa, blank=True, null=True, on_delete=models.PROTECT, related_name='documentoadministrativo_set', verbose_name=_('Matéria Vinculada')) data = models.DateField(verbose_name=_('Data')) temp_migracao_doc_acessorio = models.PositiveIntegerField( blank=True, null=True, verbose_name=_( 'Field temporário para migração dos docs acessórios da procuradoria' )) temp_migracao_sislegis = models.PositiveIntegerField( blank=True, null=True, verbose_name=_( 'Field temporário para migração dos docs adms do sislegis')) old_path = models.TextField( verbose_name=_('Path antigo para Sislegis - Publicações'), blank=True, null=True, default=None) old_json = JSONField(verbose_name=_('Json from origin import'), blank=True, null=True, default=None, encoder=DjangoJSONEncoder) epigrafe = models.CharField(max_length=1000, blank=True, verbose_name=_('Epigrafe / Título')) interessado = models.CharField(max_length=1000, blank=True, verbose_name=_('Interessado')) autor = models.ForeignKey(Autor, blank=True, null=True, on_delete=models.PROTECT) dias_prazo = models.PositiveIntegerField(blank=True, null=True, verbose_name=_('Dias Prazo')) data_fim_prazo = models.DateField(blank=True, null=True, verbose_name=_('Data Fim Prazo')) data_vencimento = models.DateField(blank=True, null=True, verbose_name=_('Data de Vencimento')) tramitacao = models.BooleanField(verbose_name=_('Em Tramitação?'), choices=YES_NO_CHOICES, default=False) assunto = models.TextField(blank=True, null=True, verbose_name=_('Assunto')) numero_externo = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Número Externo')) observacao = models.TextField(blank=True, verbose_name=_('Resumo')) texto_integral = PortalFileField(blank=True, null=True, storage=OverwriteStorage(), upload_to=texto_upload_path, verbose_name=_('Texto Integral')) anexados = models.ManyToManyField('self', blank=True, through='Anexado', symmetrical=False, related_name='anexo_de', through_fields=('documento_principal', 'documento_anexado')) workspace = models.ForeignKey(AreaTrabalho, verbose_name=_('Área de Trabalho'), related_name='documentoadministrativo_set', blank=True, null=True, on_delete=PROTECT) data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) _certidao = GenericRelation( CertidaoPublicacao, related_query_name='documentoadministrativo_cert') class Meta: verbose_name = _('Documento Administrativo') verbose_name_plural = _('Documentos Administrativos') @property def certidao(self): return self._certidao.all().first() @property def __descr__(self): return self.assunto def __str__(self): if self.epigrafe: return '%s' % self.epigrafe return _( '%(sigla)s - %(tipo)s nº %(numero)s/%(ano)s %(interessado)s') % { 'sigla': self.tipo.sigla, 'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano, 'interessado': ('(%s)' % self.interessado) if self.interessado else '' } def delete(self, using=None, keep_parents=False): texto_integral = self.texto_integral result = models.Model.delete(self, 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)