Browse Source

Merge commit '13ec4603' (= 3.1.153) into migracao

migracao
Marcio Mazza 6 years ago
parent
commit
031fcf9216
  1. 2
      docker-compose.yml
  2. 58
      docs/solr.rst
  3. 5
      sapl/api/views.py
  4. 3
      sapl/comissoes/views.py
  5. 52
      sapl/materia/forms.py
  6. 55
      sapl/materia/views.py
  7. 3
      sapl/norma/forms.py
  8. 17
      sapl/norma/models.py
  9. 19
      sapl/parlamentares/forms.py
  10. 15
      sapl/parlamentares/tests/test_parlamentares.py
  11. 2
      sapl/settings.py
  12. 2
      sapl/templates/base.html
  13. 3
      sapl/templates/menu_tabelas_auxiliares.yaml
  14. 1
      sapl/templates/norma/normajuridica_form.html
  15. 3
      sapl/templates/sessao/blocos_ata/identificacao_basica.html
  16. 6
      sapl/templates/sessao/blocos_ata/lista_presenca.html
  17. 3
      sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html
  18. 51
      sapl/templates/sessao/blocos_ata/materias_expediente.html
  19. 35
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  20. 3
      sapl/templates/sessao/blocos_ata/mesa_diretora.html
  21. 7
      sapl/templates/sessao/blocos_ata/oradores_expediente.html
  22. 5
      sapl/templates/sessao/blocos_ata/oradores_explicacoes.html
  23. 2
      setup.py
  24. 2
      solr/docker-compose.yml

2
docker-compose.yml

@ -11,7 +11,7 @@ sapldb:
ports: ports:
- "5432:5432" - "5432:5432"
sapl: sapl:
image: interlegis/sapl:3.1.152 image: interlegis/sapl:3.1.153
restart: always restart: always
environment: environment:
ADMIN_PASSWORD: interlegis ADMIN_PASSWORD: interlegis

58
docs/solr.rst

@ -1,27 +1,55 @@
**ESTAS INSTRUÇÕES ESTÃO DEFASADAS. EM BREVE IREMOS DISPONIBILIZAR UM TUTORIAL MAIS ATUALIZADO DE COMO INTEGRAR O SOLR AO SAPL**
================================ ================================
Instruções para instalar o Solr Instruções para instalar o Solr
================================ ================================
Solr é a ferramenta utilizada pelo SAPL 3.1 para indexar documentos para que possa ser feita Solr é uma plataforma open source de indexação e busca textual utilizada pelo SAPL 3.1 para indexar documentos (normas jurídicas, matérias legislativas e documentos acessórios).
a Pesquisa Textual.
Observação: Se a execução do SAPL for mediante containers Docker então use o arquivo *docker-compose.yml* disponível em
*https://github.com/interlegis/sapl/blob/3.1.x/solr/docker-compose.yml* (verifique os mapeamentos de volume estão corretos, a verso do SAPL referenciada no arquivo docker-compose.yml, e realize o backup de seu BD **antes** de qualquer tentativa de substituição do arquivo *docker-compose.yml* em uso corrente);
1) Faça o download da distribuição *binária* do Apache Solr do site oficial do projeto **http://lucene.apache.org/solr**
As instalações Solr suportadas até o momento vão da 7.4 à 8;
2) Descompacte o arquivo em uma pasta do diretório (referenciada neste tutorial como $SOLR_HOME)
3) Inicie o Solr com o comando:
**$SOLR_HOME/bin/solr start -c**
4) Por meio do browser, acesse a URL **http://localhost:8983** (ou informe o endereço da máquina onde o Solr foi instalado)
5) Pare o servidor do SAPL;
6) Edite o arquivo .env adicionando as seguintes linhas:
USE_SOLR = True
SOLR_COLLECTION = sapl
SOLR_URL = http://localhost:8983
Adicione ao arquivo ``.env`` o seguinte atributo: (o valor do campo SOLR_URL deve corresponder à URL acessada no item 3)
``SOLR_URL = 'http://127.0.0.1:8983/solr'`` 7) Entre no diretório raiz do SAPL e digite o comando: **python3 solr_api.py -c sapl -u http://localhost:8983`**
Dentro do diretório principal siga os seguintes passos:: (a URL informada acima deve ser a mesma dos itens 3 e 6)
curl -LO https://archive.apache.org/dist/lucene/solr/4.10.2/solr-4.10.2.tgz 8) Enquanto o Solr realiza a indexação da base de dados do SAPL, inicie em uma outra tela o SAPL;
tar xvzf solr-4.10.2.tgz
cd solr-4.10.2
cd example
java -jar start.jar
./manage.py build_solr_schema --filename solr-4.10.2/example/solr/collection1/conf/schema.xml
9) Após realizados os passos com sucesso, nas telas de busca de Matéria Legislativa e Normas deverá aparecer um botão
de 'Busca Textual' próximo ao botão de busca tradicional.
Após isso, deve-se parar o servidor do Solr e restartar com ``java -jar start.jar`` **Observações:**
* Para parar o Solr execute o comando **$SOLR_HOME/bin/solr stop**
**OBS: Toda vez que o código da pesquisa textual for modificado, os comandos de build_solr_schema e start.jar devem ser rodados, nessa mesma ordem.** * Para reindexar os dados do SAPL execute o comando **python3 manage.py rebuild_index** (isso irá apagar todos os dados
do Solr e indexar tudo novamente).

5
sapl/api/views.py

@ -401,6 +401,11 @@ class _MateriaLegislativaViewSet:
return Response(serializer_class.data) return Response(serializer_class.data)
@action(detail=True, methods=['GET'])
def anexadas(self, request, *args, **kwargs):
self.queryset = self.get_object().anexadas.all()
return self.list(request, *args, **kwargs)
@customize(TipoMateriaLegislativa) @customize(TipoMateriaLegislativa)
class _TipoMateriaLegislativaViewSet: class _TipoMateriaLegislativaViewSet:

3
sapl/comissoes/views.py

@ -197,7 +197,8 @@ class ReuniaoCrud(MasterDetailCrud):
public = [RP_LIST, RP_DETAIL, ] public = [RP_LIST, RP_DETAIL, ]
class BaseMixin(MasterDetailCrud.BaseMixin): class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['data', 'nome', 'tema'] list_field_names = ['data', 'nome', 'tema', 'upload_ata']
ordering = '-data'
class ListView(MasterDetailCrud.ListView): class ListView(MasterDetailCrud.ListView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

52
sapl/materia/forms.py

@ -3,7 +3,6 @@ import logging
import os import os
from crispy_forms.bootstrap import Alert, InlineRadios from crispy_forms.bootstrap import Alert, InlineRadios
from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset, from crispy_forms.layout import (HTML, Button, Column, Div, Field, Fieldset,
Layout, Row) Layout, Row)
from django import forms from django import forms
@ -31,6 +30,7 @@ from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PRIVATE) STATUS_TA_PRIVATE)
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row) to_row)
from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto,
MateriaLegislativa, Orgao, RegimeTramitacao, MateriaLegislativa, Orgao, RegimeTramitacao,
TipoDocumento, TipoProposicao, StatusTramitacao, TipoDocumento, TipoProposicao, StatusTramitacao,
@ -402,7 +402,17 @@ class RelatoriaForm(ModelForm):
self.fields['composicao'].choices = [('', '---------')] + \ self.fields['composicao'].choices = [('', '---------')] + \
[(c.pk, c) for c in composicoes] [(c.pk, c) for c in composicoes]
self.fields['parlamentar'].choices = [('', '---------')] # UPDATE
if self.initial.get('composicao') and self.initial.get('parlamentar'):
parlamentares = [(p.parlamentar.id, p.parlamentar) for p in
Participacao.objects.filter(composicao__comissao_id=comissao_pk,
composicao_id=self.initial['composicao'])]
self.fields['parlamentar'].choices = [
('', '---------')] + parlamentares
# INSERT
else:
self.fields['parlamentar'].choices = [('', '---------')]
def clean(self): def clean(self):
super().clean() super().clean()
@ -424,6 +434,11 @@ class RelatoriaForm(ModelForm):
else: else:
cleaned_data['comissao'] = comissao cleaned_data['comissao'] = comissao
if cleaned_data['data_designacao_relator'] < cleaned_data['composicao'].periodo.data_inicio \
or cleaned_data['data_designacao_relator'] > cleaned_data['composicao'].periodo.data_fim:
raise ValidationError(
_('Data de designação deve estar dentro do período da composição.'))
return cleaned_data return cleaned_data
@ -452,9 +467,12 @@ class TramitacaoForm(ModelForm):
super(TramitacaoForm, self).__init__(*args, **kwargs) super(TramitacaoForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date() self.fields['data_tramitacao'].initial = timezone.now().date()
ust = UnidadeTramitacao.objects.select_related().all() ust = UnidadeTramitacao.objects.select_related().all()
unidade_tramitacao_destino = [('', '---------')]+[(ut.pk, ut) for ut in ust if ut.comissao and ut.comissao.ativa] unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut)
unidade_tramitacao_destino.extend([(ut.pk, ut) for ut in ust if ut.orgao]) for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino.extend([(ut.pk, ut) for ut in ust if ut.parlamentar]) unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.orgao])
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.parlamentar])
self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
def clean(self): def clean(self):
@ -791,9 +809,11 @@ class AnexadaForm(ModelForm):
self.logger.error("Matéria não pode ser anexada a si mesma.") self.logger.error("Matéria não pode ser anexada a si mesma.")
raise ValidationError(_('Matéria não pode ser anexada a si mesma')) raise ValidationError(_('Matéria não pode ser anexada a si mesma'))
is_anexada = Anexada.objects.filter(materia_principal=materia_principal, is_anexada = Anexada.objects.filter(
materia_anexada=materia_anexada materia_principal=materia_principal,
).exists() materia_anexada=materia_anexada
).exclude(pk=self.instance.pk).exists()
if is_anexada: if is_anexada:
self.logger.error("Matéria já se encontra anexada.") self.logger.error("Matéria já se encontra anexada.")
raise ValidationError(_('Matéria já se encontra anexada')) raise ValidationError(_('Matéria já se encontra anexada'))
@ -1169,6 +1189,7 @@ class AcessorioEmLoteFilterSet(django_filters.FilterSet):
Fieldset(_('Documentos Acessórios em Lote'), Fieldset(_('Documentos Acessórios em Lote'),
row1, row2, form_actions(label='Pesquisar'))) row1, row2, form_actions(label='Pesquisar')))
class AnexadaEmLoteFilterSet(django_filters.FilterSet): class AnexadaEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin): class Meta(FilterOverridesMetaMixin):
@ -1570,8 +1591,8 @@ class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
if cd['numero_materia_futuro'] and \ if cd['numero_materia_futuro'] and \
'tipo' in cd and \ 'tipo' in cd and \
MateriaLegislativa.objects.filter(tipo=cd['tipo'].tipo_conteudo_related, MateriaLegislativa.objects.filter(tipo=cd['tipo'].tipo_conteudo_related,
ano=timezone.now().year, ano=timezone.now().year,
numero=cd['numero_materia_futuro']): numero=cd['numero_materia_futuro']):
raise ValidationError(_("A matéria {} {}/{} já existe.".format(cd['tipo'].tipo_conteudo_related.descricao, raise ValidationError(_("A matéria {} {}/{} já existe.".format(cd['tipo'].tipo_conteudo_related.descricao,
cd['numero_materia_futuro'], cd['numero_materia_futuro'],
timezone.now().year))) timezone.now().year)))
@ -1990,14 +2011,13 @@ class ConfirmarProposicaoForm(ProposicaoForm):
if numeracao is None: if numeracao is None:
numero['numero__max'] = 0 numero['numero__max'] = 0
if cd['numero_materia_futuro'] and not MateriaLegislativa.objects.filter(tipo=tipo, if cd['numero_materia_futuro'] and not MateriaLegislativa.objects.filter(tipo=tipo,
ano=ano, ano=ano,
numero=cd['numero_materia_futuro']): numero=cd['numero_materia_futuro']):
max_numero = cd['numero_materia_futuro'] max_numero = cd['numero_materia_futuro']
else: else:
max_numero = numero['numero__max'] + 1 if numero['numero__max'] else 1 max_numero = numero['numero__max'] + \
1 if numero['numero__max'] else 1
# dados básicos # dados básicos
materia = MateriaLegislativa() materia = MateriaLegislativa()
@ -2488,7 +2508,9 @@ class MateriaPesquisaSimplesForm(forms.Form):
raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e ' raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e '
'Data Final devem ser preenchidos obrigatoriamente')) 'Data Final devem ser preenchidos obrigatoriamente'))
elif data_inicial > data_final: elif data_inicial > data_final:
self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(data_final, data_inicial)) self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(
raise ValidationError(_('A Data Final não pode ser menor que a Data Inicial')) data_final, data_inicial))
raise ValidationError(
_('A Data Final não pode ser menor que a Data Inicial'))
return cleaned_data return cleaned_data

55
sapl/materia/views.py

@ -14,7 +14,7 @@ from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import Max, Q from django.db.models import Max, Q
from django.http import HttpResponse, JsonResponse from django.http import HttpResponse, JsonResponse
@ -33,7 +33,7 @@ import sapl
from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig
from sapl.base.signals import tramitacao_signal from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao, Participacao from sapl.comissoes.models import Comissao, Participacao, Composicao
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT,
STATUS_TA_PRIVATE) STATUS_TA_PRIVATE)
from sapl.compilacao.views import IntegracaoTaView from sapl.compilacao.views import IntegracaoTaView
@ -1135,6 +1135,26 @@ class RelatoriaCrud(MasterDetailCrud):
layout_key = None layout_key = None
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_initial(self):
relatoria = Relatoria.objects.get(id=self.kwargs['pk'])
parlamentar = relatoria.parlamentar
comissao = relatoria.comissao
composicoes = [p.composicao for p in
Participacao.objects.filter(
parlamentar=parlamentar,
composicao__comissao=comissao)]
data_designacao = relatoria.data_designacao_relator
composicao = ''
for c in composicoes:
data_inicial = c.periodo.data_inicio
data_fim = c.periodo.data_fim if c.periodo.data_fim else timezone.now().date()
if data_inicial <= data_designacao <= data_fim:
composicao = c.id
break
return {'comissao': relatoria.comissao.id,
'parlamentar': relatoria.parlamentar.id,
'composicao': composicao}
class TramitacaoCrud(MasterDetailCrud): class TramitacaoCrud(MasterDetailCrud):
model = Tramitacao model = Tramitacao
@ -1925,6 +1945,7 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AcessorioEmLoteFilterSet filterset_class = AcessorioEmLoteFilterSet
template_name = 'materia/em_lote/acessorio.html' template_name = 'materia/em_lote/acessorio.html'
permission_required = ('materia.add_documentoacessorio',) permission_required = ('materia.add_documentoacessorio',)
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(DocumentoAcessorioEmLoteView, context = super(DocumentoAcessorioEmLoteView,
@ -1946,6 +1967,7 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
username = request.user.username
marcadas = request.POST.getlist('materia_id') marcadas = request.POST.getlist('materia_id')
if len(marcadas) == 0: if len(marcadas) == 0:
@ -1961,14 +1983,21 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
msg = _('Autor tem que ter menos do que 50 caracteres.') msg = _('Autor tem que ter menos do que 50 caracteres.')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
tmp_name = os.path.join(tempfile.gettempdir(), request.FILES['arquivo'].name) tmp_name = os.path.join(MEDIA_ROOT, request.FILES['arquivo'].name)
with open(tmp_name, 'wb') as destination: with open(tmp_name, 'wb') as destination:
for chunk in request.FILES['arquivo'].chunks(): for chunk in request.FILES['arquivo'].chunks():
destination.write(chunk) destination.write(chunk)
try:
doc_data = tz.localize(datetime.strptime(
request.POST['data'], "%d/%m/%Y"))
except Exception as e:
msg = _('Formato da data incorreto. O formato deve ser da forma dd/mm/aaaa.')
messages.add_message(request, messages.ERROR, msg)
self.logger.error("User={}. {}. Data inserida: {}".format(username, str(msg), request.POST['data']))
os.remove(tmp_name)
return self.get(request, self.kwargs)
doc_data = tz.localize(datetime.strptime(
request.POST['data'], "%d/%m/%Y"))
for materia_id in marcadas: for materia_id in marcadas:
doc = DocumentoAcessorio() doc = DocumentoAcessorio()
doc.materia_id = materia_id doc.materia_id = materia_id
@ -1977,6 +2006,18 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
doc.data = doc_data doc.data = doc_data
doc.autor = request.POST['autor'] doc.autor = request.POST['autor']
doc.ementa = request.POST['ementa'] doc.ementa = request.POST['ementa']
doc.arquivo.name = tmp_name
try:
doc.clean_fields()
except ValidationError as e:
for m in [ '%s: %s' % (DocumentoAcessorio()._meta.get_field(k).verbose_name, '</br>'.join(v))
for k,v in e.message_dict.items() ]:
# Insere as mensagens de erro no formato:
# 'verbose_name do nome do campo': 'mensagem de erro'
messages.add_message(request, messages.ERROR, m)
self.logger.error("User={}. {}. Nome do arquivo: {}.".format(username, str(msg), request.FILES['arquivo'].name))
os.remove(tmp_name)
return self.get(request, self.kwargs)
doc.save() doc.save()
diretorio = os.path.join(MEDIA_ROOT, diretorio = os.path.join(MEDIA_ROOT,
'sapl/public/documentoacessorio', 'sapl/public/documentoacessorio',
@ -1987,7 +2028,7 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
file_path = os.path.join(diretorio, file_path = os.path.join(diretorio,
request.FILES['arquivo'].name) request.FILES['arquivo'].name)
shutil.copy2(tmp_name, file_path) shutil.copy2(tmp_name, file_path)
doc.arquivo.name = file_path.split(MEDIA_ROOT)[1] # Retira MEDIA_ROOT do nome doc.arquivo.name = file_path.split(MEDIA_ROOT + "/")[1] # Retira MEDIA_ROOT do nome
doc.save() doc.save()
os.remove(tmp_name) os.remove(tmp_name)

3
sapl/norma/forms.py

@ -298,11 +298,10 @@ class AnexoNormaJuridicaForm(FileFieldCheckMixin, ModelForm):
def save(self, commit=False): def save(self, commit=False):
anexo = self.instance anexo = self.instance
anexo.ano = self.cleaned_data['norma'].ano anexo.ano = self.cleaned_data['norma'].ano
anexo = super(AnexoNormaJuridicaForm, self).save(commit=True)
anexo.norma = self.cleaned_data['norma'] anexo.norma = self.cleaned_data['norma']
anexo.assunto_anexo = self.cleaned_data['assunto_anexo'] anexo.assunto_anexo = self.cleaned_data['assunto_anexo']
anexo.anexo_arquivo = self.cleaned_data['anexo_arquivo'] anexo.anexo_arquivo = self.cleaned_data['anexo_arquivo']
anexo.save() anexo = super(AnexoNormaJuridicaForm, self).save(commit=True)
return anexo return anexo

17
sapl/norma/models.py

@ -351,3 +351,20 @@ class AnexoNormaJuridica(models.Model):
def __str__(self): def __str__(self):
return _('Anexo: %(anexo)s da norma %(norma)s') % { return _('Anexo: %(anexo)s da norma %(norma)s') % {
'anexo': self.anexo_arquivo, 'norma': self.norma} '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)

19
sapl/parlamentares/forms.py

@ -236,18 +236,6 @@ class ParlamentarFilterSet(django_filters.FilterSet):
class ParlamentarCreateForm(ParlamentarForm): class ParlamentarCreateForm(ParlamentarForm):
legislatura = forms.ModelChoiceField(
label=_('Legislatura'),
required=True,
queryset=Legislatura.objects.all().order_by('-data_inicio'),
empty_label='----------',
)
data_expedicao_diploma = forms.DateField(
label=_('Expedição do Diploma'),
required=True,
)
class Meta(ParlamentarForm.Meta): class Meta(ParlamentarForm.Meta):
widgets = { widgets = {
'fotografia': forms.ClearableFileInput(), 'fotografia': forms.ClearableFileInput(),
@ -258,13 +246,6 @@ class ParlamentarCreateForm(ParlamentarForm):
@transaction.atomic @transaction.atomic
def save(self, commit=True): def save(self, commit=True):
parlamentar = super(ParlamentarCreateForm, self).save(commit) parlamentar = super(ParlamentarCreateForm, self).save(commit)
legislatura = self.cleaned_data['legislatura']
Mandato.objects.create(
parlamentar=parlamentar,
legislatura=legislatura,
data_inicio_mandato=legislatura.data_inicio,
data_fim_mandato=legislatura.data_fim,
data_expedicao_diploma=self.cleaned_data['data_expedicao_diploma'])
content_type = ContentType.objects.get_for_model(Parlamentar) content_type = ContentType.objects.get_for_model(Parlamentar)
object_id = parlamentar.pk object_id = parlamentar.pk
tipo = TipoAutor.objects.get(content_type=content_type) tipo = TipoAutor.objects.get(content_type=content_type)

15
sapl/parlamentares/tests/test_parlamentares.py

@ -11,7 +11,6 @@ from sapl.parlamentares.models import (Dependente, Filiacao, Legislatura,
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_cadastro_parlamentar(admin_client): def test_cadastro_parlamentar(admin_client):
legislatura = mommy.make(Legislatura)
url = reverse('sapl.parlamentares:parlamentar_create') url = reverse('sapl.parlamentares:parlamentar_create')
response = admin_client.get(url) response = admin_client.get(url)
@ -20,21 +19,13 @@ def test_cadastro_parlamentar(admin_client):
response = admin_client.post(url, {'nome_completo': 'Teresa Barbosa', response = admin_client.post(url, {'nome_completo': 'Teresa Barbosa',
'nome_parlamentar': 'Terezinha', 'nome_parlamentar': 'Terezinha',
'sexo': 'F', 'sexo': 'F',
'ativo': 'True', 'ativo': 'True'},
'legislatura': legislatura.id,
'data_expedicao_diploma': '2001-01-01'},
follow=True) follow=True)
[parlamentar] = Parlamentar.objects.all() [parlamentar] = Parlamentar.objects.all()
assert parlamentar.nome_parlamentar == 'Terezinha' assert parlamentar.nome_parlamentar == 'Terezinha'
assert parlamentar.sexo == 'F' assert parlamentar.sexo == 'F'
assert parlamentar.ativo is True assert parlamentar.ativo is True
# o primeiro mandato é criado
[mandato] = Mandato.objects.all()
assert mandato.parlamentar == parlamentar
assert str(mandato.data_expedicao_diploma) == '2001-01-01'
assert mandato.legislatura == legislatura
assert mandato.data_fim_mandato == legislatura.data_fim
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
@ -42,9 +33,7 @@ def test_incluir_parlamentar_errors(admin_client):
url = reverse('sapl.parlamentares:parlamentar_create') url = reverse('sapl.parlamentares:parlamentar_create')
response = admin_client.post(url) response = admin_client.post(url)
erros_esperados = {campo: ['Este campo é obrigatório.'] erros_esperados = {campo: ['Este campo é obrigatório.']
for campo in ['legislatura', for campo in ['nome_parlamentar',
'data_expedicao_diploma',
'nome_parlamentar',
'nome_completo', 'nome_completo',
'sexo', 'sexo',
]} ]}

2
sapl/settings.py

@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next=' LOGIN_URL = '/login/?next='
SAPL_VERSION = '3.1.152' SAPL_VERSION = '3.1.153'
if DEBUG: if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

2
sapl/templates/base.html

@ -179,7 +179,7 @@
<small> <small>
Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto. Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto.
</small> </small>
<span>Release: 3.1.152</span> <span>Release: 3.1.153</span>
</p> </p>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">

3
sapl/templates/menu_tabelas_auxiliares.yaml

@ -20,6 +20,9 @@
- title: {% trans 'Pesquisar Parlamentar' %} - title: {% trans 'Pesquisar Parlamentar' %}
url: sapl.parlamentares:pesquisar_parlamentar url: sapl.parlamentares:pesquisar_parlamentar
css_class: btn btn-link css_class: btn btn-link
- title: {% trans 'Adicionar Parlamentar' %}
url: sapl.parlamentares:parlamentar_create
css_class: btn btn-link
- title: {% trans 'Legislatura' %} - title: {% trans 'Legislatura' %}
url: sapl.parlamentares:legislatura_list url: sapl.parlamentares:legislatura_list
css_class: btn btn-link css_class: btn btn-link

1
sapl/templates/norma/normajuridica_form.html

@ -30,7 +30,6 @@
for (i = 0; i < fields.length; i++) { for (i = 0; i < fields.length; i++) {
$(fields[i]).change(recuperar_materia); $(fields[i]).change(recuperar_materia);
} }
recuperar_materia();
function recuperar_norma() { function recuperar_norma() {
var tipo = $("#id_tipo").val(); var tipo = $("#id_tipo").val();

3
sapl/templates/sessao/blocos_ata/identificacao_basica.html

@ -2,7 +2,8 @@
<p align="justify"> <p align="justify">
<strong>Identificação Básica: </strong> <strong>Identificação Básica: </strong>
{% for b in basica %} {% for b in basica %}
{{b}} ; {{b}}
{% if not forloop.last %} ; {% endif %}
{% endfor %} {% endfor %}
</p> </p>
</fieldset> </fieldset>

6
sapl/templates/sessao/blocos_ata/lista_presenca.html

@ -5,7 +5,8 @@
{% if presenca_sessao %} {% if presenca_sessao %}
<strong>Lista de Presença na Sessão: </strong> <strong>Lista de Presença na Sessão: </strong>
{% for p in presenca_sessao %} {% for p in presenca_sessao %}
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }} ; {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
{% if not forloop.last %} ; {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>
@ -13,7 +14,8 @@
{% if justificativa_ausencia %} {% if justificativa_ausencia %}
<strong>Justificativas de Ausências na Sessão: </strong> <strong>Justificativas de Ausências na Sessão: </strong>
{% for j in justificativa_ausencia %} {% for j in justificativa_ausencia %}
{{j.parlamentar.nome_completo}} / {{ j.tipo_ausencia }} ; {{j.parlamentar.nome_completo}} / {{ j.tipo_ausencia }}
{% if not forloop.last %} ; {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

3
sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html

@ -5,7 +5,8 @@
{% if presenca_ordem %} {% if presenca_ordem %}
<strong>Lista de Presença na Ordem do Dia: </strong> <strong>Lista de Presença na Ordem do Dia: </strong>
{% for p in presenca_ordem %} {% for p in presenca_ordem %}
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }} ; {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
{% if not forloop.last %} ; {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

51
sapl/templates/sessao/blocos_ata/materias_expediente.html

@ -1,27 +1,36 @@
<fieldset> <fieldset>
<p align="justify"> <p align="justify">
{% if materia_expediente %} {% if materia_expediente %}
<strong>Matérias do Expediente: </strong> <strong>Matérias do Expediente: </strong>
{% for m in materia_expediente %} {% for m in materia_expediente %}
<b>{{m.numero}} - {{m.titulo}}</b> <b>{{m.numero}} - {{m.titulo}}</b>,
{{m.ementa|safe}}
{% if m.turno %} Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }},
Turno: {{m.turno}} {% if m.numero_protocolo %}
{% endif %} Número de Protocolo: {{ m.numero_protocolo }},
{% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} {% if m.numero_processo %}
Processo: {{ m.numero_processo }},
{% if m.numero_protocolo %} {% endif %}
Número de Protocolo: {{ m.numero_protocolo }} {%if m.turno %}
{% endif %} Turno: {{m.turno}},
{%endif %}
{% if m.numero_processo %} {%if m.tipo_votacao %}
Processo: {{ m.numero_processo }} Tipo: {{m.tipo_votacao}},
{% endif %} Sim: {{ m.voto_sim }},
Não: {{ m.voto_nao }},
{{m.ementa|safe}} Abstenções: {{m.voto_abstencoes}},
{{m.resultado}} {{m.resultado_observacao}}</td> {% endif %}
{% endfor %} Resultado:</b> {{m.resultado}}
{% if m.resultado_observacao %} - {{m.resultado_observacao}} {% endif %}
{% if m.voto_nominal%}
<b>Votos Nominais :</b>
{% for voto in m.voto_nominal %}
{{voto.0}} - {{voto.1}}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %} {% endif %}
</p> </p>
</fieldset> </fieldset>

35
sapl/templates/sessao/blocos_ata/materias_ordem_dia.html

@ -2,29 +2,32 @@
<p align="justify"> <p align="justify">
<strong>Matérias da Ordem do Dia: </strong> <strong>Matérias da Ordem do Dia: </strong>
{% for m in materias_ordem %} {% for m in materias_ordem %}
<b>{{m.numero}} - {{m.titulo}}</b> <b>{{m.numero}} - {{m.titulo}}</b>,
Descrição: {{m.ementa|safe}} {{m.ementa|safe}}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }} Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }},
{% if m.numero_protocolo %} {% if m.numero_protocolo %}
Número de Protocolo: {{ m.numero_protocolo }} Número de Protocolo: {{ m.numero_protocolo }},
{% endif %} {% endif %}
{% if m.numero_processo %} {% if m.numero_processo %}
Processo:{{ m.numero_processo }} Processo: {{ m.numero_processo }},
{% endif %} {% endif %}
{%if m.turno %} {%if m.turno %}
Turno: {{m.turno}} Turno: {{m.turno}},
{%endif %} {%endif %}
Tipo: {{m.tipo_votacao}} {%if m.tipo_votacao %}
Sim:{{m.voto_sim}} Tipo: {{m.tipo_votacao}},
Não:{{m.voto_nao}} Sim: {{ m.voto_sim }},
Abstenções:{{m.voto_abstencoes}} Não: {{ m.voto_nao }},
Resultado:</b> {{m.resultado}} {{m.resultado_observacao}} Abstenções: {{m.voto_abstencoes}},
{% endif %}
Resultado:</b> {{m.resultado}}
{% if m.resultado_observacao %} - {{m.resultado_observacao}} {% endif %}
{% if m.voto_nominal%} {% if m.voto_nominal%}
<b>Votos Nominais :</b> <b>Votos Nominais :</b>
{% for voto in m.voto_nominal %} {% for voto in m.voto_nominal %}
/ {{voto.0}} - {{voto.1}} {{voto.0}} - {{voto.1}}
{% endfor %}; {% if not forloop.last %} ; {% endif %}
{% endif %} {% endfor %}
{% endfor %} {% endif %}
</p> {% endfor %}
</fieldset> </fieldset>

3
sapl/templates/sessao/blocos_ata/mesa_diretora.html

@ -4,7 +4,8 @@
<strong>Mesa Diretora: </strong> <strong>Mesa Diretora: </strong>
{% for m in mesa %} {% for m in mesa %}
{{m.cargo}}: {{m.cargo}}:
{{m.parlamentar.nome_completo}} / {{ m.parlamentar.filiacao_atual }} ; {{m.parlamentar.nome_completo}} / {{ m.parlamentar.filiacao_atual }}
{% if not forloop.last %} ; {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

7
sapl/templates/sessao/blocos_ata/oradores_expediente.html

@ -3,10 +3,9 @@
{% if oradores %} {% if oradores %}
<strong>Oradores do Expediente: </strong> <strong>Oradores do Expediente: </strong>
{% for o in oradores %} {% for o in oradores %}
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}}</div> <b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }}
<div>{{o.url_discurso}}</div> {% if o.observacao %} - {{o.observacao}} {% endif %}
<div>{{o.observacao}}</div> {% if not forloop.last %} ; {% endif %}
</br>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

5
sapl/templates/sessao/blocos_ata/oradores_explicacoes.html

@ -3,8 +3,9 @@
{% if oradores_explicacoes %} {% if oradores_explicacoes %}
<strong>Oradores das Explicações Pessoais: </strong> <strong>Oradores das Explicações Pessoais: </strong>
{% for o in oradores_explicacoes %} {% for o in oradores_explicacoes %}
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }} ; <b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }}
{{o.url_discurso}} {% if o.observacao %} - {{o.observacao}} {% endif %}
{% if not forloop.last %} ; {% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</p> </p>

2
setup.py

@ -43,7 +43,7 @@ install_requires = [
] ]
setup( setup(
name='interlegis-sapl', name='interlegis-sapl',
version='3.1.152', version='3.1.153',
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007', license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',

2
solr/docker-compose.yml

@ -24,7 +24,7 @@ services:
- "8983:8983" - "8983:8983"
sapl: sapl:
image: interlegis/sapl:3.1.144 image: interlegis/sapl:3.1.152
# build: . # build: .
restart: always restart: always
environment: environment:

Loading…
Cancel
Save