Browse Source

Merge branch '3.1.x' into oradores-ordem-dia

pull/2662/head
Edward 7 years ago
committed by GitHub
parent
commit
3013512931
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      Dockerfile
  2. 2
      docker-compose.yml
  3. 7
      sapl/api/urls.py
  4. 126
      sapl/api/views.py
  5. 24
      sapl/compilacao/forms.py
  6. 20
      sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py
  7. 7
      sapl/compilacao/models.py
  8. 6
      sapl/materia/forms.py
  9. 22
      sapl/materia/migrations/0044_auto_20190327_1409.py
  10. 1
      sapl/materia/models.py
  11. 49
      sapl/materia/views.py
  12. 3
      sapl/relatorios/views.py
  13. 22
      sapl/sessao/forms.py
  14. 6
      sapl/sessao/urls.py
  15. 116
      sapl/sessao/views.py
  16. 2
      sapl/settings.py
  17. 2
      sapl/templates/base.html
  18. 1
      sapl/templates/compilacao/layouts.yaml
  19. 3
      sapl/templates/compilacao/text_list.html
  20. 2
      sapl/templates/relatorios/header_ata.html
  21. 8
      sapl/templates/relatorios/relatorio_ata.html
  22. 2
      sapl/templates/sessao/blocos_ata/assinaturas.html
  23. 12
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  24. 5
      sapl/templates/sessao/expedientemateria_list.html
  25. 5
      sapl/templates/sessao/ordemdia_list.html
  26. 2
      setup.py

5
Dockerfile

@ -3,7 +3,7 @@ FROM alpine:3.8
ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \ ENV BUILD_PACKAGES postgresql-dev graphviz-dev graphviz build-base git pkgconfig \
python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \ python3-dev libxml2-dev jpeg-dev libressl-dev libffi-dev libxslt-dev \
nodejs py3-lxml py3-magic postgresql-client poppler-utils antiword \ nodejs py3-lxml py3-magic postgresql-client poppler-utils antiword \
curl jq openssh-client vim openssh-client bash curl jq openssh-client vim bash
RUN apk update --update-cache && apk upgrade RUN apk update --update-cache && apk upgrade
@ -32,9 +32,6 @@ RUN pip install -r /var/interlegis/sapl/requirements/dev-requirements.txt --upgr
COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env
# Configura timezone para BRT
# RUN cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime && echo "America/Sao_Paulo" > /etc/timezone
RUN python3 manage.py collectstatic --noinput --clear RUN python3 manage.py collectstatic --noinput --clear
# Remove .env(fake) e sapl.db da imagem # Remove .env(fake) e sapl.db da imagem

2
docker-compose.yml

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

7
sapl/api/urls.py

@ -8,7 +8,7 @@ from rest_framework.routers import DefaultRouter
from sapl.api.deprecated import MateriaLegislativaViewSet, SessaoPlenariaViewSet,\ from sapl.api.deprecated import MateriaLegislativaViewSet, SessaoPlenariaViewSet,\
AutoresProvaveisListView, AutoresPossiveisListView, AutorListView,\ AutoresProvaveisListView, AutoresPossiveisListView, AutorListView,\
ModelChoiceView ModelChoiceView
from sapl.api.views import SaplSetViews from sapl.api.views import SaplApiViewSetConstrutor
from .apps import AppConfig from .apps import AppConfig
@ -21,9 +21,10 @@ router.register(r'materia$', MateriaLegislativaViewSet)
router.register(r'sessao-plenaria', SessaoPlenariaViewSet) router.register(r'sessao-plenaria', SessaoPlenariaViewSet)
for app, built_sets in SaplSetViews.items(): for app, built_sets in SaplApiViewSetConstrutor._built_sets.items():
for view_prefix, viewset in built_sets.items(): for view_prefix, viewset in built_sets.items():
router.register(app + '/' + view_prefix, viewset) router.register(app.label + '/' +
view_prefix._meta.model_name, viewset)
urlpatterns_router = router.urls urlpatterns_router = router.urls

126
sapl/api/views.py

@ -22,8 +22,12 @@ from sapl.api.forms import SaplFilterSetMixin
from sapl.api.permissions import SaplModelPermissions from sapl.api.permissions import SaplModelPermissions
from sapl.api.serializers import ChoiceSerializer from sapl.api.serializers import ChoiceSerializer
from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO
from sapl.materia.models import Proposicao, TipoMateriaLegislativa from sapl.materia.models import Proposicao, TipoMateriaLegislativa,\
MateriaLegislativa, Tramitacao
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import DocumentoAdministrativo,\
DocumentoAcessorioAdministrativo, TramitacaoAdministrativo
from sapl.sessao.models import SessaoPlenaria
from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria
@ -31,20 +35,25 @@ class BusinessRulesNotImplementedMixin:
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
raise Exception(_("POST Create não implementado")) raise Exception(_("POST Create não implementado"))
def put(self, request, *args, **kwargs): def update(self, request, *args, **kwargs):
raise Exception(_("PUT Update não implementado")) raise Exception(_("PUT and PATCH não implementado"))
def patch(self, request, *args, **kwargs):
raise Exception(_("PATCH Partial Update não implementado"))
def delete(self, request, *args, **kwargs): def delete(self, request, *args, **kwargs):
raise Exception(_("DELETE Delete não implementado")) raise Exception(_("DELETE Delete não implementado"))
class SaplApiViewSetConstrutor(ModelViewSet): class SaplApiViewSet(ModelViewSet):
filter_backends = (DjangoFilterBackend,) filter_backends = (DjangoFilterBackend,)
class SaplApiViewSetConstrutor():
_built_sets = {}
@classonlymethod
def get_class_for_model(cls, model):
return cls._built_sets[model._meta.app_config][model]
@classonlymethod @classonlymethod
def build_class(cls): def build_class(cls):
import inspect import inspect
@ -95,7 +104,7 @@ class SaplApiViewSetConstrutor(ModelViewSet):
model = _model model = _model
# Define uma classe padrão ModelViewSet de DRF # Define uma classe padrão ModelViewSet de DRF
class ModelSaplViewSet(cls): class ModelSaplViewSet(SaplApiViewSet):
queryset = _model.objects.all() queryset = _model.objects.all()
# Utiliza o filtro customizado pela classe # Utiliza o filtro customizado pela classe
@ -119,12 +128,12 @@ class SaplApiViewSetConstrutor(ModelViewSet):
apps_sapl = [apps.apps.get_app_config( apps_sapl = [apps.apps.get_app_config(
n[5:]) for n in settings.SAPL_APPS] n[5:]) for n in settings.SAPL_APPS]
for app in apps_sapl: for app in apps_sapl:
built_sets[app.label] = {} cls._built_sets[app] = {}
for model in app.get_models(): for model in app.get_models():
built_sets[app.label][model._meta.model_name] = build(model) cls._built_sets[app][model] = build(model)
return built_sets
SaplApiViewSetConstrutor.build_class()
""" """
1. Constroi uma rest_framework.viewsets.ModelViewSet para 1. Constroi uma rest_framework.viewsets.ModelViewSet para
@ -187,15 +196,39 @@ class SaplApiViewSetConstrutor(ModelViewSet):
} }
""" """
SaplSetViews = SaplApiViewSetConstrutor.build_class()
# Toda Classe construida acima, pode ser redefinida e aplicado quaisquer # Toda Classe construida acima, pode ser redefinida e aplicado quaisquer
# das possibilidades para uma classe normal criada a partir de # das possibilidades para uma classe normal criada a partir de
# rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor # rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor
# decorator para recuperar e transformar o default
class customize(object):
def __init__(self, model):
self.model = model
def __call__(self, cls):
class _SaplApiViewSet(
cls,
SaplApiViewSetConstrutor._built_sets[
self.model._meta.app_config][self.model]
):
pass
if hasattr(_SaplApiViewSet, 'build'):
_SaplApiViewSet = _SaplApiViewSet.build()
SaplApiViewSetConstrutor._built_sets[
self.model._meta.app_config][self.model] = _SaplApiViewSet
return _SaplApiViewSet
# Customização para AutorViewSet com implementação de actions específicas # Customização para AutorViewSet com implementação de actions específicas
class _AutorViewSet(SaplSetViews['base']['autor']):
@customize(Autor)
class _AutorViewSet:
""" """
Neste exemplo de customização do que foi criado em Neste exemplo de customização do que foi criado em
SaplApiViewSetConstrutor além do ofertado por SaplApiViewSetConstrutor além do ofertado por
@ -240,7 +273,7 @@ class _AutorViewSet(SaplSetViews['base']['autor']):
return Response(serializer.data) return Response(serializer.data)
@classonlymethod @classonlymethod
def build_class_with_actions(cls): def build(cls):
models_with_gr_for_autor = models_with_gr_for_model(Autor) models_with_gr_for_autor = models_with_gr_for_model(Autor)
@ -263,7 +296,8 @@ class _AutorViewSet(SaplSetViews['base']['autor']):
return cls return cls
class _ParlamentarViewSet(SaplSetViews['parlamentares']['parlamentar']): @customize(Parlamentar)
class _ParlamentarViewSet:
@action(detail=True) @action(detail=True)
def proposicoes(self, request, *args, **kwargs): def proposicoes(self, request, *args, **kwargs):
""" """
@ -288,15 +322,16 @@ class _ParlamentarViewSet(SaplSetViews['parlamentares']['parlamentar']):
page = self.paginate_queryset(qs) page = self.paginate_queryset(qs)
if page is not None: if page is not None:
serializer = SaplSetViews[ serializer = SaplApiViewSetConstrutor.get_class_for_model(
'materia']['proposicao'].serializer_class(page, many=True) Proposicao).serializer_class(page, many=True)
return self.get_paginated_response(serializer.data) return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(page, many=True) serializer = self.get_serializer(page, many=True)
return Response(serializer.data) return Response(serializer.data)
class _ProposicaoViewSet(SaplSetViews['materia']['proposicao']): @customize(Proposicao)
class _ProposicaoViewSet():
""" """
list: list:
Retorna lista de Proposições Retorna lista de Proposições
@ -349,7 +384,26 @@ class _ProposicaoViewSet(SaplSetViews['materia']['proposicao']):
return qs return qs
class _TipoMateriaLegislativaViewSet(SaplSetViews['materia']['tipomaterialegislativa']): @customize(MateriaLegislativa)
class _MateriaLegislativaViewSet:
@action(detail=True, methods=['GET'])
def ultima_tramitacao(self, request, *args, **kwargs):
materia = self.get_object()
if not materia.tramitacao_set.exists():
return Response({})
ultima_tramitacao = materia.tramitacao_set.last()
serializer_class = SaplApiViewSetConstrutor.get_class_for_model(
Tramitacao).serializer_class(ultima_tramitacao)
return Response(serializer_class.data)
@customize(TipoMateriaLegislativa)
class _TipoMateriaLegislativaViewSet:
@action(detail=True, methods=['POST']) @action(detail=True, methods=['POST'])
def change_position(self, request, *args, **kwargs): def change_position(self, request, *args, **kwargs):
@ -366,7 +420,8 @@ class _TipoMateriaLegislativaViewSet(SaplSetViews['materia']['tipomaterialegisla
return Response(result) return Response(result)
class _DocumentoAdministrativoViewSet(SaplSetViews['protocoloadm']['documentoadministrativo']): @customize(DocumentoAdministrativo)
class _DocumentoAdministrativoViewSet:
class DocumentoAdministrativoPermission(SaplModelPermissions): class DocumentoAdministrativoPermission(SaplModelPermissions):
def has_permission(self, request, view): def has_permission(self, request, view):
@ -400,8 +455,8 @@ class _DocumentoAdministrativoViewSet(SaplSetViews['protocoloadm']['documentoadm
return qs return qs
class _DocumentoAcessorioAdministrativoViewSet( @customize(DocumentoAcessorioAdministrativo)
SaplSetViews['protocoloadm']['documentoacessorioadministrativo']): class _DocumentoAcessorioAdministrativoViewSet:
permission_classes = ( permission_classes = (
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission, ) _DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission, )
@ -414,9 +469,8 @@ class _DocumentoAcessorioAdministrativoViewSet(
return qs return qs
class _TramitacaoAdministrativoViewSet( @customize(TramitacaoAdministrativo)
SaplSetViews['protocoloadm']['tramitacaoadministrativo'], class _TramitacaoAdministrativoViewSet(BusinessRulesNotImplementedMixin):
BusinessRulesNotImplementedMixin):
# TODO: Implementar regras de manutenção das tramitações de docs adms # TODO: Implementar regras de manutenção das tramitações de docs adms
permission_classes = ( permission_classes = (
@ -430,8 +484,8 @@ class _TramitacaoAdministrativoViewSet(
return qs return qs
class _SessaoPlenariaViewSet( @customize(SessaoPlenaria)
SaplSetViews['sessao']['sessaoplenaria']): class _SessaoPlenariaViewSet:
@action(detail=False) @action(detail=False)
def years(self, request, *args, **kwargs): def years(self, request, *args, **kwargs):
@ -439,17 +493,3 @@ class _SessaoPlenariaViewSet(
serializer = ChoiceSerializer(years, many=True) serializer = ChoiceSerializer(years, many=True)
return Response(serializer.data) return Response(serializer.data)
SaplSetViews['base']['autor'] = _AutorViewSet.build_class_with_actions()
SaplSetViews['materia']['proposicao'] = _ProposicaoViewSet
SaplSetViews['materia']['tipomaterialegislativa'] = _TipoMateriaLegislativaViewSet
SaplSetViews['parlamentares']['parlamentar'] = _ParlamentarViewSet
SaplSetViews['protocoloadm']['documentoadministrativo'] = _DocumentoAdministrativoViewSet
SaplSetViews['protocoloadm']['documentoacessorioadministrativo'] = _DocumentoAcessorioAdministrativoViewSet
SaplSetViews['protocoloadm']['tramitacaoadministrativo'] = _TramitacaoAdministrativoViewSet
SaplSetViews['sessao']['sessaoplenaria'] = _SessaoPlenariaViewSet

24
sapl/compilacao/forms.py

@ -3,7 +3,6 @@ from datetime import timedelta
from crispy_forms.bootstrap import (Alert, FieldWithButtons, FormActions, from crispy_forms.bootstrap import (Alert, FieldWithButtons, FormActions,
InlineCheckboxes, InlineRadios, InlineCheckboxes, InlineRadios,
StrictButton) StrictButton)
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, Submit) Layout, Row, Submit)
from django import forms from django import forms
@ -23,10 +22,12 @@ from sapl.compilacao.models import (NOTAS_PUBLICIDADE_CHOICES,
TipoTextoArticulado, TipoVide, TipoTextoArticulado, TipoVide,
VeiculoPublicacao, Vide) VeiculoPublicacao, Vide)
from sapl.compilacao.utils import DISPOSITIVO_SELECT_RELATED from sapl.compilacao.utils import DISPOSITIVO_SELECT_RELATED
from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row,\ from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row,\
form_actions form_actions
from sapl.utils import YES_NO_CHOICES from sapl.utils import YES_NO_CHOICES
error_messages = { error_messages = {
'required': _('Este campo é obrigatório'), 'required': _('Este campo é obrigatório'),
'invalid': _('URL inválida.') 'invalid': _('URL inválida.')
@ -59,6 +60,13 @@ class TipoTaForm(ModelForm):
widget=forms.RadioSelect(), widget=forms.RadioSelect(),
required=True) required=True)
rodape_global = forms.CharField(
label=TipoTextoArticulado._meta.get_field(
'rodape_global').verbose_name,
widget=forms.Textarea(attrs={'id': 'texto-rico'}),
required=False
)
class Meta: class Meta:
model = TipoTextoArticulado model = TipoTextoArticulado
fields = ['sigla', fields = ['sigla',
@ -66,10 +74,12 @@ class TipoTaForm(ModelForm):
'content_type', 'content_type',
'participacao_social', 'participacao_social',
'publicacao_func', 'publicacao_func',
'perfis' 'perfis',
'rodape_global'
] ]
widgets = {'perfis': widgets.CheckboxSelectMultiple()} widgets = {'perfis': widgets.CheckboxSelectMultiple(),
'rodape_global': forms.Textarea}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -84,12 +94,18 @@ class TipoTaForm(ModelForm):
('perfis', 12), ('perfis', 12),
]) ])
row3 = to_row([
('rodape_global', 12),
])
self.helper = SaplFormHelper() self.helper = SaplFormHelper()
self.helper.layout = SaplFormLayout( self.helper.layout = SaplFormLayout(
Fieldset(_('Identificação Básica'), Fieldset(_('Identificação Básica'),
row1, css_class="col-md-12"), row1, css_class="col-md-12"),
Fieldset(_('Funcionalidades'), Fieldset(_('Funcionalidades'),
row2, css_class="col-md-12")) row2, css_class="col-md-12"),
Fieldset(_('Nota de Rodapé Global'),
row3, css_class="col-md-12"))
super(TipoTaForm, self).__init__(*args, **kwargs) super(TipoTaForm, self).__init__(*args, **kwargs)

20
sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-03-26 18:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0010_auto_20181004_1939'),
]
operations = [
migrations.AddField(
model_name='tipotextoarticulado',
name='rodape_global',
field=models.TextField(default='', help_text='A cada Tipo de Texto Articulado pode ser adicionado uma nota global de rodapé!', verbose_name='Rodapé Global'),
),
]

7
sapl/compilacao/models.py

@ -149,6 +149,13 @@ class TipoTextoArticulado(models.Model):
em edição. em edição.
""")) """))
rodape_global = models.TextField(
verbose_name=_('Rodapé Global'),
help_text=_('A cada Tipo de Texto Articulado pode ser adicionado '
'uma nota global de rodapé!'),
default=''
)
class Meta: class Meta:
verbose_name = _('Tipo de Texto Articulado') verbose_name = _('Tipo de Texto Articulado')
verbose_name_plural = _('Tipos de Texto Articulados') verbose_name_plural = _('Tipos de Texto Articulados')

6
sapl/materia/forms.py

@ -727,7 +727,7 @@ class AnexadaForm(ModelForm):
empty_label='Selecione', empty_label='Selecione',
) )
numero = forms.CharField(label='Número', required=True) numero = forms.IntegerField(label='Número', required=True)
ano = forms.CharField(label='Ano', required=True) ano = forms.CharField(label='Ano', required=True)
@ -751,8 +751,8 @@ class AnexadaForm(ModelForm):
ano=cleaned_data['ano'], ano=cleaned_data['ano'],
tipo=cleaned_data['tipo']) tipo=cleaned_data['tipo'])
except ObjectDoesNotExist: except ObjectDoesNotExist:
msg = _('A MateriaLegislativa a ser anexada (numero={}, ano={}, tipo={}) não existe no cadastro' msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.'
' de matérias legislativas.'.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])) .format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano']))
self.logger.error("A matéria a ser anexada não existe no cadastro" self.logger.error("A matéria a ser anexada não existe no cadastro"
" de matérias legislativas.") " de matérias legislativas.")
raise ValidationError(msg) raise ValidationError(msg)

22
sapl/materia/migrations/0044_auto_20190327_1409.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-03-27 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.materia.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('materia', '0043_auto_20190320_1749'),
]
operations = [
migrations.AlterField(
model_name='documentoacessorio',
name='arquivo',
field=models.FileField(blank=True, max_length=255, null=True, upload_to=sapl.materia.models.anexo_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Integral'),
),
]

1
sapl/materia/models.py

@ -497,6 +497,7 @@ class DocumentoAcessorio(models.Model):
arquivo = models.FileField( arquivo = models.FileField(
blank=True, blank=True,
null=True, null=True,
max_length=255,
upload_to=anexo_upload_path, upload_to=anexo_upload_path,
verbose_name=_('Texto Integral'), verbose_name=_('Texto Integral'),
validators=[restringe_tipos_de_arquivo_txt]) validators=[restringe_tipos_de_arquivo_txt])

49
sapl/materia/views.py

@ -1,5 +1,11 @@
from datetime import datetime
import logging import logging
import os
import shutil
import tempfile
import weasyprint
import itertools
from datetime import datetime
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
@ -45,6 +51,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm,
from sapl.norma.models import LegislacaoCitada from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
from sapl.settings import MEDIA_ROOT
from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO, from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO,
gerar_hash_arquivo, get_base_url, gerar_hash_arquivo, get_base_url,
get_mime_type_from_file_extension, montar_row_autor, get_mime_type_from_file_extension, montar_row_autor,
@ -2035,17 +2042,35 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
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)
with open(tmp_name, 'wb') as destination:
for chunk in request.FILES['arquivo'].chunks():
destination.write(chunk)
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
doc.tipo = tipo doc.tipo = tipo
doc.arquivo = request.FILES['arquivo']
doc.nome = request.POST['nome'] doc.nome = request.POST['nome']
doc.data = tz.localize(datetime.strptime( doc.data = doc_data
request.POST['data'], "%d/%m/%Y"))
doc.autor = request.POST['autor'] doc.autor = request.POST['autor']
doc.ementa = request.POST['ementa'] doc.ementa = request.POST['ementa']
doc.save() doc.save()
diretorio = os.path.join(MEDIA_ROOT,
'sapl/public/documentoacessorio',
str(doc_data.year),
str(doc.id))
if not os.path.exists(diretorio):
os.makedirs(diretorio)
file_path = os.path.join(diretorio,
request.FILES['arquivo'].name)
shutil.copy2(tmp_name, file_path)
doc.arquivo.name = file_path.split(MEDIA_ROOT)[1] # Retira MEDIA_ROOT do nome
doc.save()
os.remove(tmp_name)
msg = _('Documento(s) criado(s).') msg = _('Documento(s) criado(s).')
messages.add_message(request, messages.SUCCESS, msg) messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
@ -2226,7 +2251,17 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
# TODO: usar Form # TODO: usar Form
urgente = request.POST['urgente'] == 'True' urgente = request.POST['urgente'] == 'True'
flag_error = False flag_error = False
for materia_id in marcadas:
materias_principais = [m for m in MateriaLegislativa.objects.filter(id__in=marcadas)]
materias_anexadas = [m.anexadas.all() for m in MateriaLegislativa.objects.filter(id__in=marcadas) if m.anexadas.all()]
materias_anexadas = list(itertools.chain.from_iterable(materias_anexadas))
tramitacao_local = int(request.POST['unidade_tramitacao_local'])
materias_anexadas = list(filter(lambda ma : not ma.tramitacao_set.all() or \
ma.tramitacao_set.last().unidade_tramitacao_destino.id == tramitacao_local,
materias_anexadas))
materias = set(materias_principais + materias_anexadas)
for materia in materias:
try: try:
data_tramitacao = tz.localize(datetime.strptime( data_tramitacao = tz.localize(datetime.strptime(
request.POST['data_tramitacao'], "%d/%m/%Y")) request.POST['data_tramitacao'], "%d/%m/%Y"))
@ -2236,7 +2271,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
t = Tramitacao( t = Tramitacao(
materia_id=materia_id, materia=materia,
data_tramitacao=data_tramitacao, data_tramitacao=data_tramitacao,
data_encaminhamento=data_encaminhamento, data_encaminhamento=data_encaminhamento,
data_fim_prazo=data_fim_prazo, data_fim_prazo=data_fim_prazo,
@ -2270,7 +2305,7 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
status = StatusTramitacao.objects.get(id=request.POST['status']) status = StatusTramitacao.objects.get(id=request.POST['status'])
for materia in MateriaLegislativa.objects.filter(id__in=marcadas): for materia in materias:
if status.indicador == 'F': if status.indicador == 'F':
materia.em_tramitacao = False materia.em_tramitacao = False
elif self.primeira_tramitacao: elif self.primeira_tramitacao:

3
sapl/relatorios/views.py

@ -579,6 +579,8 @@ def get_sessao_plenaria(sessao, casa):
# unescape HTML codes # unescape HTML codes
# https://github.com/interlegis/sapl/issues/1046 # https://github.com/interlegis/sapl/issues/1046
conteudo = re.sub('style=".*?"', '', conteudo) conteudo = re.sub('style=".*?"', '', conteudo)
conteudo = re.sub('class=".*?"', '', conteudo)
conteudo = re.sub('<p\s+>', '<p>', conteudo)
conteudo = html.unescape(conteudo) conteudo = html.unescape(conteudo)
# escape special character '&' # escape special character '&'
@ -1290,6 +1292,7 @@ def resumo_ata_pdf(request,pk):
context.update(get_oradores_ordemdia(sessao_plenaria)) context.update(get_oradores_ordemdia(sessao_plenaria))
context.update(get_oradores_explicações_pessoais(sessao_plenaria)) context.update(get_oradores_explicações_pessoais(sessao_plenaria))
context.update(get_ocorrencias_da_sessão(sessao_plenaria)) context.update(get_ocorrencias_da_sessão(sessao_plenaria))
context.update(get_assinaturas(sessao_plenaria))
context.update({'object': sessao_plenaria}) context.update({'object': sessao_plenaria})
context.update({'data': dt.today().strftime('%d/%m/%Y')}) context.update({'data': dt.today().strftime('%d/%m/%Y')})
context.update({'rodape': rodape}) context.update({'rodape': rodape})

22
sapl/sessao/forms.py

@ -694,6 +694,28 @@ class OradorForm(ModelForm):
self.fields['parlamentar'].queryset = Parlamentar.objects.filter( self.fields['parlamentar'].queryset = Parlamentar.objects.filter(
id__in=ids).order_by('nome_parlamentar') id__in=ids).order_by('nome_parlamentar')
def clean(self):
super(OradorForm, self).clean()
cleaned_data = self.cleaned_data
if not self.is_valid():
return self.cleaned_data
sessao_id = self.initial['id_sessao']
numero = self.initial.get('numero')
numero_ordem = cleaned_data['numero_ordem']
ordem = Orador.objects.filter(
sessao_plenaria_id=sessao_id,
numero_ordem=numero_ordem
).exists()
if ordem and numero_ordem != numero:
raise ValidationError(_(
"Já existe orador nesta posição de ordem de pronunciamento"
))
return self.cleaned_data
class Meta: class Meta:
model = Orador model = Orador
exclude = ['sessao_plenaria'] exclude = ['sessao_plenaria']

6
sapl/sessao/urls.py

@ -29,6 +29,8 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
remove_parlamentar_composicao, remove_parlamentar_composicao,
reordernar_materias_expediente, reordernar_materias_expediente,
reordernar_materias_ordem, reordernar_materias_ordem,
renumerar_materias_ordem,
renumerar_materias_expediente,
sessao_legislativa_legislatura_ajax, sessao_legislativa_legislatura_ajax,
VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente, VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente,
VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView) VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView)
@ -78,6 +80,10 @@ urlpatterns = [
name="reordenar_expediente"), name="reordenar_expediente"),
url(r'^sessao/(?P<pk>\d+)/reordenar-ordem$', reordernar_materias_ordem, url(r'^sessao/(?P<pk>\d+)/reordenar-ordem$', reordernar_materias_ordem,
name="reordenar_ordem"), name="reordenar_ordem"),
url(r'^sessao/(?P<pk>\d+)/renumerar-ordem$', renumerar_materias_ordem,
name="renumerar_ordem"),
url(r'^sessao/(?P<pk>\d+)/renumerar-materias-expediente$', renumerar_materias_expediente,
name="renumerar_materias_expediente"),
url(r'^sistema/sessao-plenaria/tipo/', url(r'^sistema/sessao-plenaria/tipo/',
include(TipoSessaoCrud.get_urls())), include(TipoSessaoCrud.get_urls())),
url(r'^sistema/sessao-plenaria/tipo-resultado-votacao/', url(r'^sistema/sessao-plenaria/tipo-resultado-votacao/',

116
sapl/sessao/views.py

@ -93,6 +93,25 @@ def reordernar_materias_ordem(request, pk):
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk})) reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))
def renumerar_materias_ordem(request, pk):
ordens = OrdemDia.objects.filter(sessao_plenaria_id=pk)
for ordem_num, o in enumerate(ordens, 1):
o.numero_ordem = ordem_num
o.save()
return HttpResponseRedirect(
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))
def renumerar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter(sessao_plenaria_id=pk)
for exp_num, e in enumerate(expedientes, 1):
e.numero_ordem = exp_num
e.save()
return HttpResponseRedirect(
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk}))
def verifica_presenca(request, model, spk): def verifica_presenca(request, model, spk):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -645,6 +664,7 @@ class OradorCrud(OradorCrud):
def get_initial(self): def get_initial(self):
initial = super(UpdateView, self).get_initial() initial = super(UpdateView, self).get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id}) initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero':self.object.numero_ordem})
return initial return initial
@ -1058,9 +1078,6 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView):
return self.get(self, request, args, kwargs) return self.get(self, request, args, kwargs)
def ordenar_integrantes_por_cargo(integrantes):
return sorted(integrantes, key=lambda k: k['cargo'].id)
class MesaView(FormMixin, DetailView): class MesaView(FormMixin, DetailView):
template_name = 'sessao/mesa.html' template_name = 'sessao/mesa.html'
@ -1346,7 +1363,8 @@ def get_identificação_basica(sessao_plenaria):
'abertura': abertura, 'hora_inicio': sessao_plenaria.hora_inicio}, 'abertura': abertura, 'hora_inicio': sessao_plenaria.hora_inicio},
_('Encerramento: %(encerramento)s %(hora_fim)s') % { _('Encerramento: %(encerramento)s %(hora_fim)s') % {
'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim} 'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim}
]}) ],
'sessaoplenaria': sessao_plenaria})
def get_conteudo_multimidia(sessao_plenaria): def get_conteudo_multimidia(sessao_plenaria):
@ -1365,24 +1383,17 @@ def get_conteudo_multimidia(sessao_plenaria):
def get_mesa_diretora(sessao_plenaria): def get_mesa_diretora(sessao_plenaria):
mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria) mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria).order_by('cargo_id')
integrantes = [] integrantes = [{'parlamentar': m.parlamentar,
for m in mesa: 'cargo': m.cargo} for m in mesa]
parlamentar = Parlamentar.objects.get( return {'mesa': integrantes}
id=m.parlamentar_id)
cargo = CargoMesa.objects.get(
id=m.cargo_id)
integrante = {'parlamentar': parlamentar, 'cargo': cargo}
integrantes.append(integrante)
return ({'mesa': ordenar_integrantes_por_cargo(integrantes)})
def get_presenca_sessao(sessao_plenaria): def get_presenca_sessao(sessao_plenaria):
presencas = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')
parlamentares_sessao = [p.parlamentar for p in presencas] parlamentares_sessao = [p.parlamentar for p in SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')]
ausentes_sessao = JustificativaAusencia.objects.filter( ausentes_sessao = JustificativaAusencia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id sessao_plenaria_id=sessao_plenaria.id
@ -1414,9 +1425,15 @@ def get_materias_expediente(sessao_plenaria):
ementa = m.materia.ementa ementa = m.materia.ementa
titulo = m.materia titulo = m.materia
numero = m.numero_ordem numero = m.numero_ordem
tramitacao = m.materia.tramitacao_set.last()
turno = None
tramitacao = ''
tramitacoes = Tramitacao.objects.filter(materia=m.materia).order_by('-pk')
for aux_tramitacao in tramitacoes:
if aux_tramitacao.turno:
tramitacao = aux_tramitacao
break
turno = None
if tramitacao: if tramitacao:
turno = get_turno(tramitacao.turno) turno = get_turno(tramitacao.turno)
@ -1467,52 +1484,49 @@ def get_oradores_expediente(sessao_plenaria):
'observacao': observacao 'observacao': observacao
} }
oradores.append(ora) oradores.append(ora)
context = {'oradores': oradores} return {'oradores': oradores}
return context
def get_presenca_ordem_do_dia(sessao_plenaria): def get_presenca_ordem_do_dia(sessao_plenaria):
mesa_aux = get_mesa_diretora(sessao_plenaria) parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter(
presencas = PresencaOrdemDia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar') ).order_by('parlamentar__nome_parlamentar')]
parlamentares_mesa_dia = [m for m in mesa_aux['mesa']] return {'presenca_ordem': parlamentares_ordem}
presidente_dia = ''
for m in mesa_aux['mesa']:
if m['cargo'].descricao == 'Presidente':
presidente_dia = [m['parlamentar']]
break
parlamentares_ordem = [p.parlamentar for p in presencas] def get_assinaturas(sessao_plenaria):
mesa_dia = get_mesa_diretora(sessao_plenaria)['mesa']
cont = 0 presidente_dia = [next(iter(
for index, parlamentar in enumerate(parlamentares_ordem): [m['parlamentar'] for m in mesa_dia if m['cargo'].descricao == 'Presidente']),
try: '')]
if parlamentar == parlamentares_mesa_dia[cont]["parlamentar"]:
del(parlamentares_ordem[index]) parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter(
cont += 1 sessao_plenaria_id=sessao_plenaria.id
except IndexError: ).order_by('parlamentar__nome_parlamentar')]
pass
parlamentares_mesa = [m['parlamentar'] for m in mesa_dia]
# filtra parlamentares retirando os que sao da mesa
parlamentares_ordem = [p for p in parlamentares_ordem if p not in parlamentares_mesa]
context = {} context = {}
context.update({'presenca_ordem': parlamentares_ordem})
config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata
if config_assinatura_ata == 'T' and parlamentares_ordem: if config_assinatura_ata == 'T' and parlamentares_ordem:
context.update( context.update(
{'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'}) {'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'})
context.update({'assinatura_mesa': parlamentares_mesa_dia, context.update({'assinatura_mesa': mesa_dia,
'assinatura_presentes': parlamentares_ordem}) 'assinatura_presentes': parlamentares_ordem})
elif config_assinatura_ata == 'M' and parlamentares_mesa_dia: elif config_assinatura_ata == 'M' and mesa_dia:
context.update( context.update(
{'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'}) {'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'})
context.update({'assinatura_presentes': parlamentares_mesa_dia}) context.update({'assinatura_mesa': mesa_dia})
elif config_assinatura_ata == 'P' and presidente_dia: elif config_assinatura_ata == 'P' and presidente_dia:
context.update( context.update(
{'texto_assinatura': 'Assinatura do Presidente da Sessão'}) {'texto_assinatura': 'Assinatura do Presidente da Sessão'})
context.update({'assinatura_presentes': presidente_dia}) context.update({'assinatura_mesa': presidente_dia})
return context return context
@ -1525,7 +1539,14 @@ def get_materias_ordem_do_dia(sessao_plenaria):
ementa_observacao = o.observacao ementa_observacao = o.observacao
titulo = o.materia titulo = o.materia
numero = o.numero_ordem numero = o.numero_ordem
tramitacao = o.materia.tramitacao_set.last()
tramitacao = ''
tramitacoes = Tramitacao.objects.filter(materia=o.materia).order_by('-pk')
for aux_tramitacao in tramitacoes:
if aux_tramitacao.turno:
tramitacao = aux_tramitacao
break
turno = None turno = None
if tramitacao: if tramitacao:
turno = get_turno(tramitacao.turno) turno = get_turno(tramitacao.turno)
@ -1702,6 +1723,9 @@ class ResumoView(DetailView):
# Presença Ordem do Dia # Presença Ordem do Dia
context.update(get_presenca_ordem_do_dia(self.object)) context.update(get_presenca_ordem_do_dia(self.object))
# ===================================================================== # =====================================================================
# Assinaturas
context.update(get_assinaturas(self.object))
# =====================================================================
# Matérias Ordem do Dia # Matérias Ordem do Dia
# Votos de Votação Nominal de Matérias Ordem do Dia # Votos de Votação Nominal de Matérias Ordem do Dia
materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter( materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter(

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.149' SAPL_VERSION = '3.1.150'
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.149</span> <span>Release: 3.1.150</span>
</p> </p>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">

1
sapl/templates/compilacao/layouts.yaml

@ -45,3 +45,4 @@ TipoTextoArticulado:
{% trans 'Funcionalidaes' %}: {% trans 'Funcionalidaes' %}:
- participacao_social publicacao_func - participacao_social publicacao_func
- perfis - perfis
- rodape_global

3
sapl/templates/compilacao/text_list.html

@ -18,4 +18,7 @@
{% endblock %} {% endblock %}
{% include 'compilacao/text_list__embedded.html'%} {% include 'compilacao/text_list__embedded.html'%}
{{object.tipo_ta.rodape_global|dont_break_out}}
{% endblock base_content %} {% endblock base_content %}

2
sapl/templates/relatorios/header_ata.html

@ -19,7 +19,7 @@
</dt> </dt>
<dd class="title"> <dd class="title">
<ul> <ul>
<li style="margin-top:10px"><h2>{{casa}}</h2></li> <li style="margin-top:10px"><h2>{{casa.nome}}</h2></li>
<li><h3>Sistema de Apoio ao Processo Legislativo</h3></li> <li><h3>Sistema de Apoio ao Processo Legislativo</h3></li>
</ul> </ul>
</dd> </dd>

8
sapl/templates/relatorios/relatorio_ata.html

@ -37,7 +37,7 @@
</head> </head>
<body> <body>
<h3 style="text-align:center;">Extrato Reunião</h3> <h3 style="text-align:center;">Extrato Eletrônico da {{sessaoplenaria}}</h3>
{% include 'sessao/blocos_ata/identificacao_basica.html' %} {% include 'sessao/blocos_ata/identificacao_basica.html' %}
{% include 'sessao/blocos_ata/mesa_diretora.html' %} {% include 'sessao/blocos_ata/mesa_diretora.html' %}
{% include 'sessao/blocos_ata/lista_presenca.html' %} {% include 'sessao/blocos_ata/lista_presenca.html' %}
@ -48,6 +48,7 @@
{% include 'sessao/blocos_ata/materias_ordem_dia.html' %} {% include 'sessao/blocos_ata/materias_ordem_dia.html' %}
{% include 'sessao/blocos_ata/oradores_ordemdia.html' %} {% include 'sessao/blocos_ata/oradores_ordemdia.html' %}
{% include 'sessao/blocos_ata/oradores_explicacoes.html' %} {% include 'sessao/blocos_ata/oradores_explicacoes.html' %}
{% include 'sessao/blocos_ata/ocorrencias_da_sessao.html' %}
{% if assinatura_mesa or assinatura_presentes %} {% if assinatura_mesa or assinatura_presentes %}
@ -82,12 +83,13 @@
<tr style="margin-top:20px"> <tr style="margin-top:20px">
<td> <td>
<div style="float: left; position: relative;top: -50px; left: 8px; width: 120px;">_____________________</br> <div style="float: left; position: relative;top: -50px; left: 8px; width: 120px;">_____________________</br>
<p style="font-size:8pt"><b>{{p.cargo}}: </b> {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}</p> <p style="font-size:8pt">
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br> </br></br></br>
</div> </div>
{% else %} {% else %}
<div style="float: left; position: relative; top: -50px;left: 142px; width: 120px; margin-right:-220px;">_____________________ </br> <div style="float: left; position: relative; top: -50px;left: 142px; width: 120px; margin-right:-220px;">_____________________ </br>
<p style="font-size:8pt">{{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}</p> <p style="font-size:8pt">{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br> </br></br></br>
</div> </div>
</td> </td>

2
sapl/templates/sessao/blocos_ata/assinaturas.html

@ -11,7 +11,7 @@
{% endfor %} {% endfor %}
{% for p in assinatura_presentes %} {% for p in assinatura_presentes %}
<div class="col-md-6">___________________________________________ </br> <div class="col-md-6">___________________________________________ </br>
{{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }} {{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
</br></br></br> </br></br></br>
</div> </div>
{% endfor %} {% endfor %}

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

@ -1,19 +1,19 @@
<fieldset> <fieldset>
</br> <p align="justify">
<strong>Matérias da Ordem do Dia: </strong> <strong>Matérias da Ordem do Dia: </strong>
</br></br>
{% for m in materias_ordem %} {% for m in materias_ordem %}
<p> <b>{{m.numero}} - {{m.titulo}}</b>
<b>Materia do Expediente: {{m.numero}} - {{m.titulo}}</b>
Descrição: {{m.ementa|safe}} Descrição: {{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 %}
Turno: {{m.turno}} Turno: {{m.turno}}
{%endif %}
Tipo: {{m.tipo_votacao}} Tipo: {{m.tipo_votacao}}
Sim:{{m.voto_sim}} Sim:{{m.voto_sim}}
Não:{{m.voto_nao}} Não:{{m.voto_nao}}
@ -25,6 +25,6 @@
/ {{voto.0}} - {{voto.1}} / {{voto.0}} - {{voto.1}}
{% endfor %}; {% endfor %};
{% endif %} {% endif %}
</p>
{% endfor %} {% endfor %}
</p>
</fieldset> </fieldset>

5
sapl/templates/sessao/expedientemateria_list.html

@ -7,7 +7,10 @@
{% if perms|get_add_perm:view %} {% if perms|get_add_perm:view %}
<a href="{% url 'sapl.sessao:reordenar_expediente' root_pk %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.sessao:reordenar_expediente' root_pk %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Ajustar Ordenação {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Reordenar pela precedência {% endblocktrans %}
</a>
<a href="{% url 'sapl.sessao:renumerar_materias_expediente' root_pk %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Renumerar Expediente {% endblocktrans %}
</a> </a>
<a href="{% url 'sapl.sessao:adicionar_varias_materias_expediente' root_pk %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.sessao:adicionar_varias_materias_expediente' root_pk %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Várias Matérias {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Várias Matérias {% endblocktrans %}

5
sapl/templates/sessao/ordemdia_list.html

@ -7,7 +7,10 @@
{% if perms|get_add_perm:view %} {% if perms|get_add_perm:view %}
<a href="{% url 'sapl.sessao:reordenar_ordem' root_pk %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.sessao:reordenar_ordem' root_pk %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Ajustar Ordenação {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Reordenar pela precedência {% endblocktrans %}
</a>
<a href="{% url 'sapl.sessao:renumerar_ordem' root_pk %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Renumerar Ordem {% endblocktrans %}
</a> </a>
<a href="{% url 'sapl.sessao:adicionar_varias_materias_ordem_dia' root_pk %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.sessao:adicionar_varias_materias_ordem_dia' root_pk %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Várias Matérias {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Várias Matérias {% endblocktrans %}

2
setup.py

@ -43,7 +43,7 @@ install_requires = [
] ]
setup( setup(
name='interlegis-sapl', name='interlegis-sapl',
version='3.1.149', version='3.1.150',
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',

Loading…
Cancel
Save