Browse Source

Impl parametrização da identificação de docs adms (#3588)

* ajusta front do form de configurações da aplicação

* cria parametrização para identificação de doc adms
pull/3587/head
LeandroJataí 2 years ago
committed by GitHub
parent
commit
4d25239d86
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      sapl/base/forms.py
  2. 23
      sapl/base/migrations/0051_auto_20220814_2138.py
  3. 185
      sapl/base/models.py
  4. 45
      sapl/base/views.py
  5. 4
      sapl/norma/models.py
  6. 3
      sapl/protocoloadm/forms.py
  7. 76
      sapl/protocoloadm/models.py
  8. 2
      sapl/protocoloadm/views.py
  9. 6
      sapl/templates/base/AppConfig.html
  10. 38
      sapl/templates/base/appconfig_form.html
  11. 34
      sapl/templates/base/layouts.yaml
  12. 1
      sapl/templates/materia/layouts.yaml
  13. 20
      sapl/templates/materia/materialegislativa_detail.html
  14. 2
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  15. 2
      sapl/templates/protocoloadm/layouts.yaml
  16. 3
      sapl/utils.py

3
sapl/base/forms.py

@ -1583,7 +1583,8 @@ class ConfiguracoesAppForm(ModelForm):
'tramitacao_documento', 'tramitacao_documento',
'google_recaptcha_site_key', 'google_recaptcha_site_key',
'google_recaptcha_secret_key', 'google_recaptcha_secret_key',
'sapl_as_sapn'] 'sapl_as_sapn',
'identificacao_de_documentos']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ConfiguracoesAppForm, self).__init__(*args, **kwargs) super(ConfiguracoesAppForm, self).__init__(*args, **kwargs)

23
sapl/base/migrations/0051_auto_20220814_2138.py

@ -0,0 +1,23 @@
# Generated by Django 2.2.28 on 2022-08-15 00:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0050_metadata'),
]
operations = [
migrations.AddField(
model_name='appconfig',
name='identificacao_de_documentos',
field=models.CharField(default='{sigla}{numero}/{ano}{-}{complemento} - {nome}', help_text='\n Como mostrar a identificação dos documentos administrativos?\n Você pode usar um conjunto de combinações que pretender.\n Ao fazer sua edição, será mostrado logo abaixo o último documento cadastrado, como exemplo de resultado de sua edição.\n Em caso de erro, nenhum documento será mostrado e aparecerá apenas o formato padrão mínimo, que é este: "{sigla}{numero}/{ano}{-}{complemento} - {nome}".\n Muito importante, use as chaves "{}", sem elas, você estará inserindo um texto qualquer e não o valor de um campo.\n Você pode combinar as seguintes campos: {sigla} {nome} {numero} {ano} {complemento} {assunto}\n Ainda pode ser usado {/}, {-}, {.} se você quiser que uma barra, traço, ou ponto\n seja adicionado apenas se o próximo campo que será usado tenha algum conteúdo\n (não use dois destes destes condicionais em sequência, somente o último será considerado).\n ', max_length=254, verbose_name='Formato da identificação dos documentos'),
),
migrations.AlterField(
model_name='appconfig',
name='protocolo_manual',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Permitir informe manual de data e hora de protocolo?'),
),
]

185
sapl/base/models.py

@ -1,6 +1,7 @@
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields.jsonb import JSONField from django.contrib.postgres.fields.jsonb import JSONField
from django.core.cache import cache
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.db import models from django.db import models
from django.db.models.deletion import CASCADE from django.db.models.deletion import CASCADE
@ -93,63 +94,124 @@ class AppConfig(models.Model):
('N', _('Nunca Protocolar ao incorporar uma proposição')), ('N', _('Nunca Protocolar ao incorporar uma proposição')),
) )
documentos_administrativos = models.CharField( # MANTENHA A SEQUÊNCIA EQUIVALENTE COM /sapl/templates/base/layout.yaml
max_length=1, # AppConfig:
verbose_name=_('Visibilidade dos Documentos Administrativos'),
choices=TIPO_DOCUMENTO_ADMINISTRATIVO, default='O')
estatisticas_acesso_normas = models.CharField( # CONFIGURAÇÕES GERAIS
# Linha 1 ------------
esfera_federacao = models.CharField(
max_length=1, max_length=1,
verbose_name=_('Estatísticas de acesso a normas'), blank=True,
choices=RELATORIO_ATOS_ACESSADOS, default='N') default="",
verbose_name=_('Esfera Federação'),
choices=ESFERA_FEDERACAO_CHOICES)
sapl_as_sapn = models.BooleanField(
verbose_name=_(
'Utilizar SAPL como SAPN?'),
choices=YES_NO_CHOICES, default=False)
sequencia_numeracao_proposicao = models.CharField( # MÓDULO PARLAMENTARES
max_length=1,
verbose_name=_('Sequência de numeração de proposições'),
choices=SEQUENCIA_NUMERACAO_PROPOSICAO, default='A')
# MÓDULO MESA DIRETORA
# MÓDULO COMISSÕES
# MÓDULO BANCADAS PARLAMENTARES
# MÓDULO DOCUMENTOS ADMINISTRATIVOS
# Linha 1 -------------------------
documentos_administrativos = models.CharField(
max_length=1,
verbose_name=_('Visibilidade dos Documentos Administrativos'),
choices=TIPO_DOCUMENTO_ADMINISTRATIVO, default='O')
tramitacao_documento = models.BooleanField(
verbose_name=_(
'Tramitar documentos anexados junto com os documentos principais?'),
choices=YES_NO_CHOICES, default=True)
# Linha 2 -------------------------
protocolo_manual = models.BooleanField(
verbose_name=_('Permitir informe manual de data e hora de protocolo?'),
choices=YES_NO_CHOICES, default=False)
sequencia_numeracao_protocolo = models.CharField( sequencia_numeracao_protocolo = models.CharField(
max_length=1, max_length=1,
verbose_name=_('Sequência de numeração de protocolos'), verbose_name=_('Sequência de numeração de protocolos'),
choices=SEQUENCIA_NUMERACAO_PROTOCOLO, default='A') choices=SEQUENCIA_NUMERACAO_PROTOCOLO, default='A')
inicio_numeracao_protocolo = models.PositiveIntegerField( inicio_numeracao_protocolo = models.PositiveIntegerField(
verbose_name=_('Início da numeração de protocolo'), verbose_name=_('Início da numeração de protocolo'),
default=1 default=1
) )
# Linha 3 -------------------------
identificacao_de_documentos = models.CharField(
max_length=254,
verbose_name=_('Formato da identificação dos documentos'),
default='{sigla}{numero}/{ano}{-}{complemento} - {nome}',
help_text="""
Como mostrar a identificação dos documentos administrativos?
Você pode usar um conjunto de combinações que pretender.
Ao fazer sua edição, será mostrado logo abaixo o último documento cadastrado, como exemplo de resultado de sua edição.
Em caso de erro, nenhum documento será mostrado e aparecerá apenas o formato padrão mínimo, que é este: "{sigla}{numero}/{ano}{-}{complemento} - {nome}".
Muito importante, use as chaves "{}", sem elas, você estará inserindo um texto qualquer e não o valor de um campo.
Você pode combinar as seguintes campos: {sigla} {nome} {numero} {ano} {complemento} {assunto}
Ainda pode ser usado {/}, {-}, {.} se você quiser que uma barra, traço, ou ponto
seja adicionado apenas se o próximo campo que será usado tenha algum conteúdo
(não use dois destes destes condicionais em sequência, somente o último será considerado).
"""
)
esfera_federacao = models.CharField( # MÓDULO PROPOSIÇÕES
# Linha 1 ----------
sequencia_numeracao_proposicao = models.CharField(
max_length=1, max_length=1,
blank=True, verbose_name=_('Sequência de numeração de proposições'),
default="", choices=SEQUENCIA_NUMERACAO_PROPOSICAO, default='A')
verbose_name=_('Esfera Federação'), receber_recibo_proposicao = models.BooleanField(
choices=ESFERA_FEDERACAO_CHOICES) verbose_name=_('Protocolar proposição somente com recibo?'),
choices=YES_NO_CHOICES, default=True)
proposicao_incorporacao_obrigatoria = models.CharField(
verbose_name=_('Regra de incorporação de proposições e protocolo'),
max_length=1, choices=POLITICA_PROTOCOLO_CHOICES, default='O')
escolher_numero_materia_proposicao = models.BooleanField(
verbose_name=_(
'Indicar número da matéria a ser gerada na proposição?'),
choices=YES_NO_CHOICES, default=False)
# TODO: a ser implementado na versão 3.2 # MÓDULO MATÉRIA LEGISLATIVA
# painel_aberto = models.BooleanField( # Linha 1 ------------------
# verbose_name=_('Painel aberto para usuário anônimo'), tramitacao_origem_fixa = models.BooleanField(
# choices=YES_NO_CHOICES, default=False) verbose_name=_(
'Fixar origem de novas tramitações como sendo a tramitação de destino da última tramitação?'),
choices=YES_NO_CHOICES,
default=True,
help_text=_('Ao utilizar a opção NÂO, você compreende que os controles '
'de origem e destino das tramitações são anulados, '
'podendo seu operador registrar quaisquer origem e '
'destino para as tramitações. Se você colocar Não, '
'fizer tramitações aleatórias e voltar para SIM, '
'o destino da tramitação mais recente será utilizado '
'para a origem de uma nova inserção!'))
tramitacao_materia = models.BooleanField(
verbose_name=_(
'Tramitar matérias anexadas junto com as matérias principais?'),
choices=YES_NO_CHOICES, default=True)
# MÓDULO NORMAS JURÍDICAS
# MÓDULO TEXTOS ARTICULADOS
# Linha 1 -----------------
texto_articulado_proposicao = models.BooleanField( texto_articulado_proposicao = models.BooleanField(
verbose_name=_('Usar Textos Articulados para Proposições'), verbose_name=_('Usar Textos Articulados para Proposições'),
choices=YES_NO_CHOICES, default=False) choices=YES_NO_CHOICES, default=False)
texto_articulado_materia = models.BooleanField( texto_articulado_materia = models.BooleanField(
verbose_name=_('Usar Textos Articulados para Matérias'), verbose_name=_('Usar Textos Articulados para Matérias'),
choices=YES_NO_CHOICES, default=False) choices=YES_NO_CHOICES, default=False)
texto_articulado_norma = models.BooleanField( texto_articulado_norma = models.BooleanField(
verbose_name=_('Usar Textos Articulados para Normas'), verbose_name=_('Usar Textos Articulados para Normas'),
choices=YES_NO_CHOICES, default=True) choices=YES_NO_CHOICES, default=True)
proposicao_incorporacao_obrigatoria = models.CharField( # MÓDULO SESSÃO PLENÁRIA
verbose_name=_('Regra de incorporação de proposições e protocolo'),
max_length=1, choices=POLITICA_PROTOCOLO_CHOICES, default='O')
assinatura_ata = models.CharField( assinatura_ata = models.CharField(
verbose_name=_('Quem deve assinar a ata'), verbose_name=_('Quem deve assinar a ata'),
max_length=1, choices=ASSINATURA_ATA_CHOICES, default='T') max_length=1, choices=ASSINATURA_ATA_CHOICES, default='T')
# MÓDULO PAINEL
cronometro_discurso = models.DurationField( cronometro_discurso = models.DurationField(
verbose_name=_('Cronômetro do Discurso'), verbose_name=_('Cronômetro do Discurso'),
blank=True, blank=True,
@ -174,41 +236,20 @@ class AppConfig(models.Model):
default=False, default=False,
verbose_name=_('Mostrar brasão da Casa no painel?')) verbose_name=_('Mostrar brasão da Casa no painel?'))
receber_recibo_proposicao = models.BooleanField( # MÓDULO ESTATÍSTICAS DE ACESSO
verbose_name=_('Protocolar proposição somente com recibo?'), estatisticas_acesso_normas = models.CharField(
choices=YES_NO_CHOICES, default=True) max_length=1,
verbose_name=_('Estatísticas de acesso a normas'),
protocolo_manual = models.BooleanField( choices=RELATORIO_ATOS_ACESSADOS, default='N')
verbose_name=_('Informar data e hora de protocolo?'),
choices=YES_NO_CHOICES, default=False)
escolher_numero_materia_proposicao = models.BooleanField(
verbose_name=_(
'Indicar número da matéria a ser gerada na proposição?'),
choices=YES_NO_CHOICES, default=False)
tramitacao_origem_fixa = models.BooleanField( # MÓDULO SEGURANÇA
verbose_name=_(
'Fixar origem de novas tramitações como sendo a tramitação de destino da última tramitação?'),
choices=YES_NO_CHOICES,
default=True,
help_text=_('Ao utilizar a opção NÂO, você compreende que os controles '
'de origem e destino das tramitações são anulados, '
'podendo seu operador registrar quaisquer origem e '
'destino para as tramitações. Se você colocar Não, '
'fizer tramitações aleatórias e voltar para SIM, '
'o destino da tramitação mais recente será utilizado '
'para a origem de uma nova inserção!'))
tramitacao_materia = models.BooleanField( # MÓDULO LEXML
verbose_name=_(
'Tramitar matérias anexadas junto com as matérias principais?'),
choices=YES_NO_CHOICES, default=True)
tramitacao_documento = models.BooleanField( # TODO: a ser implementado na versão 3.2
verbose_name=_( # painel_aberto = models.BooleanField(
'Tramitar documentos anexados junto com os documentos principais?'), # verbose_name=_('Painel aberto para usuário anônimo'),
choices=YES_NO_CHOICES, default=True) # choices=YES_NO_CHOICES, default=False)
google_recaptcha_site_key = models.CharField( google_recaptcha_site_key = models.CharField(
verbose_name=_('Chave pública gerada pelo Google Recaptcha'), verbose_name=_('Chave pública gerada pelo Google Recaptcha'),
@ -217,11 +258,6 @@ class AppConfig(models.Model):
verbose_name=_('Chave privada gerada pelo Google Recaptcha'), verbose_name=_('Chave privada gerada pelo Google Recaptcha'),
max_length=256, default='') max_length=256, default='')
sapl_as_sapn = models.BooleanField(
verbose_name=_(
'Utilizar SAPL como SAPN?'),
choices=YES_NO_CHOICES, default=False)
class Meta: class Meta:
verbose_name = _('Configurações da Aplicação') verbose_name = _('Configurações da Aplicação')
verbose_name_plural = _('Configurações da Aplicação') verbose_name_plural = _('Configurações da Aplicação')
@ -231,15 +267,32 @@ class AppConfig(models.Model):
) )
ordering = ('-id',) ordering = ('-id',)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
fields = self._meta.get_fields()
for f in fields:
if f.name != 'id' and not cache.get(f'sapl_{f.name}') is None:
cache.set(f'sapl_{f.name}', getattr(self, f.name), 600)
return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
@classmethod @classmethod
def attr(cls, attr): def attr(cls, attr):
value = cache.get(f'sapl_{attr}')
if not value is None:
return value
print(f'entrou aqui para {attr}')
config = AppConfig.objects.first() config = AppConfig.objects.first()
if not config: if not config:
config = AppConfig() config = AppConfig()
config.save() config.save()
return getattr(config, attr) value = getattr(config, attr)
cache.set(f'sapl_{attr}', value, 600)
return value
def __str__(self): def __str__(self):
return _('Configurações da Aplicação - %(id)s') % { return _('Configurações da Aplicação - %(id)s') % {

45
sapl/base/views.py

@ -4,7 +4,9 @@ import datetime
import itertools import itertools
import logging import logging
import os import os
import re
from django.apps.registry import apps
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import get_user_model, views from django.contrib.auth import get_user_model, views
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
@ -32,8 +34,8 @@ from django.views.generic.base import RedirectView, TemplateView
from django_filters.views import FilterView from django_filters.views import FilterView
from haystack.query import SearchQuerySet from haystack.query import SearchQuerySet
from haystack.views import SearchView from haystack.views import SearchView
from ratelimit.decorators import ratelimit from ratelimit.decorators import ratelimit
from sapl import settings from sapl import settings
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
from sapl.base.forms import (AutorForm, TipoAutorForm, AutorFilterSet, RecuperarSenhaForm, from sapl.base.forms import (AutorForm, TipoAutorForm, AutorFilterSet, RecuperarSenhaForm,
@ -1893,6 +1895,7 @@ class UserCrud(Crud):
list_field_names = [ list_field_names = [
'usuario', 'groups', 'is_active' 'usuario', 'groups', 'is_active'
] ]
def openapi_url(self): def openapi_url(self):
return '' return ''
@ -1927,7 +1930,6 @@ class UserCrud(Crud):
class DetailView(Crud.DetailView): class DetailView(Crud.DetailView):
layout_key = 'UserDetail' layout_key = 'UserDetail'
def hook_usuario(self, obj): def hook_usuario(self, obj):
return 'Usuário', '{}<br><small>{}</small>'.format( return 'Usuário', '{}<br><small>{}</small>'.format(
obj.get_full_name() or '...', obj.get_full_name() or '...',
@ -2100,10 +2102,45 @@ class AppConfigCrud(CrudAux):
kwargs={'pk': app_config.pk})) kwargs={'pk': app_config.pk}))
class UpdateView(CrudAux.UpdateView): class UpdateView(CrudAux.UpdateView):
template_name = 'base/AppConfig.html'
form_class = ConfiguracoesAppForm form_class = ConfiguracoesAppForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = self.model._meta.verbose_name
return context
def get(self, request, *args, **kwargs):
if 'jsidd' in request.GET:
return self.json_simular_identificacao_de_documentos(request, *args, **kwargs)
return super().get(request, *args, **kwargs)
def json_simular_identificacao_de_documentos(self, request, *args, **kwargs):
DocumentoAdministrativo = apps.get_model(
'protocoloadm',
'DocumentoAdministrativo'
)
d = DocumentoAdministrativo.objects.order_by('-id').first()
jsidd = request.GET.get('jsidd', '')
values = {
'{sigla}': d.tipo.sigla if d else 'OF',
'{nome}': d.tipo.descricao if d else 'Ofício',
'{numero}': f'{d.numero:0>3}' if d else '001',
'{ano}': f'{d.ano}' if d else str(timezone.now().year),
'{complemento}': d.complemento if d else 'GAB',
'{assunto}': d.assunto if d else 'Simulação de Identificação de Documentos'
}
result = DocumentoAdministrativo.mask_to_str(values, jsidd)
return JsonResponse({
'jsidd': result[0],
'error': list(result[1])
})
def form_valid(self, form): def form_valid(self, form):
numeracao = AppConfig.objects.last().sequencia_numeracao_protocolo numeracao = AppConfig.objects.last().sequencia_numeracao_protocolo
numeracao_antiga = AppConfig.objects.last().inicio_numeracao_protocolo numeracao_antiga = AppConfig.objects.last().inicio_numeracao_protocolo

4
sapl/norma/models.py

@ -151,7 +151,9 @@ class NormaJuridica(models.Model):
verbose_name=_('Tipo da Norma Jurídica')) verbose_name=_('Tipo da Norma Jurídica'))
materia = models.ForeignKey( materia = models.ForeignKey(
MateriaLegislativa, blank=True, null=True, MateriaLegislativa, blank=True, null=True,
on_delete=models.PROTECT, verbose_name=_('Matéria')) on_delete=models.PROTECT,
verbose_name=_('Matéria'),
related_name='normajuridica_set')
orgao = models.ForeignKey( orgao = models.ForeignKey(
Orgao, blank=True, null=True, Orgao, blank=True, null=True,
on_delete=models.PROTECT, verbose_name=_('Órgão')) on_delete=models.PROTECT, verbose_name=_('Órgão'))

3
sapl/protocoloadm/forms.py

@ -1139,7 +1139,8 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
tipo = TipoDocumentoAdministrativo.objects.get( tipo = TipoDocumentoAdministrativo.objects.get(
id=tipo_documento) id=tipo_documento)
raise ValidationError( raise ValidationError(
_('{}/{} ({}) já existente!'.format(numero_documento, _('{}/{} ({}) já existente! '
'Você diferenciar preenchendo o campo complemento'.format(numero_documento,
ano_documento, ano_documento,
tipo))) tipo)))

76
sapl/protocoloadm/models.py

@ -1,10 +1,13 @@
import re
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
import reversion import reversion
from sapl.base.models import Autor from sapl.base.models import Autor, AppConfig as SaplAppConfig
from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao,\ from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao,\
MateriaLegislativa MateriaLegislativa
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path,
@ -250,19 +253,67 @@ class DocumentoAdministrativo(models.Model):
verbose_name_plural = _('Documentos Administrativos') verbose_name_plural = _('Documentos Administrativos')
ordering = ('id',) ordering = ('id',)
def __str__(self): @classmethod
return _('%(tipo)s - %(assunto)s') % { def mask_to_str(cls, values, mask):
'tipo': self.tipo, 'assunto': self.assunto erro = set()
pattern = '({[^{}]+}|{[ /.-]*})'
campos_escolhidos = re.findall(pattern, mask)
campos_permitidos = {
'{.}', '{/}', '{-}',
'{sigla}',
'{nome}',
'{numero}',
'{ano}',
'{complemento}',
'{assunto}',
}
condicionais = {
'{.}': '.',
'{/}': '/',
'{-}': '-',
} }
@property erro = set(campos_escolhidos) - campos_permitidos
def epigrafe(self):
return _('%(tipo)s - %(numero)s/%(ano)s') % { if erro:
'tipo': self.tipo, mask = '{sigla}{numero}/{ano}{-}{complemento} - {nome}'
'numero': self.numero, campos_escolhidos = re.findall(pattern, mask)
'ano': self.ano
for i, k in enumerate(campos_escolhidos):
if k in values.keys():
if i > 0 and campos_escolhidos[i - 1] in condicionais:
mask = mask.replace(
campos_escolhidos[i - 1],
condicionais[campos_escolhidos[i - 1]]if values[k] else '', 1)
mask = mask.replace(k, values[k], 1)
elif k in condicionais:
if i > 0 and campos_escolhidos[i - 1] in condicionais:
mask = mask.replace(
campos_escolhidos[i - 1],
'', 1)
if i + 1 == len(campos_escolhidos):
mask = mask.replace(k, '', 1)
return mask, erro
@cached_property
def _identificacao_de_documento(self):
mask = SaplAppConfig.attr('identificacao_de_documentos')
values = {
'{sigla}': self.tipo.sigla,
'{nome}': self.tipo.descricao,
'{numero}': f'{self.numero:0>3}',
'{ano}': f'{self.ano}',
'{complemento}': self.complemento,
'{assunto}': self.assunto
} }
return DocumentoAdministrativo.mask_to_str(values, mask)[0]
def __str__(self):
return self._identificacao_de_documento
def delete(self, using=None, keep_parents=False): def delete(self, using=None, keep_parents=False):
texto_integral = self.texto_integral texto_integral = self.texto_integral
result = super().delete(using=using, keep_parents=keep_parents) result = super().delete(using=using, keep_parents=keep_parents)
@ -487,11 +538,6 @@ class VinculoDocAdminMateria(models.Model):
def __str__(self): def __str__(self):
return f'Vinculo: {self.documento} - {self.materia}' return f'Vinculo: {self.documento} - {self.materia}'
return _('Vinculo %(documento)s // %(materia)s') % {
'documento': self.documento.epigrafe,
'materia': self.materia
}
@reversion.register() @reversion.register()
class AcompanhamentoDocumento(models.Model): class AcompanhamentoDocumento(models.Model):

2
sapl/protocoloadm/views.py

@ -1783,7 +1783,7 @@ class VinculoDocAdminMateriaCrud(MasterDetailCrud):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = self.object.documento.epigrafe context['title'] = self.object.documento
return context return context
def get_initial(self): def get_initial(self):

6
sapl/templates/base/AppConfig.html

@ -1,6 +0,0 @@
{% extends "base.html" %}
{% load i18n crispy_forms_tags menus%}
{% block base_content %}
{% crispy form %}
{% endblock base_content %}

38
sapl/templates/base/appconfig_form.html

@ -0,0 +1,38 @@
{% extends "base.html" %}
{% load i18n crispy_forms_tags menus%}
{% block base_content %}
{% crispy form %}
{% endblock base_content %}
{% block extra_js %}
<script language="Javascript">
function json_simular_identificacao_de_documento() {
var jsidd = $("#id_identificacao_de_documentos").val()
$.get("",
{ jsidd: jsidd},
function(data, status) {
$("#jsidd").remove()
$("#div_id_identificacao_de_documentos").closest('.row').after($('<div class="row"/>').append($('<div class="col-12"/>').append(
$(`<div id="jsidd" class="alert alert-${data.error.length > 0 ? "danger":"info"}"/>`).html(
`
Resultado: <strong>${data.jsidd}</strong>
${data.error.length > 0 ? '<br><br>Erro(s):': ''}
${data.error.length > 0 ? data.error: ''}
`
)
)))
});
}
var fields = ["#id_identificacao_de_documentos",];
for (i = 0; i < fields.length; i++){
$(fields[i]).keyup(function() {
json_simular_identificacao_de_documento();
});
}
$(document).ready( function() {
json_simular_identificacao_de_documento();
});
</script>
{% endblock %}

34
sapl/templates/base/layouts.yaml

@ -20,40 +20,29 @@ UserDetail:
AppConfig: AppConfig:
{% trans 'Configurações Gerais' %}: {% trans 'Configurações Gerais' %}:
- esfera_federacao documentos_administrativos sapl_as_sapn - esfera_federacao sapl_as_sapn
#{% trans 'Módulo Parlamentares' %}: #{% trans 'Módulo Parlamentares' %}:
#{% trans 'Módulo Mesa Diretora' %}: #{% trans 'Módulo Mesa Diretora' %}:
#{% trans 'Módulo Comissões' %}: #{% trans 'Módulo Comissões' %}:
#{% trans 'Módulo Bancadas Parlamentares' %}: #{% trans 'Módulo Bancadas Parlamentares' %}:
# {% trans 'Módulo Normas Jurídicas' %}: {% trans 'Módulo Administrativo' %}:
- documentos_administrativos tramitacao_documento
- protocolo_manual sequencia_numeracao_protocolo inicio_numeracao_protocolo
- identificacao_de_documentos
{% trans 'Módulo Proposições' %}: {% trans 'Módulo Proposições' %}:
- sequencia_numeracao_proposicao sequencia_numeracao_protocolo inicio_numeracao_protocolo - sequencia_numeracao_proposicao receber_recibo_proposicao proposicao_incorporacao_obrigatoria escolher_numero_materia_proposicao
- protocolo_manual receber_recibo_proposicao
- proposicao_incorporacao_obrigatoria escolher_numero_materia_proposicao
{% trans 'Módulo Matéria Legislativa' %}: {% trans 'Módulo Matéria Legislativa' %}:
- tramitacao_origem_fixa tramitacao_materia tramitacao_documento - tramitacao_origem_fixa:7 tramitacao_materia
# {% trans 'Módulo Normas Jurídicas' %}:
{% trans 'Módulo Textos Articulados' %}: {% trans 'Módulo Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma - texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
#{% trans 'Módulo Sessão Plenária' %}: {% trans 'Módulo Sessão Plenária' %}:
#{% trans 'Módulo LexML' %}:
#{% trans 'Módulo Administrativo' %}:
{% trans 'Estatísticas de acesso' %}:
- estatisticas_acesso_normas
{% trans 'Assinaturas' %}:
- assinatura_ata - assinatura_ata
{% trans 'Módulo Painel' %}: {% trans 'Módulo Painel' %}:
@ -61,9 +50,14 @@ AppConfig:
- cronometro_ordem cronometro_consideracoes - cronometro_ordem cronometro_consideracoes
- mostrar_brasao_painel - mostrar_brasao_painel
{% trans 'Estatísticas de acesso' %}:
- estatisticas_acesso_normas
{% trans 'Segurança' %}: {% trans 'Segurança' %}:
- google_recaptcha_site_key google_recaptcha_secret_key - google_recaptcha_site_key google_recaptcha_secret_key
#{% trans 'Módulo LexML' %}:
TipoAutor: TipoAutor:
{% trans 'Tipo Autor' %}: {% trans 'Tipo Autor' %}:
- descricao - descricao

1
sapl/templates/materia/layouts.yaml

@ -29,6 +29,7 @@ MateriaLegislativa:
- data_apresentacao numero_protocolo tipo_apresentacao - data_apresentacao numero_protocolo tipo_apresentacao
- tipo_autor autor - tipo_autor autor
- texto_original - texto_original
{% trans 'Outras Informações' %}: {% trans 'Outras Informações' %}:
- apelido dias_prazo polemica - apelido dias_prazo polemica
- objeto regime_tramitacao em_tramitacao - objeto regime_tramitacao em_tramitacao

20
sapl/templates/materia/materialegislativa_detail.html

@ -40,12 +40,22 @@
</br> </br>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if object.normajuridica_set.last %} {% if object.normajuridica_set.last %}
<p class="control-label">&emsp; Norma Jurídica Relacionada</p> <br>
<div class="actions btn-group btn-group-sm" role="group"> <div class="row">
&emsp;&emsp;<a href="{% url 'sapl.norma:normajuridica_detail' object.normajuridica_set.last.id %}"> <div class="col-12">
<div id="div_id_docadmvinculados" class="form-group">
<p class="control-label">Norma Jurídica Relacionada</p>
<div class="controls">
<div class="form-control-static">
<a href="{% url 'sapl.norma:normajuridica_detail' object.normajuridica_set.last.id %}">
{{ object.normajuridica_set.last }}</a> {{ object.normajuridica_set.last }}</a>
</div> </div>
</div>
</div>
</div>
</div>
{% endif %} {% endif %}
{% if object.docadmvinculados.all.exists %} {% if object.docadmvinculados.all.exists %}
@ -55,13 +65,13 @@
<div id="div_id_docadmvinculados" class="form-group"> <div id="div_id_docadmvinculados" class="form-group">
<p class="control-label">Documentos Administrativos Públicos Vinculados a Matéria</p> <p class="control-label">Documentos Administrativos Públicos Vinculados a Matéria</p>
<div class="controls"> <div class="controls">
<div class="form-control-static"> <div class="form-control-static p-2">
{% for vinculodocadmmateria in object.documentoadministrativo_vinculado_set.all %} {% for vinculodocadmmateria in object.documentoadministrativo_vinculado_set.all %}
{% if not vinculodocadmmateria.documento.restrito or vinculodocadmmateria.documento.restrito and not user.is_anonymous %} {% if not vinculodocadmmateria.documento.restrito or vinculodocadmmateria.documento.restrito and not user.is_anonymous %}
<strong>Data Anexação:</strong> {{vinculodocadmmateria.data_anexacao}} {% if vinculodocadmmateria.data_desanexacao %} - {{vinculodocadmmateria.data_desanexacao}}{% endif %} <strong>Data Anexação:</strong> {{vinculodocadmmateria.data_anexacao}} {% if vinculodocadmmateria.data_desanexacao %} - {{vinculodocadmmateria.data_desanexacao}}{% endif %}
<br><strong>Documento:</strong> <br><strong>Documento:</strong>
<a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' vinculodocadmmateria.documento.id %}"> <a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' vinculodocadmmateria.documento.id %}">
{{ vinculodocadmmateria.documento.epigrafe }} {{ vinculodocadmmateria.documento }}
</a> </a>
<br>{{ vinculodocadmmateria.documento.assunto}} <br>{{ vinculodocadmmateria.documento.assunto}}
{% if vinculodocadmmateria.documento.restrito %} {% if vinculodocadmmateria.documento.restrito %}

2
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -37,7 +37,7 @@
{% if request.user.is_anonymous and not d.restrito or not request.user.is_anonymous%} {% if request.user.is_anonymous and not d.restrito or not request.user.is_anonymous%}
<tr> <tr>
<td> <td>
<strong><a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}{%if d.complemento %}-{{d.complemento}}{% endif %}/{{d.ano}} - {{d.tipo}}</strong></a></br> <a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}"><strong>{{d}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}} <strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}}
</br> </br>
<strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }} <strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }}

2
sapl/templates/protocoloadm/layouts.yaml

@ -9,7 +9,7 @@ DocumentoAdministrativo:
- numero complemento ano - numero complemento ano
- data protocolo - data protocolo
- assunto - assunto
- interessado autor tramitacao - interessado autor tramitacao:2
- texto_integral|urlize - texto_integral|urlize
- documento_anexado_set__documento_principal|m2m_urlize_for_detail - documento_anexado_set__documento_principal|m2m_urlize_for_detail
- documento_principal_set__documento_anexado|m2m_urlize_for_detail - documento_principal_set__documento_anexado|m2m_urlize_for_detail

3
sapl/utils.py

@ -1,6 +1,6 @@
from functools import wraps from functools import wraps
import hashlib import hashlib
from itertools import groupby from itertools import groupby, chain
import logging import logging
from operator import itemgetter from operator import itemgetter
import os import os
@ -26,6 +26,7 @@ from django.core.files.uploadedfile import UploadedFile
from django.core.mail import get_connection from django.core.mail import get_connection
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from django.db.models.fields.related import ForeignKey
from django.forms import BaseForm from django.forms import BaseForm
from django.forms.widgets import SplitDateTimeWidget from django.forms.widgets import SplitDateTimeWidget
from django.utils import six, timezone from django.utils import six, timezone

Loading…
Cancel
Save