Browse Source

Merge branch '3.1.x' into 2712-partidos-errados-extrato-e-resumo

pull/2714/head
Edward 7 years ago
committed by GitHub
parent
commit
794b9c08a3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Dockerfile
  2. 13
      check_solr.sh
  3. 17
      docker-compose.yml
  4. 20
      sapl/base/migrations/0033_auto_20190415_1050.py
  5. 3
      sapl/base/models.py
  6. 4
      sapl/compilacao/forms.py
  7. 37
      sapl/lexml/OAIServer.py
  8. 12
      sapl/materia/forms.py
  9. 20
      sapl/materia/migrations/0045_auto_20190415_1050.py
  10. 22
      sapl/materia/views.py
  11. 10
      sapl/protocoloadm/forms.py
  12. 24
      sapl/protocoloadm/tests/test_protocoloadm.py
  13. 26
      sapl/protocoloadm/views.py
  14. 24
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  15. 15
      sapl/relatorios/views.py
  16. 33
      sapl/sessao/migrations/0037_auto_20190415_1324.py
  17. 13
      sapl/sessao/models.py
  18. 36
      sapl/sessao/views.py
  19. 7
      sapl/templates/base/layouts.yaml
  20. 2
      sapl/templates/sessao/votacao/votacao_bloco_expediente.html
  21. 2
      sapl/templates/sessao/votacao/votacao_bloco_ordem.html
  22. 84
      scripts/remove_multiplos_autores.py
  23. 13
      scripts/remove_protocolos_inexistentes_materias.py
  24. 8
      start.sh

1
Dockerfile

@ -39,6 +39,7 @@ RUN rm -rf /var/interlegis/sapl/sapl/.env && \
rm -rf /var/interlegis/sapl/sapl.db rm -rf /var/interlegis/sapl/sapl.db
RUN chmod +x /var/interlegis/sapl/start.sh && \ RUN chmod +x /var/interlegis/sapl/start.sh && \
chmod +x /var/interlegis/sapl/check_solr.sh && \
ln -sf /dev/stdout /var/log/nginx/access.log && \ ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log && \ ln -sf /dev/stderr /var/log/nginx/error.log && \
mkdir /var/log/sapl/ && touch /var/interlegis/sapl/sapl.log && \ mkdir /var/log/sapl/ && touch /var/interlegis/sapl/sapl.log && \

13
check_solr.sh

@ -4,15 +4,22 @@
SOLR_URL=$1 SOLR_URL=$1
RETRY_COUNT=1
RETRY_LIMIT=4
echo "Waiting for solr connection at $SOLR_URL ..." echo "Waiting for solr connection at $SOLR_URL ..."
while true; do while [[ $RETRY_COUNT < $RETRY_LIMIT ]]; do
echo "Attempt to connect to solr: $RETRY_COUNT of $RETRY_LIMIT"
let RETRY_COUNT=RETRY_COUNT+1;
echo "$SOLR_URL/solr/admin/collections?action=LIST" echo "$SOLR_URL/solr/admin/collections?action=LIST"
RESULT=$(curl -s -o /dev/null -I "$SOLR_URL/solr/admin/collections?action=LIST" -w '%{http_code}') RESULT=$(curl -s -o /dev/null -I "$SOLR_URL/solr/admin/collections?action=LIST" -w '%{http_code}')
echo $RESULT echo $RESULT
if [ "$RESULT" -eq '200' ]; then if [ $RESULT == 200 ]; then
echo "Solr server is up!" echo "Solr server is up!"
break exit 1
else else
sleep 3 sleep 3
fi fi
done done
echo "Solr connection failed."
exit 2

17
docker-compose.yml

@ -12,6 +12,7 @@ sapldb:
- "5432:5432" - "5432:5432"
sapl: sapl:
image: interlegis/sapl:3.1.153 image: interlegis/sapl:3.1.153
# build: .
restart: always restart: always
environment: environment:
ADMIN_PASSWORD: interlegis ADMIN_PASSWORD: interlegis
@ -23,11 +24,27 @@ sapl:
EMAIL_HOST_USER: usuariosmtp EMAIL_HOST_USER: usuariosmtp
EMAIL_SEND_USER: usuariosmtp EMAIL_SEND_USER: usuariosmtp
EMAIL_HOST_PASSWORD: senhasmtp EMAIL_HOST_PASSWORD: senhasmtp
# USE_SOLR: 'True'
# SOLR_COLLECTION: sapl
# SOLR_URL: http://saplsolr:8983
TZ: America/Sao_Paulo TZ: America/Sao_Paulo
volumes: volumes:
- sapl_data:/var/interlegis/sapl/data - sapl_data:/var/interlegis/sapl/data
- sapl_media:/var/interlegis/sapl/media - sapl_media:/var/interlegis/sapl/media
links: links:
- sapldb - sapldb
# - saplsolr
ports: ports:
- "80:80" - "80:80"
#saplsolr:
# image: solr:7.4-alpine
# restart: always
# command: bin/solr start -c -f
# volumes:
# - solr_data:/opt/solr/server/solr
# - solr_configsets:/opt/solr/server/solr/configsets
# ports:
# - "8983:8983"

20
sapl/base/migrations/0033_auto_20190415_1050.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-15 13:50
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0032_merge_20190219_0941'),
]
operations = [
migrations.AlterField(
model_name='appconfig',
name='sequencia_numeracao',
field=models.CharField(choices=[('A', 'Sequencial por ano para cada autor'), ('B', 'Sequencial por ano indepententemente do autor'), ('L', 'Sequencial por legislatura'), ('U', 'Sequencial único')], default='A', max_length=1, verbose_name='Sequência de numeração'),
),
]

3
sapl/base/models.py

@ -18,7 +18,8 @@ TIPO_DOCUMENTO_ADMINISTRATIVO = ((DOC_ADM_OSTENSIVO, _('Ostensiva')),
RELATORIO_ATOS_ACESSADOS = (('S', _('Sim')), RELATORIO_ATOS_ACESSADOS = (('S', _('Sim')),
('N', _('Não'))) ('N', _('Não')))
SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano')), SEQUENCIA_NUMERACAO = (('A', _('Sequencial por ano para cada autor')),
('B', _('Sequencial por ano indepententemente do autor')),
('L', _('Sequencial por legislatura')), ('L', _('Sequencial por legislatura')),
('U', _('Sequencial único'))) ('U', _('Sequencial único')))

4
sapl/compilacao/forms.py

@ -220,7 +220,7 @@ class NotaForm(ModelForm):
publicacao = forms.DateField( publicacao = forms.DateField(
label=Nota._meta.get_field('publicacao').verbose_name, label=Nota._meta.get_field('publicacao').verbose_name,
input_formats=['%d/%m/%Y'], input_formats=['%d/%m/%Y', '%d%m%Y'],
required=True, required=True,
widget=forms.DateInput( widget=forms.DateInput(
format='%d/%m/%Y'), format='%d/%m/%Y'),
@ -228,7 +228,7 @@ class NotaForm(ModelForm):
) )
efetividade = forms.DateField( efetividade = forms.DateField(
label=Nota._meta.get_field('efetividade').verbose_name, label=Nota._meta.get_field('efetividade').verbose_name,
input_formats=['%d/%m/%Y'], input_formats=['%d/%m/%Y', '%d%m%Y'],
required=True, required=True,
widget=forms.DateInput( widget=forms.DateInput(
format='%d/%m/%Y'), format='%d/%m/%Y'),

37
sapl/lexml/OAIServer.py

@ -1,3 +1,4 @@
import unicodedata
from datetime import datetime from datetime import datetime
import oaipmh import oaipmh
@ -11,6 +12,7 @@ from lxml.builder import ElementMaker
from sapl.base.models import AppConfig, CasaLegislativa from sapl.base.models import AppConfig, CasaLegislativa
from sapl.lexml.models import LexmlPublicador, LexmlProvedor from sapl.lexml.models import LexmlPublicador, LexmlProvedor
from sapl.norma.models import NormaJuridica from sapl.norma.models import NormaJuridica
from sapl.utils import LISTA_DE_UFS
class OAILEXML: class OAILEXML:
@ -122,22 +124,33 @@ class OAIServer:
else: else:
return None return None
@staticmethod
def remove_acentos(linha):
res = unicodedata.normalize('NFKD', linha).encode('ASCII', 'ignore')
res = res.decode("UTF-8")
remove_list = ["\'", "\"", "-"]
for i in remove_list:
res = res.replace(i, "")
return res
def monta_urn(self, norma, esfera): def monta_urn(self, norma, esfera):
if norma: if norma:
urn = 'urn:lex:br;' urn = 'urn:lex:br;'
esferas = {'M': 'municipal', 'E': 'estadual'} esferas = {'M': 'municipal', 'E': 'estadual'}
municipio = casa.municipio.lower() municipio = self.remove_acentos(casa.municipio.lower())
uf = casa.uf.lower() uf_map = dict(LISTA_DE_UFS)
uf_desc = uf_map.get(casa.uf.upper(), '').lower()
uf_desc = self.remove_acentos(uf_desc)
for x in [' ', '.de.', '.da.', '.das.', '.do.', '.dos.']: for x in [' ', '.de.', '.da.', '.das.', '.do.', '.dos.']:
municipio = municipio.replace(x, '.') municipio = municipio.replace(x, '.')
uf = uf.replace(x, '.') uf_desc = uf_desc.replace(x, '.')
if esfera == 'M': if esfera == 'M':
urn += '{};{}:'.format(uf, municipio) urn += '{};{}:'.format(uf_desc, municipio)
if norma.tipo.equivalente_lexml == 'regimento.interno' or norma.tipo.equivalente_lexml == 'resolucao': if norma.tipo.equivalente_lexml == 'regimento.interno' or norma.tipo.equivalente_lexml == 'resolucao':
urn += 'camara.' urn += 'camara.'
urn += esferas[esfera] + ':' urn += esferas[esfera] + ':'
elif esfera == 'E': elif esfera == 'E':
urn += '{}:{}:'.format(uf, esferas[esfera]) urn += '{}:{}:'.format(uf_desc, esferas[esfera])
else: else:
urn += ':' urn += ':'
if norma.tipo.equivalente_lexml: if norma.tipo.equivalente_lexml:
@ -166,11 +179,14 @@ class OAIServer:
return '' return ''
def monta_xml(self, urn, norma): def monta_xml(self, urn, norma):
BASE_URL_SAPL = self.config['base_url']
BASE_URL_SAPL = BASE_URL_SAPL[:BASE_URL_SAPL.find('/', 8)]
publicador = LexmlPublicador.objects.first() publicador = LexmlPublicador.objects.first()
if norma and publicador: if norma and publicador:
LEXML = ElementMaker(namespace=self.ns['lexml'], nsmap=self.ns) LEXML = ElementMaker(namespace=self.ns['lexml'], nsmap=self.ns)
oai_lexml = LEXML.LexML() oai_lexml = LEXML.LexML()
oai_lexml.attrib['{{}}schemaLocation'.format(self.XSI_NS)] = '{} {}'.format( oai_lexml.attrib['{{{pre}}}schemaLocation'.format(pre=self.XSI_NS)] = '{} {}'.format(
'http://www.lexml.gov.br/oai_lexml', 'http://projeto.lexml.gov.br/esquemas/oai_lexml.xsd') 'http://www.lexml.gov.br/oai_lexml', 'http://projeto.lexml.gov.br/esquemas/oai_lexml.xsd')
texto_integral = norma.texto_integral texto_integral = norma.texto_integral
mime_types = {'doc': 'application/msword', mime_types = {'doc': 'application/msword',
@ -178,20 +194,21 @@ class OAIServer:
'odt': 'application/vnd.oasis.opendocument.text', 'odt': 'application/vnd.oasis.opendocument.text',
'pdf': 'application/pdf', 'pdf': 'application/pdf',
'rtf': 'application/rtf'} 'rtf': 'application/rtf'}
if texto_integral: if texto_integral:
url_conteudo = self.config['base_url'] + texto_integral.url url_conteudo = BASE_URL_SAPL + texto_integral.url
extensao = texto_integral.url.split('.')[-1] extensao = texto_integral.url.split('.')[-1]
formato = mime_types.get(extensao, 'application/octet-stream') formato = mime_types.get(extensao, 'application/octet-stream')
else: else:
formato = 'text/html' formato = 'text/html'
url_conteudo = self.config['base_url'] + reverse('sapl.norma:normajuridica_detail', url_conteudo = BASE_URL_SAPL + reverse('sapl.norma:normajuridica_detail',
kwargs={'pk': norma.numero}) kwargs={'pk': norma.pk})
element_maker = ElementMaker() element_maker = ElementMaker()
id_publicador = str(publicador.id_publicador) id_publicador = str(publicador.id_publicador)
item_conteudo = element_maker.Item(url_conteudo, formato=formato, idPublicador=id_publicador, item_conteudo = element_maker.Item(url_conteudo, formato=formato, idPublicador=id_publicador,
tipo='conteudo') tipo='conteudo')
oai_lexml.append(item_conteudo) oai_lexml.append(item_conteudo)
url = self.config['base_url'] + reverse('sapl.norma:normajuridica_detail', kwargs={'pk': norma.numero}) url = BASE_URL_SAPL + reverse('sapl.norma:normajuridica_detail', kwargs={'pk': norma.pk})
item_metadado = element_maker.Item(url, formato='text/html', idPublicador=id_publicador, tipo='metadado') item_metadado = element_maker.Item(url, formato='text/html', idPublicador=id_publicador, tipo='metadado')
oai_lexml.append(item_metadado) oai_lexml.append(item_metadado)
documento_individual = element_maker.DocumentoIndividual(urn) documento_individual = element_maker.DocumentoIndividual(urn)

12
sapl/materia/forms.py

@ -790,6 +790,13 @@ class AnexadaForm(ModelForm):
cleaned_data = self.cleaned_data cleaned_data = self.cleaned_data
data_anexacao = cleaned_data['data_anexacao']
data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao
if data_anexacao > data_desanexacao:
self.logger.error("Data de anexação posterior à data de desanexação.")
raise ValidationError(_("Data de anexação posterior à data de desanexação."))
try: try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})." self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) .format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
@ -1659,9 +1666,14 @@ class ProposicaoForm(FileFieldCheckMixin, forms.ModelForm):
return super().save(commit) return super().save(commit)
inst.ano = timezone.now().year inst.ano = timezone.now().year
sequencia_numeracao = AppConfig.attr('sequencia_numeracao')
if sequencia_numeracao == 'A':
numero__max = Proposicao.objects.filter( numero__max = Proposicao.objects.filter(
autor=inst.autor, autor=inst.autor,
ano=timezone.now().year).aggregate(Max('numero_proposicao')) ano=timezone.now().year).aggregate(Max('numero_proposicao'))
elif sequencia_numeracao == 'B':
numero__max = Proposicao.objects.filter(
ano=timezone.now().year).aggregate(Max('numero_proposicao'))
numero__max = numero__max['numero_proposicao__max'] numero__max = numero__max['numero_proposicao__max']
inst.numero_proposicao = ( inst.numero_proposicao = (
numero__max + 1) if numero__max else 1 numero__max + 1) if numero__max else 1

20
sapl/materia/migrations/0045_auto_20190415_1050.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-15 13:50
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0044_auto_20190327_1409'),
]
operations = [
migrations.AlterField(
model_name='tipomaterialegislativa',
name='sequencia_numeracao',
field=models.CharField(blank=True, choices=[('A', 'Sequencial por ano para cada autor'), ('B', 'Sequencial por ano indepententemente do autor'), ('L', 'Sequencial por legislatura'), ('U', 'Sequencial único')], max_length=1, verbose_name='Sequência de numeração'),
),
]

22
sapl/materia/views.py

@ -2112,19 +2112,31 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id') marcadas = request.POST.getlist('materia_id')
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
data_anexacao = datetime.strptime( data_anexacao = datetime.strptime(
request.POST['data_anexacao'], "%d/%m/%Y").date() request.POST['data_anexacao'], "%d/%m/%Y").date()
if request.POST['data_desanexacao'] == '': if request.POST['data_desanexacao'] == '':
data_desanexacao = None data_desanexacao = None
v_data_desanexacao = data_anexacao
else: else:
data_desanexacao = datetime.strptime( data_desanexacao = datetime.strptime(
request.POST['data_desanexacao'], "%d/%m/%Y").date() request.POST['data_desanexacao'], "%d/%m/%Y").date()
v_data_desanexacao = data_desanexacao
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg)
if data_anexacao > v_data_desanexacao:
msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
if data_anexacao > v_data_desanexacao:
msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
principal = MateriaLegislativa.objects.get(pk=kwargs['pk']) principal = MateriaLegislativa.objects.get(pk=kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in=marcadas): for materia in MateriaLegislativa.objects.filter(id__in=marcadas):

10
sapl/protocoloadm/forms.py

@ -221,7 +221,7 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
) )
class AnularProcoloAdmForm(ModelForm): class AnularProtocoloAdmForm(ModelForm):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -240,7 +240,7 @@ class AnularProcoloAdmForm(ModelForm):
widget=forms.Textarea) widget=forms.Textarea)
def clean(self): def clean(self):
super(AnularProcoloAdmForm, self).clean() super(AnularProtocoloAdmForm, self).clean()
cleaned_data = self.cleaned_data cleaned_data = self.cleaned_data
@ -313,7 +313,7 @@ class AnularProcoloAdmForm(ModelForm):
form_actions(label='Anular') form_actions(label='Anular')
) )
) )
super(AnularProcoloAdmForm, self).__init__( super(AnularProtocoloAdmForm, self).__init__(
*args, **kwargs) *args, **kwargs)
@ -811,8 +811,8 @@ class AnexadoForm(ModelForm):
data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao
if data_anexacao > data_desanexacao: if data_anexacao > data_desanexacao:
self.logger.error("A data de anexação não pode ser posterior a data de desanexação.") self.logger.error("Data de anexação posterior à data de desanexação.")
raise ValidationError(_("A data de anexação não pode ser posterior a data de desanexação.")) raise ValidationError(_("Data de anexação posterior à data de desanexação."))
try: try:
self.logger.info( self.logger.info(
"Tentando obter objeto DocumentoAdministrativo (numero={}, ano={}, tipo={})." "Tentando obter objeto DocumentoAdministrativo (numero={}, ano={}, tipo={})."

24
sapl/protocoloadm/tests/test_protocoloadm.py

@ -9,7 +9,7 @@ import pytest
from sapl.base.models import AppConfig from sapl.base.models import AppConfig
from sapl.materia.models import UnidadeTramitacao from sapl.materia.models import UnidadeTramitacao
from sapl.protocoloadm.forms import (AnularProcoloAdmForm, from sapl.protocoloadm.forms import (AnularProtocoloAdmForm,
DocumentoAdministrativoForm, DocumentoAdministrativoForm,
MateriaLegislativa, ProtocoloDocumentForm, MateriaLegislativa, ProtocoloDocumentForm,
ProtocoloMateriaForm) ProtocoloMateriaForm)
@ -51,7 +51,7 @@ def test_anular_protocolo_submit(admin_client):
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_form_anular_protocolo_inexistente(): def test_form_anular_protocolo_inexistente():
form = AnularProcoloAdmForm({'numero': '1', form = AnularProtocoloAdmForm({'numero': '1',
'ano': '2016', 'ano': '2016',
'justificativa_anulacao': 'TESTE'}) 'justificativa_anulacao': 'TESTE'})
@ -64,7 +64,7 @@ def test_form_anular_protocolo_inexistente():
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_form_anular_protocolo_valido(): def test_form_anular_protocolo_valido():
mommy.make(Protocolo, numero='1', ano='2016', anulado=False) mommy.make(Protocolo, numero='1', ano='2016', anulado=False)
form = AnularProcoloAdmForm({'numero': '1', form = AnularProtocoloAdmForm({'numero': '1',
'ano': '2016', 'ano': '2016',
'justificativa_anulacao': 'TESTE'}) 'justificativa_anulacao': 'TESTE'})
if not form.is_valid(): if not form.is_valid():
@ -74,7 +74,7 @@ def test_form_anular_protocolo_valido():
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_form_anular_protocolo_anulado(): def test_form_anular_protocolo_anulado():
mommy.make(Protocolo, numero='1', ano='2016', anulado=True) mommy.make(Protocolo, numero='1', ano='2016', anulado=True)
form = AnularProcoloAdmForm({'numero': '1', form = AnularProtocoloAdmForm({'numero': '1',
'ano': '2016', 'ano': '2016',
'justificativa_anulacao': 'TESTE'}) 'justificativa_anulacao': 'TESTE'})
assert form.errors['__all__'] == \ assert form.errors['__all__'] == \
@ -88,7 +88,7 @@ def test_form_anular_protocolo_campos_obrigatorios():
# TODO: generalizar para diminuir o tamanho deste método # TODO: generalizar para diminuir o tamanho deste método
# numero ausente # numero ausente
form = AnularProcoloAdmForm({'numero': '', form = AnularProtocoloAdmForm({'numero': '',
'ano': '2016', 'ano': '2016',
'justificativa_anulacao': 'TESTE'}) 'justificativa_anulacao': 'TESTE'})
if form.is_valid(): if form.is_valid():
@ -98,7 +98,7 @@ def test_form_anular_protocolo_campos_obrigatorios():
assert form.errors['numero'] == [_('Este campo é obrigatório.')] assert form.errors['numero'] == [_('Este campo é obrigatório.')]
# ano ausente # ano ausente
form = AnularProcoloAdmForm({'numero': '1', form = AnularProtocoloAdmForm({'numero': '1',
'ano': '', 'ano': '',
'justificativa_anulacao': 'TESTE'}) 'justificativa_anulacao': 'TESTE'})
if form.is_valid(): if form.is_valid():
@ -108,7 +108,7 @@ def test_form_anular_protocolo_campos_obrigatorios():
assert form.errors['ano'] == [_('Este campo é obrigatório.')] assert form.errors['ano'] == [_('Este campo é obrigatório.')]
# justificativa_anulacao ausente # justificativa_anulacao ausente
form = AnularProcoloAdmForm({'numero': '1', form = AnularProtocoloAdmForm({'numero': '1',
'ano': '2016', 'ano': '2016',
'justificativa_anulacao': ''}) 'justificativa_anulacao': ''})
if form.is_valid(): if form.is_valid():
@ -261,7 +261,7 @@ def test_create_tramitacao(admin_client):
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_anular_protocolo_dados_invalidos(): def test_anular_protocolo_dados_invalidos():
form = AnularProcoloAdmForm(data={}) form = AnularProtocoloAdmForm(data={})
assert not form.is_valid() assert not form.is_valid()
@ -276,7 +276,7 @@ def test_anular_protocolo_dados_invalidos():
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
def test_anular_protocolo_form_anula_protocolo_inexistente(): def test_anular_protocolo_form_anula_protocolo_inexistente():
form = AnularProcoloAdmForm(data={'numero': '1', form = AnularProtocoloAdmForm(data={'numero': '1',
'ano': '2017', 'ano': '2017',
'justificativa_anulacao': 'teste' 'justificativa_anulacao': 'teste'
}) })
@ -291,7 +291,7 @@ def test_anular_protocolo_form_anula_protocolo_inexistente():
def test_anular_protocolo_form_anula_protocolo_anulado(): def test_anular_protocolo_form_anula_protocolo_anulado():
mommy.make(Protocolo, numero=1, ano=2017, anulado=True) mommy.make(Protocolo, numero=1, ano=2017, anulado=True)
form = AnularProcoloAdmForm(data={'numero': '1', form = AnularProtocoloAdmForm(data={'numero': '1',
'ano': '2017', 'ano': '2017',
'justificativa_anulacao': 'teste' 'justificativa_anulacao': 'teste'
}) })
@ -316,7 +316,7 @@ def test_anular_protocolo_form_anula_protocolo_com_doc_vinculado():
ano=2017, ano=2017,
numero_protocolo=1) numero_protocolo=1)
form = AnularProcoloAdmForm(data={'numero': '1', form = AnularProtocoloAdmForm(data={'numero': '1',
'ano': '2017', 'ano': '2017',
'justificativa_anulacao': 'teste' 'justificativa_anulacao': 'teste'
}) })
@ -338,7 +338,7 @@ def test_anular_protocolo_form_anula_protocolo_com_doc_vinculado():
mommy.make(DocumentoAdministrativo, mommy.make(DocumentoAdministrativo,
protocolo=protocolo_documento) protocolo=protocolo_documento)
form = AnularProcoloAdmForm(data={'numero': '2', form = AnularProtocoloAdmForm(data={'numero': '2',
'ano': '2017', 'ano': '2017',
'justificativa_anulacao': 'teste' 'justificativa_anulacao': 'teste'
}) })

26
sapl/protocoloadm/views.py

@ -37,7 +37,7 @@ from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, get_mime_type_from_file_extension,
show_results_filter_set, mail_service_configured) show_results_filter_set, mail_service_configured)
from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm, from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm,
DocumentoAcessorioAdministrativoForm, DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet, DocumentoAdministrativoFilterSet,
DocumentoAdministrativoForm, FichaPesquisaAdmForm, FichaSelecionaAdmForm, ProtocoloDocumentForm, DocumentoAdministrativoForm, FichaPesquisaAdmForm, FichaSelecionaAdmForm, ProtocoloDocumentForm,
@ -484,7 +484,7 @@ class ProtocoloListView(PermissionRequiredMixin, ListView):
class AnularProtocoloAdmView(PermissionRequiredMixin, CreateView): class AnularProtocoloAdmView(PermissionRequiredMixin, CreateView):
template_name = 'protocoloadm/anular_protocoloadm.html' template_name = 'protocoloadm/anular_protocoloadm.html'
form_class = AnularProcoloAdmForm form_class = AnularProtocoloAdmForm
form_valid_message = _('Protocolo anulado com sucesso!') form_valid_message = _('Protocolo anulado com sucesso!')
permission_required = ('protocoloadm.action_anular_protocolo', ) permission_required = ('protocoloadm.action_anular_protocolo', )
@ -1047,21 +1047,33 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
marcados = request.POST.getlist('documento_id') marcados = request.POST.getlist('documento_id')
if len(marcados) == 0:
msg =_('Nenhum documento foi selecionado')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
data_anexacao = datetime.strptime( data_anexacao = datetime.strptime(
request.POST['data_anexacao'], "%d/%m/%Y" request.POST['data_anexacao'], "%d/%m/%Y"
).date() ).date()
if request.POST['data_desanexacao'] == '': if request.POST['data_desanexacao'] == '':
data_desanexacao = None data_desanexacao = None
v_data_desanexacao = data_anexacao
else: else:
data_desanexacao = datetime.strptime( data_desanexacao = datetime.strptime(
request.POST['data_desanexacao'], "%d/%m/%Y" request.POST['data_desanexacao'], "%d/%m/%Y"
).date() ).date()
v_data_desanexacao = data_desanexacao
if len(marcados) == 0:
msg =_('Nenhum documento foi selecionado')
messages.add_message(request, messages.ERROR, msg)
if data_anexacao > v_data_desanexacao:
msg=_('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
if data_anexacao > v_data_desanexacao:
msg =_('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, messages.ERROR, msg)
principal = DocumentoAdministrativo.objects.get(pk = kwargs['pk']) principal = DocumentoAdministrativo.objects.get(pk = kwargs['pk'])
for documento in DocumentoAdministrativo.objects.filter(id__in = marcados): for documento in DocumentoAdministrativo.objects.filter(id__in = marcados):

24
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -128,6 +128,24 @@ def inf_basicas(inf_basicas_dic):
return tmp return tmp
def multimidia(cont_mult_dic):
"""
"""
tmp = ""
mul_audio = cont_mult_dic['multimidia_audio']
mul_video = cont_mult_dic['multimidia_video']
tmp += '\t\t<para style="P1">Conteúdo Multimídia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Audio: </b> ' + mul_audio + '</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Video: </b> ' + mul_video + '</para>\n'
return tmp
def mesa(lst_mesa): def mesa(lst_mesa):
""" """
@ -392,7 +410,7 @@ def ocorrencias(lst_ocorrencias):
return tmp return tmp
def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_ausencia_sessao, lst_expedientes, lst_expediente_materia, lst_expediente_materia_vot_nom, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_votacao_vot_nom, lst_oradores_ordemdia, lst_oradores, lst_ocorrencias): def principal(rodape_dic, imagem, inf_basicas_dic, cont_mult_dic, lst_mesa, lst_presenca_sessao, lst_ausencia_sessao, lst_expedientes, lst_expediente_materia, lst_expediente_materia_vot_nom, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_votacao_vot_nom, lst_oradores_ordemdia, lst_oradores, lst_ocorrencias):
""" """
""" """
arquivoPdf = str(int(time.time() * 100)) + ".pdf" arquivoPdf = str(int(time.time() * 100)) + ".pdf"
@ -416,7 +434,7 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
ordenacao = ResumoOrdenacao.objects.first() ordenacao = ResumoOrdenacao.objects.first()
dict_ord_template = { dict_ord_template = {
'cont_mult': '', 'cont_mult': multimidia(cont_mult_dic),
'exp': expedientes(lst_expedientes), 'exp': expedientes(lst_expedientes),
'id_basica': inf_basicas(inf_basicas_dic), 'id_basica': inf_basicas(inf_basicas_dic),
'lista_p': presenca(lst_presenca_sessao, lst_ausencia_sessao), 'lista_p': presenca(lst_presenca_sessao, lst_ausencia_sessao),
@ -452,6 +470,7 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
logger.error("KeyError: " + str(e) + ". Erro ao tentar utilizar " logger.error("KeyError: " + str(e) + ". Erro ao tentar utilizar "
"configuração de ordenação. Utilizando ordenação padrão.") "configuração de ordenação. Utilizando ordenação padrão.")
tmp += inf_basicas(inf_basicas_dic) tmp += inf_basicas(inf_basicas_dic)
tmp += multimidia(cont_mult_dic)
tmp += mesa(lst_mesa) tmp += mesa(lst_mesa)
tmp += presenca(lst_presenca_sessao, lst_ausencia_sessao) tmp += presenca(lst_presenca_sessao, lst_ausencia_sessao)
tmp += expedientes(lst_expedientes) tmp += expedientes(lst_expedientes)
@ -467,6 +486,7 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
else: else:
tmp += inf_basicas(inf_basicas_dic) tmp += inf_basicas(inf_basicas_dic)
tmp += multimidia(cont_mult_dic)
tmp += mesa(lst_mesa) tmp += mesa(lst_mesa)
tmp += presenca(lst_presenca_sessao, lst_ausencia_sessao) tmp += presenca(lst_presenca_sessao, lst_ausencia_sessao)
tmp += expedientes(lst_expedientes) tmp += expedientes(lst_expedientes)

15
sapl/relatorios/views.py

@ -520,6 +520,18 @@ def get_sessao_plenaria(sessao, casa):
inf_basicas_dic["hr_fim_sessao"] = sessao.hora_fim inf_basicas_dic["hr_fim_sessao"] = sessao.hora_fim
inf_basicas_dic["nom_camara"] = casa.nome inf_basicas_dic["nom_camara"] = casa.nome
# Conteudo multimidia
cont_mult_dic = {}
if sessao.url_audio:
cont_mult_dic['multimidia_audio'] = str(sessao.url_audio)
else:
cont_mult_dic['multimidia_audio'] = 'Indisponível'
if sessao.url_video:
cont_mult_dic['multimidia_video'] = str(sessao.url_video)
else:
cont_mult_dic['multimidia_video'] = 'Indisponível'
# Lista da composicao da mesa diretora # Lista da composicao da mesa diretora
lst_mesa = [] lst_mesa = []
for composicao in IntegranteMesa.objects.filter(sessao_plenaria=sessao): for composicao in IntegranteMesa.objects.filter(sessao_plenaria=sessao):
@ -852,6 +864,7 @@ def get_sessao_plenaria(sessao, casa):
lst_ocorrencias.append(o) lst_ocorrencias.append(o)
return (inf_basicas_dic, return (inf_basicas_dic,
cont_mult_dic,
lst_mesa, lst_mesa,
lst_presenca_sessao, lst_presenca_sessao,
lst_ausencia_sessao, lst_ausencia_sessao,
@ -910,6 +923,7 @@ def relatorio_sessao_plenaria(request, pk):
raise Http404('Essa página não existe') raise Http404('Essa página não existe')
(inf_basicas_dic, (inf_basicas_dic,
cont_mult_dic,
lst_mesa, lst_mesa,
lst_presenca_sessao, lst_presenca_sessao,
lst_ausencia_sessao, lst_ausencia_sessao,
@ -934,6 +948,7 @@ def relatorio_sessao_plenaria(request, pk):
rodape, rodape,
imagem, imagem,
inf_basicas_dic, inf_basicas_dic,
cont_mult_dic,
lst_mesa, lst_mesa,
lst_presenca_sessao, lst_presenca_sessao,
lst_ausencia_sessao, lst_ausencia_sessao,

33
sapl/sessao/migrations/0037_auto_20190415_1324.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-15 16:24
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('sessao', '0036_auto_20190412_1106'),
]
operations = [
migrations.AddField(
model_name='registrovotacao',
name='data_hora',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Data/Hora'),
),
migrations.AddField(
model_name='registrovotacao',
name='ip',
field=models.CharField(blank=True, default='', max_length=30, verbose_name='IP'),
),
migrations.AddField(
model_name='registrovotacao',
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
),
]

13
sapl/sessao/models.py

@ -456,6 +456,19 @@ class RegistroVotacao(models.Model):
verbose_name=_('Abstenções')) verbose_name=_('Abstenções'))
observacao = models.TextField( observacao = models.TextField(
blank=True, verbose_name=_('Observações')) blank=True, verbose_name=_('Observações'))
user = models.ForeignKey(get_settings_auth_user_model(),
on_delete=models.PROTECT,
null=True,
blank=True)
ip = models.CharField(verbose_name=_('IP'),
max_length=30,
blank=True,
default='')
data_hora = models.DateTimeField(
verbose_name=_('Data/Hora'),
auto_now_add=True,
blank=True,
null=True)
class Meta: class Meta:
verbose_name = _('Votação') verbose_name = _('Votação')

36
sapl/sessao/views.py

@ -35,7 +35,7 @@ from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato,
Parlamentar, SessaoLegislativa) Parlamentar, SessaoLegislativa)
from sapl.sessao.apps import AppConfig from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
from sapl.utils import show_results_filter_set, remover_acentos from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip
from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, BlocoForm, from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, BlocoForm,
ExpedienteForm, JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm, ExpedienteForm, JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm,
@ -2163,6 +2163,8 @@ class VotacaoView(SessaoPermissionMixin):
votacao.ordem_id = ordem_id votacao.ordem_id = ordem_id
votacao.tipo_resultado_votacao_id = int( votacao.tipo_resultado_votacao_id = int(
request.POST['resultado_votacao']) request.POST['resultado_votacao'])
votacao.user = request.user
votacao.ip = get_client_ip(request)
votacao.save() votacao.save()
except Exception as e: except Exception as e:
username = request.user.username username = request.user.username
@ -2383,6 +2385,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
votacao.numero_votos_nao = votos_nao votacao.numero_votos_nao = votos_nao
votacao.numero_abstencoes = abstencoes votacao.numero_abstencoes = abstencoes
votacao.observacao = request.POST.get('observacao', None) votacao.observacao = request.POST.get('observacao', None)
votacao.user = request.user
votacao.ip = get_client_ip(request)
votacao.materia_id = materia_votacao.materia.id votacao.materia_id = materia_votacao.materia.id
if self.ordem: if self.ordem:
@ -2410,6 +2414,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
voto_parlamentar.voto = voto voto_parlamentar.voto = voto
voto_parlamentar.parlamentar_id = parlamentar_id voto_parlamentar.parlamentar_id = parlamentar_id
voto_parlamentar.votacao_id = votacao.id voto_parlamentar.votacao_id = votacao.id
voto_parlamentar.user = request.user
voto_parlamentar.ip = get_client_ip(request)
voto_parlamentar.save() voto_parlamentar.save()
resultado = form.cleaned_data['resultado_votacao'] resultado = form.cleaned_data['resultado_votacao']
@ -2847,10 +2853,10 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
if (int(request.POST['voto_presidente']) == 0): if (int(request.POST['voto_presidente']) == 0):
qtde_presentes -= 1 qtde_presentes -= 1
if (qtde_votos > qtde_presentes or qtde_votos < qtde_presentes): if qtde_votos != qtde_presentes:
form._errors["total_votos"] = ErrorList([u""]) form._errors["total_votos"] = ErrorList([u""])
return self.render_to_response(context) return self.render_to_response(context)
elif (qtde_presentes == qtde_votos): else:
try: try:
votacao = RegistroVotacao() votacao = RegistroVotacao()
votacao.numero_votos_sim = int(request.POST['votos_sim']) votacao.numero_votos_sim = int(request.POST['votos_sim'])
@ -2861,6 +2867,8 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
votacao.expediente_id = expediente_id votacao.expediente_id = expediente_id
votacao.tipo_resultado_votacao_id = int( votacao.tipo_resultado_votacao_id = int(
request.POST['resultado_votacao']) request.POST['resultado_votacao'])
votacao.user = request.user
votacao.ip = get_client_ip(request)
votacao.save() votacao.save()
except Exception as e: except Exception as e:
username = request.user.username username = request.user.username
@ -3544,9 +3552,13 @@ class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(VotacaoEmBlocoExpediente, context = super(VotacaoEmBlocoExpediente,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['pk'] = self.kwargs['pk'] context['pk'] = self.kwargs['pk']
context['root_pk'] = self.kwargs['pk'] context['root_pk'] = self.kwargs['pk']
if not verifica_sessao_iniciada(self.request, self.kwargs['pk']):
context['sessao_iniciada'] = False
return context
context['sessao_iniciada'] = True
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk']) context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
return context return context
@ -3566,9 +3578,13 @@ class VotacaoEmBlocoOrdemDia(PermissionRequiredForAppCrudMixin, ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(VotacaoEmBlocoOrdemDia, context = super(VotacaoEmBlocoOrdemDia,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['pk'] = self.kwargs['pk'] context['pk'] = self.kwargs['pk']
context['root_pk'] = self.kwargs['pk'] context['root_pk'] = self.kwargs['pk']
if not verifica_sessao_iniciada(self.request, self.kwargs['pk']):
context['sessao_iniciada'] = False
return context
context['sessao_iniciada'] = True
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk']) context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
return context return context
@ -3640,6 +3656,8 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
resultado = TipoResultadoVotacao.objects.get( resultado = TipoResultadoVotacao.objects.get(
id=request.POST['resultado_votacao']) id=request.POST['resultado_votacao'])
votacao.tipo_resultado_votacao = resultado votacao.tipo_resultado_votacao = resultado
votacao.user = request.user
votacao.ip = get_client_ip(request)
votacao.save() votacao.save()
except Exception as e: except Exception as e:
username = request.user.username username = request.user.username
@ -3671,6 +3689,8 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
resultado = TipoResultadoVotacao.objects.get( resultado = TipoResultadoVotacao.objects.get(
id=request.POST['resultado_votacao']) id=request.POST['resultado_votacao'])
votacao.tipo_resultado_votacao = resultado votacao.tipo_resultado_votacao = resultado
votacao.user = request.user
votacao.ip = get_client_ip(request)
votacao.save() votacao.save()
except Exception as e: except Exception as e:
username = request.user.username username = request.user.username
@ -3862,6 +3882,8 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView)
voto_parlamentar.voto = voto voto_parlamentar.voto = voto
voto_parlamentar.parlamentar_id = parlamentar_id voto_parlamentar.parlamentar_id = parlamentar_id
voto_parlamentar.votacao_id = votacao.id voto_parlamentar.votacao_id = votacao.id
voto_parlamentar.user = request.user
voto_parlamentar.ip = get_client_ip(request)
voto_parlamentar.save() voto_parlamentar.save()
ordem.resultado = form.cleaned_data['resultado_votacao'].nome ordem.resultado = form.cleaned_data['resultado_votacao'].nome
@ -3889,6 +3911,8 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView)
votacao.materia = expediente.materia votacao.materia = expediente.materia
votacao.expediente = expediente votacao.expediente = expediente
votacao.tipo_resultado_votacao = form.cleaned_data['resultado_votacao'] votacao.tipo_resultado_votacao = form.cleaned_data['resultado_votacao']
votacao.user = request.user
votacao.ip = get_client_ip(request)
votacao.save() votacao.save()
# Salva os votos de cada parlamentar # Salva os votos de cada parlamentar
@ -3904,6 +3928,8 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView)
voto_parlamentar.voto = voto voto_parlamentar.voto = voto
voto_parlamentar.parlamentar_id = parlamentar_id voto_parlamentar.parlamentar_id = parlamentar_id
voto_parlamentar.votacao_id = votacao.id voto_parlamentar.votacao_id = votacao.id
voto_parlamentar.user = request.user
voto_parlamentar.ip = get_client_ip(request)
voto_parlamentar.save() voto_parlamentar.save()
expediente.resultado = form.cleaned_data['resultado_votacao'].nome expediente.resultado = form.cleaned_data['resultado_votacao'].nome

7
sapl/templates/base/layouts.yaml

@ -18,8 +18,8 @@ AppConfig:
- esfera_federacao - esfera_federacao
{% trans 'Proposições e Protocolo' %}: {% trans 'Proposições e Protocolo' %}:
- sequencia_numeracao proposicao_incorporacao_obrigatoria receber_recibo_proposicao - sequencia_numeracao protocolo_manual receber_recibo_proposicao
- escolher_numero_materia_proposicao protocolo_manual - proposicao_incorporacao_obrigatoria escolher_numero_materia_proposicao
{% trans 'Textos Articulados' %}: {% trans 'Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma - texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
@ -31,7 +31,8 @@ AppConfig:
- assinatura_ata - assinatura_ata
{% trans 'Cronômetros do Painel' %}: {% trans 'Cronômetros do Painel' %}:
- cronometro_discurso cronometro_aparte cronometro_ordem cronometro_consideracoes - cronometro_discurso cronometro_aparte
- cronometro_ordem cronometro_consideracoes
{% trans 'Configurações do Painel' %}: {% trans 'Configurações do Painel' %}:
- mostrar_brasao_painel - mostrar_brasao_painel

2
sapl/templates/sessao/votacao/votacao_bloco_expediente.html

@ -3,6 +3,7 @@
{% block base_content %} {% block base_content %}
{% if sessao_iniciada %}
<form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}"> <form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}">
{% csrf_token %} {% csrf_token %}
<br><br> <br><br>
@ -91,6 +92,7 @@
<input type="hidden" id="origem" name="origem" value="expediente"> <input type="hidden" id="origem" name="origem" value="expediente">
</form> </form>
{% endif %}
{% endblock base_content %} {% endblock base_content %}

2
sapl/templates/sessao/votacao/votacao_bloco_ordem.html

@ -3,6 +3,7 @@
{% block base_content %} {% block base_content %}
{% if sessao_iniciada %}
<form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}"> <form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}">
{% csrf_token %} {% csrf_token %}
<br><br> <br><br>
@ -91,6 +92,7 @@
<input type="hidden" id="origem" name="origem" value="ordem"> <input type="hidden" id="origem" name="origem" value="ordem">
</form> </form>
{% endif %}
{% endblock base_content %} {% endblock base_content %}

84
scripts/remove_multiplos_autores.py

@ -0,0 +1,84 @@
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Count
from sapl.base.models import Autor
from sapl.parlamentares.models import Parlamentar
def pega_autores():
return [[autor for autor in Autor.objects.filter(nome=nome)]
for nome in Autor.objects.values_list('nome', flat=True).annotate(qntd=Count('nome')).filter(qntd__gt=1)]
def pega_parlamentares_autores():
parlamentares = [[parlamentar for parlamentar in Parlamentar.objects.filter(nome_parlamentar=nome_parlamentar)]
for nome_parlamentar in Parlamentar.objects.values_list('nome_parlamentar', flat=True)
.annotate(qntd=Count('nome_parlamentar')).filter(qntd__gt=1)]
parlamentares_autores = []
for parlamentar in parlamentares:
parlamentar_autor = []
for clone in parlamentar[1:]:
try:
autor_principal = Autor.objects.get(parlamentar_set=parlamentar[0])
except ObjectDoesNotExist:
try:
autor_clonado = Autor.objects.get(parlamentar_set=clone)
except ObjectDoesNotExist:
pass
else:
autor_clonado.object_id = parlamentar[0].id
autor_clonado.save()
parlamentares_autores.append(autor_clonado)
else:
if len(parlamentar_autor) == 0:
parlamentar_autor.append(autor_principal)
try:
autor_clonado = Autor.objects.get(parlamentar_set=clone)
except ObjectDoesNotExist:
pass
else:
parlamentar_autor.append(autor_clonado)
parlamentares_autores.extend(parlamentar_autor)
return parlamentares_autores
def transfere_valeres(autores):
for autor in autores:
for clone in autor[1:]:
for autoria in clone.autoria_set.all():
autoria.autor_id = autor[0]
autoria.save()
for proposicao in clone.proposicao_set.all():
proposicao.autor_id = autor[0]
proposicao.save()
for autorianorma in clone.autorianorma_set.all():
autorianorma.autor_id = autor[0]
autorianorma.save()
for documentoadministrativo in clone.documentoadministrativo_set.all():
documentoadministrativo.autor_id = autor[0]
documentoadministrativo.save()
for protocolo in clone.protocolo_set.all():
protocolo.autor_id = autor[0]
protocolo.save()
clone.delete()
def main():
autores = pega_autores()
parlamentares_autores = pega_parlamentares_autores()
autores.append(parlamentares_autores)
transfere_valeres(autores)
if __name__ == '__main__':
main()

13
scripts/remove_protocolos_inexistentes_materias.py

@ -0,0 +1,13 @@
from sapl.materia.models import MateriaLegislativa
from sapl.protocoloadm.models import Protocolo
def main():
for materia in MateriaLegislativa.objects.filter(numero_protocolo__isnull=False):
if not Protocolo.objects.filter(ano=materia.ano, numero=materia.numero_protocolo).exists():
materia.numero_protocolo = None
materia.save()
if __name__ == '__main__':
main()

8
start.sh

@ -71,10 +71,18 @@ if [ "${USE_SOLR-False}" == "True" ] || [ "${USE_SOLR-False}" == "true" ]; then
echo "MAX SHARDS PER NODE: $MAX_SHARDS_PER_NODE" echo "MAX SHARDS PER NODE: $MAX_SHARDS_PER_NODE"
echo "=========================================" echo "========================================="
echo "running solr script"
/bin/bash check_solr.sh $SOLR_URL /bin/bash check_solr.sh $SOLR_URL
CHECK_SOLR_RETURN=$?
if [ $CHECK_SOLR_RETURN == 1 ]; then
echo "Connecting to solr..."
python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE & python3 solr_api.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE &
# python3 manage.py rebuild_index --noinput & # python3 manage.py rebuild_index --noinput &
else
echo "Solr is offline, not possible to connect."
fi
else else
echo "Suporte a SOLR não inicializado." echo "Suporte a SOLR não inicializado."
fi fi

Loading…
Cancel
Save