Browse Source

Merge tag '3.1.150' into migracao

migracao
Marcio Mazza 6 years ago
parent
commit
632cb39448
  1. 2
      docker-compose.yml
  2. 2
      requirements/requirements.txt
  3. 20
      sapl/api/views.py
  4. 7
      sapl/base/email_utils.py
  5. 29
      sapl/base/search_indexes.py
  6. 4
      sapl/base/urls.py
  7. 26
      sapl/base/views.py
  8. 1
      sapl/comissoes/views.py
  9. 24
      sapl/compilacao/forms.py
  10. 20
      sapl/compilacao/migrations/0011_tipotextoarticulado_rodape_global.py
  11. 7
      sapl/compilacao/models.py
  12. 14
      sapl/crud/base.py
  13. 6
      sapl/lexml/OAIServer.py
  14. 7
      sapl/lexml/views.py
  15. 73
      sapl/materia/forms.py
  16. 21
      sapl/materia/migrations/0042_tipomaterialegislativa_sequencia_regimental.py
  17. 19
      sapl/materia/migrations/0043_auto_20190320_1749.py
  18. 52
      sapl/materia/models.py
  19. 6
      sapl/materia/urls.py
  20. 166
      sapl/materia/views.py
  21. 24
      sapl/norma/forms.py
  22. 31
      sapl/norma/views.py
  23. 2
      sapl/parlamentares/views.py
  24. 4
      sapl/protocoloadm/views.py
  25. 47
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  26. 5
      sapl/relatorios/urls.py
  27. 73
      sapl/relatorios/views.py
  28. 103
      sapl/sessao/tests/test_sessao_view.py
  29. 18
      sapl/sessao/urls.py
  30. 614
      sapl/sessao/views.py
  31. 7
      sapl/settings.py
  32. 62
      sapl/static/sapl/css/header-relatorio.css
  33. 56
      sapl/static/sapl/css/relatorio.css
  34. 2
      sapl/templates/base.html
  35. 67
      sapl/templates/comissoes/composicao_list.html
  36. 2
      sapl/templates/comissoes/materias_em_tramitacao.html
  37. 1
      sapl/templates/compilacao/layouts.yaml
  38. 3
      sapl/templates/compilacao/text_list.html
  39. 9
      sapl/templates/crud/list.html
  40. 15
      sapl/templates/materia/em_lote/acessorio.html
  41. 15
      sapl/templates/materia/em_lote/anexada.html
  42. 15
      sapl/templates/materia/em_lote/tramitacao.html
  43. 7
      sapl/templates/materia/impressos/ficha.html
  44. 6
      sapl/templates/materia/impressos/ficha_seleciona.html
  45. 66
      sapl/templates/materia/impressos/impressos.html
  46. 0
      sapl/templates/materia/impressos/impressos_form.html
  47. 67
      sapl/templates/materia/impressos/materias_pdf.html
  48. 7
      sapl/templates/materia/impressos/norma.html
  49. 111
      sapl/templates/materia/impressos/normas_pdf.html
  50. 6
      sapl/templates/materia/layouts.yaml
  51. 55
      sapl/templates/materia/tipomaterialegislativa_list.html
  52. 8
      sapl/templates/protocoloadm/MateriaTemplate.html
  53. 85
      sapl/templates/protocoloadm/em_lote/anexado.html
  54. 31
      sapl/templates/relatorios/header_ata.html
  55. 102
      sapl/templates/relatorios/relatorio_ata.html
  56. 23
      sapl/templates/sessao/adicionar_varias_materias_expediente.html
  57. 18
      sapl/templates/sessao/adicionar_varias_materias_ordem.html
  58. 14
      sapl/templates/sessao/blocos_ata/assinaturas.html
  59. 4
      sapl/templates/sessao/blocos_ata/lista_presenca.html
  60. 2
      sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html
  61. 50
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  62. 2
      sapl/templates/sessao/blocos_ata/mesa_diretora.html
  63. 8
      sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html
  64. 2
      sapl/templates/sessao/blocos_ata/oradores_expediente.html
  65. 2
      sapl/templates/sessao/blocos_ata/oradores_explicacoes.html
  66. 3
      sapl/templates/sessao/ocorrencia_sessao.html
  67. 31
      sapl/templates/sessao/painel.html
  68. 12
      sapl/templates/sessao/resumo_ata.html
  69. 6
      sapl/templates/sessao/sessaoplenaria_form.html
  70. 4
      sapl/templates/sessao/subnav.yaml
  71. 37
      sapl/templates/sessao/votacao/votacao_bloco_expediente.html
  72. 37
      sapl/templates/sessao/votacao/votacao_bloco_ordem.html
  73. 7
      setup.py
  74. BIN
      solr/sapl_configset/conf/saplconfigset.zip
  75. 2
      solr/sapl_configset/conf/schema.xml

2
docker-compose.yml

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

2
requirements/requirements.txt

@ -27,9 +27,7 @@ WeasyPrint==44
Pillow==5.1.0
gunicorn==19.9.0
textract==1.5.0
pysolr==3.6.0
whoosh==2.7.4
pyoai==2.5.0

20
sapl/api/views.py

@ -22,7 +22,7 @@ from sapl.api.forms import SaplFilterSetMixin
from sapl.api.permissions import SaplModelPermissions
from sapl.api.serializers import ChoiceSerializer
from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO
from sapl.materia.models import Proposicao
from sapl.materia.models import Proposicao, TipoMateriaLegislativa
from sapl.parlamentares.models import Parlamentar
from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria
@ -349,6 +349,23 @@ class _ProposicaoViewSet(SaplSetViews['materia']['proposicao']):
return qs
class _TipoMateriaLegislativaViewSet(SaplSetViews['materia']['tipomaterialegislativa']):
@action(detail=True, methods=['POST'])
def change_position(self, request, *args, **kwargs):
result = {
'status': 200,
'message': 'OK'
}
d = request.data
if 'pos_ini' in d and 'pos_fim' in d:
if d['pos_ini'] != d['pos_fim']:
pk = kwargs['pk']
TipoMateriaLegislativa.objects.reposicione(pk, d['pos_fim'])
return Response(result)
class _DocumentoAdministrativoViewSet(SaplSetViews['protocoloadm']['documentoadministrativo']):
class DocumentoAdministrativoPermission(SaplModelPermissions):
@ -427,6 +444,7 @@ class _SessaoPlenariaViewSet(
SaplSetViews['base']['autor'] = _AutorViewSet.build_class_with_actions()
SaplSetViews['materia']['proposicao'] = _ProposicaoViewSet
SaplSetViews['materia']['tipomaterialegislativa'] = _TipoMateriaLegislativaViewSet
SaplSetViews['parlamentares']['parlamentar'] = _ParlamentarViewSet

7
sapl/base/email_utils.py

@ -11,6 +11,7 @@ from sapl.materia.models import AcompanhamentoMateria
from sapl.protocoloadm.models import AcompanhamentoDocumento
from sapl.settings import EMAIL_SEND_USER
from sapl.utils import mail_service_configured
from django.utils.translation import ugettext_lazy as _
def load_email_templates(templates, context={}):
@ -208,8 +209,8 @@ def do_envia_email_tramitacao(base_url, tipo, doc_mat, status, unidade_destino):
# Envia email de tramitacao para usuarios cadastrados
#
logger = logging.getLogger(__name__)
if not mail_service_configured():
logger = logging.getLogger(__name__)
logger.warning(_('Servidor de email não configurado.'))
return
@ -220,6 +221,10 @@ def do_envia_email_tramitacao(base_url, tipo, doc_mat, status, unidade_destino):
destinatarios = AcompanhamentoDocumento.objects.filter(documento=doc_mat,
confirmado=True)
if not destinatarios:
logger.debug(_('Não existem destinatários cadastrados para essa matéria.'))
return
casa = CasaLegislativa.objects.first()
sender = EMAIL_SEND_USER

29
sapl/base/search_indexes.py

@ -1,5 +1,4 @@
import os.path
import textract
import logging
from django.db.models import F, Q, Value
@ -11,7 +10,6 @@ from haystack.constants import Indexable
from haystack.fields import CharField
from haystack.indexes import SearchIndex
from haystack.utils import get_model_ct_tuple
from textract.exceptions import ExtensionNotSupported
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PUBLIC, Dispositivo)
@ -49,19 +47,6 @@ class TextExtractField(CharField):
data = ''
return data
def whoosh_extraction(self, arquivo):
if arquivo.path.endswith('html') or arquivo.path.endswith('xml'):
with open(arquivo.path, 'r', encoding="utf8", errors='ignore') as f:
content = ' '.join(f.read())
return RemoveTag(content)
else:
return textract.process(
arquivo.path,
language='pt-br').decode('utf-8').replace('\n', ' ').replace(
'\t', ' ')
def print_error(self, arquivo, error):
msg = 'Erro inesperado processando arquivo %s erro: %s' % (
arquivo.path, error)
@ -80,20 +65,6 @@ class TextExtractField(CharField):
except Exception as err:
print(str(err))
self.print_error(arquivo, err)
# Em ambiente de DEV utiliza-se o Whoosh
# Como ele não possui extração, faz-se uso do textract
else:
try:
self.logger.debug("Tentando whoosh_extraction no arquivo {}".format(arquivo.path))
return self.whoosh_extraction(arquivo)
self.print_error(arquivo)
except ExtensionNotSupported as err:
print(str(err))
self.logger.error(str(err))
except Exception as err:
print(str(err))
self.print_error(arquivo, str(err))
return ''
def ta_extractor(self, value):

4
sapl/base/urls.py

@ -8,7 +8,7 @@ from django.contrib.auth.views import (password_reset, password_reset_complete,
password_reset_done)
from django.views.generic.base import RedirectView, TemplateView
from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud, get_data_ultima_atualizacao
from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud, get_estatistica
from sapl.settings import EMAIL_SEND_USER, MEDIA_URL
from .apps import AppConfig
@ -176,7 +176,7 @@ urlpatterns = [
ListarLegislaturaInfindavelView.as_view(),
name='lista_legislatura_infindavel'),
url(r'^sistema/data_ultima_atualizacao', get_data_ultima_atualizacao),
url(r'^sistema/estatisticas', get_estatistica),
# todos os sublinks de sistema devem vir acima deste
url(r'^sistema/$', permission_required('base.view_tabelas_auxiliares')

26
sapl/base/views.py

@ -611,12 +611,13 @@ class RelatorioMateriasTramitacaoView(FilterView):
qs = filtra_url_materias_em_tramitacao(
qr, qs, 'tramitacao__status', 'status')
context['object_list'] = qs
li = [li1 for li1 in qs if li1.tramitacao_set.last() and li1.tramitacao_set.last().status.indicador != 'F']
context['object_list'] = li
qtdes = {}
for tipo in TipoMateriaLegislativa.objects.all():
qs = context['object_list']
qtde = len(qs.filter(tipo_id=tipo.id))
li = context['object_list']
qtde = sum(1 for i in li if i.tipo_id==tipo.id)
if qtde > 0:
qtdes[tipo] = qtde
context['qtdes'] = qtdes
@ -1234,7 +1235,9 @@ def mandato_sem_data_inicio():
return Mandato.objects.filter(data_inicio_mandato__isnull=True).order_by('parlamentar')
def get_data_ultima_atualizacao(request):
def get_estatistica(request):
json_dict = {}
datas = [MateriaLegislativa.objects.all().
order_by('-data_ultima_atualizacao').
@ -1243,15 +1246,22 @@ def get_data_ultima_atualizacao(request):
NormaJuridica.objects.all().
order_by('-data_ultima_atualizacao').
values_list('data_ultima_atualizacao', flat=True).
first()]
first()] # Retorna [None, None] se inexistem registros
max_data = ''
if datas[0] and datas[1]:
max_data = max(datas)
else:
max_data = next([i for i in datas if i is not None], '')
return JsonResponse({'data_ultima_atualizacao': max_data})
max_data = next(iter([i for i in datas if i is not None]), '')
json_dict["data_ultima_atualizacao"] = max_data
json_dict["num_materias_legislativas"] = MateriaLegislativa.objects.all().count()
json_dict["num_normas_juridicas "] = NormaJuridica.objects.all().count()
json_dict["num_parlamentares"] = Parlamentar.objects.all().count()
json_dict["num_sessoes_plenarias"] = SessaoPlenaria.objects.all().count()
return JsonResponse(json_dict)
class ListarMandatoSemDataInicioView(PermissionRequiredMixin, ListView):
@ -1452,7 +1462,7 @@ class PesquisarUsuarioView(PermissionRequiredMixin, FilterView):
data = self.filterset.data
url = ''
if data:
url = "&" + str(self.request.environ['QUERY_STRING'])
url = "&" + str(self.request.META['QUERY_STRING'])
if url.startswith("&page"):
ponto_comeco = url.find('username=') - 1
url = url[ponto_comeco:]

1
sapl/comissoes/views.py

@ -186,6 +186,7 @@ class MateriasTramitacaoListView(ListView):
context = super(
MateriasTramitacaoListView, self).get_context_data(**kwargs)
context['object'] = Comissao.objects.get(id=self.kwargs['pk'])
context['qtde'] = self.object_list.count()
return context

24
sapl/compilacao/forms.py

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

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.
"""))
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:
verbose_name = _('Tipo de Texto Articulado')
verbose_name_plural = _('Tipos de Texto Articulados')

14
sapl/crud/base.py

@ -2,7 +2,6 @@ import logging
from braces.views import FormMessagesMixin
from crispy_forms.bootstrap import FieldWithButtons, StrictButton
from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import Field, Layout
from django import forms
from django.conf.urls import url
@ -25,6 +24,7 @@ from django.views.generic.base import ContextMixin
from django.views.generic.list import MultipleObjectMixin
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
RP_LIST)
from sapl.settings import BASE_DIR
@ -449,18 +449,28 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
if not n:
s += '<br>'
continue
m = obj
n = n.split('__')
for f in n[:-1]:
m = getattr(m, f)
if not m:
break
ss = ''
if m:
ss = get_field_display(m, n[-1])[1]
ss = (
('<br>' if '<ul>' in ss else ' - ') + ss)\
if ss and j != 0 and s else ss
hook = 'hook_{}'.format(''.join(n))
if hasattr(self, hook):
hs, url = getattr(self, hook)(obj, ss, url)
s += str(hs)
else:
s += ss
r.append((s, url))
return r
@ -571,6 +581,8 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
rmo = rmo[0]
if not isinstance(rmo, str):
rmo = rmo[0]
if rmo.startswith('-'):
rmo = rmo[1:]
fo = '%s__%s' % (fo, rmo)
fo = desc + fo

6
sapl/lexml/OAIServer.py

@ -26,7 +26,7 @@ class OAILEXML:
def __call__(self, element, metadata):
data = metadata.record
if data['metadata']:
if data.get('metadata'):
value = etree.XML(data['metadata'])
element.append(value)
@ -55,7 +55,7 @@ class OAIServer:
granularity='YYYY-MM-DDThh:mm:ssZ',
compression=['identity'],
toolkit_description=False)
if self.config['descricao']:
if self.config.get('descricao'):
result.add_description(self.config['descricao'])
return result
@ -89,7 +89,7 @@ class OAIServer:
def create_header(self, record):
oai_id = self.get_oai_id(record['record']['id'])
timestamp = record['record']['when_modified']
timestamp = record['record']['when_modified'] if record['record']['when_modified'] else datetime.now()
timestamp = timestamp.replace(tzinfo=None)
sets = []
deleted = record['record']['deleted']

7
sapl/lexml/views.py

@ -18,10 +18,15 @@ class LexmlProvedorCrud(Crud):
class DetailView(Crud.DetailView):
layout_key = 'LexmlProvedorDetail'
def lexml_request(request):
request_dict = request.GET.copy()
if request_dict.get('batch_size'):
del request_dict['batch_size']
config = get_config(request.get_raw_uri(), int(request.GET.get('batch_size', '10')))
oai_server = OAIServerFactory(config)
r = oai_server.handleRequest(request.GET)
r = oai_server.handleRequest(request_dict)
response = r.decode('UTF-8')
return HttpResponse(response, content_type='text/xml')

73
sapl/materia/forms.py

@ -1151,8 +1151,6 @@ class AnexadaEmLoteFilterSet(django_filters.FilterSet):
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['data_apresentacao'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
@ -1160,7 +1158,7 @@ class AnexadaEmLoteFilterSet(django_filters.FilterSet):
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Matéria Anexada em Lote'),
Fieldset(_('Pesquisa de Matérias'),
row1, row2, form_actions(label='Pesquisar')))
@ -2396,3 +2394,72 @@ class ExcluirTramitacaoEmLote(forms.Form):
form_actions(label='Excluir')
)
)
class MateriaPesquisaSimplesForm(forms.Form):
tipo_materia = forms.ModelChoiceField(
label=TipoMateriaLegislativa._meta.verbose_name,
queryset=TipoMateriaLegislativa.objects.all(),
required=False,
empty_label='Selecione')
data_inicial = forms.DateField(
label='Data Inicial',
required=False,
widget=forms.DateInput(format='%d/%m/%Y')
)
data_final = forms.DateField(
label='Data Final',
required=False,
widget=forms.DateInput(format='%d/%m/%Y')
)
titulo = forms.CharField(
label='Título do Relatório',
required=False,
max_length=150)
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
row1 = to_row(
[('tipo_materia', 6),
('data_inicial', 3),
('data_final', 3)])
row2 = to_row(
[('titulo', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
'Índice de Materias',
row1, row2,
form_actions(label='Pesquisar')
)
)
def clean(self):
super().clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
data_inicial = cleaned_data['data_inicial']
data_final = cleaned_data['data_final']
if data_inicial or data_final:
if not (data_inicial and data_final):
self.logger.error("Caso pesquise por data, os campos de Data Inicial e "
"Data Final devem ser preenchidos obrigatoriamente")
raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e '
'Data Final devem ser preenchidos obrigatoriamente'))
elif data_inicial > data_final:
self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(data_final, data_inicial))
raise ValidationError(_('A Data Final não pode ser menor que a Data Inicial'))
return cleaned_data

21
sapl/materia/migrations/0042_tipomaterialegislativa_sequencia_regimental.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-03-20 11:26
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0041_proposicao_numero_materia_futuro'),
]
operations = [
migrations.AddField(
model_name='tipomaterialegislativa',
name='sequencia_regimental',
field=models.PositiveIntegerField(
default=0, help_text='A sequência regimental diz respeito ao que define o regimento da Casa Legislativa sobre qual a ordem de entrada das proposições nas Sessões Plenárias.', verbose_name='Sequência Regimental'),
),
]

19
sapl/materia/migrations/0043_auto_20190320_1749.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-03-20 20:49
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('materia', '0042_tipomaterialegislativa_sequencia_regimental'),
]
operations = [
migrations.AlterModelOptions(
name='tipomaterialegislativa',
options={'ordering': ['sequencia_regimental', 'descricao'], 'verbose_name': 'Tipo de Matéria Legislativa', 'verbose_name_plural': 'Tipos de Matérias Legislativas'},
),
]

52
sapl/materia/models.py

@ -78,8 +78,37 @@ class TipoProposicao(models.Model):
return self.descricao
class TipoMateriaManager(models.Manager):
def reordene(self, exclude_pk=None):
tipos = self.get_queryset()
if exclude_pk:
tipos = tipos.exclude(pk=exclude_pk)
for sr, t in enumerate(tipos, 1):
t.sequencia_regimental = sr
t.save()
def reposicione(self, pk, idx):
tipos = self.reordene(exclude_pk=pk)
self.get_queryset(
).filter(
sequencia_regimental__gte=idx
).update(
sequencia_regimental=models.F('sequencia_regimental') + 1
)
self.get_queryset(
).filter(
pk=pk
).update(
sequencia_regimental=idx
)
@reversion.register()
class TipoMateriaLegislativa(models.Model):
objects = TipoMateriaManager()
sigla = models.CharField(max_length=5, verbose_name=_('Sigla'))
descricao = models.CharField(max_length=50, verbose_name=_('Descrição '))
# XXX o que é isso ?
@ -101,10 +130,17 @@ class TipoMateriaLegislativa(models.Model):
verbose_name=_('Sequência de numeração'),
choices=SEQUENCIA_NUMERACAO)
sequencia_regimental = models.PositiveIntegerField(
default=0,
verbose_name=_('Sequência Regimental'),
help_text=_('A sequência regimental diz respeito ao que define '
'o regimento da Casa Legislativa sobre qual a ordem '
'de entrada das proposições nas Sessões Plenárias.'))
class Meta:
verbose_name = _('Tipo de Matéria Legislativa')
verbose_name_plural = _('Tipos de Matérias Legislativas')
ordering = ['descricao']
ordering = ['sequencia_regimental', 'descricao']
def __str__(self):
return self.descricao
@ -630,10 +666,15 @@ class Relatoria(models.Model):
verbose_name_plural = _('Relatorias')
def __str__(self):
return _('%(materia)s - %(tipo)s - %(data)s') % {
if self.tipo_fim_relatoria:
return _('%(materia)s - %(tipo)s - %(data)s') % {
'materia': self.materia,
'tipo': self.tipo_fim_relatoria,
'data': self.data_designacao_relator.strftime("%d/%m/%Y")}
else:
return _('%(materia)s - %(data)s') % {
'materia': self.materia,
'tipo': self.tipo_fim_relatoria,
'data': self.data_designacao_relator}
'data': self.data_designacao_relator.strftime("%d/%m/%Y")}
@reversion.register()
@ -920,7 +961,8 @@ class Tramitacao(models.Model):
('B', 'primeira_votacao', _('1ª Votação')),
('C', 'segunda_terceira_votacao', _('2ª e 3ª Votação')),
('D', 'deliberacao', _('Deliberação')),
('E', 'primeira_segunda_votacao_urgencia', _('1ª e 2ª votações em regime de urgência'))
('E', 'primeira_segunda_votacao_urgencia', _(
'1ª e 2ª votações em regime de urgência'))
)

6
sapl/materia/urls.py

@ -25,7 +25,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
TipoProposicaoCrud, TramitacaoCrud,
TramitacaoEmLoteView, UnidadeTramitacaoCrud,
proposicao_texto, recuperar_materia,
ExcluirTramitacaoEmLoteView, RetornarProposicao)
ExcluirTramitacaoEmLoteView, RetornarProposicao,
MateriaPesquisaSimplesView)
from sapl.norma.views import NormaPesquisaSimplesView
from sapl.protocoloadm.views import (FichaPesquisaAdmView, FichaSelecionaAdmView)
@ -49,6 +50,9 @@ urlpatterns_impressos = [
url(r'^materia/impressos/norma-pesquisa/$',
NormaPesquisaSimplesView.as_view(),
name='impressos_norma_pesquisa'),
url(r'^materia/impressos/materia-pesquisa/$',
MateriaPesquisaSimplesView.as_view(),
name='impressos_materia_pesquisa'),
url(r'^materia/impressos/ficha-pesquisa-adm/$',
FichaPesquisaAdmView.as_view(),
name= 'impressos_ficha_pesquisa_adm'),

166
sapl/materia/views.py

@ -3,7 +3,6 @@ import logging
from random import choice
from string import ascii_letters, digits
from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import HTML
from django.conf import settings
from django.contrib import messages
@ -11,7 +10,7 @@ from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.urlresolvers import reverse
from django.db.models import Max
from django.db.models import Max, Q
from django.http import HttpResponse, JsonResponse
from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
@ -32,6 +31,7 @@ from sapl.comissoes.models import Comissao, Participacao
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT,
STATUS_TA_PRIVATE)
from sapl.compilacao.views import IntegracaoTaView
from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud,
@ -41,7 +41,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm,
ConfirmarProposicaoForm,
DevolverProposicaoForm, LegislacaoCitadaForm,
OrgaoForm, ProposicaoForm, TipoProposicaoForm,
TramitacaoForm, TramitacaoUpdateForm)
TramitacaoForm, TramitacaoUpdateForm, MateriaPesquisaSimplesForm)
from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo
@ -75,9 +75,6 @@ AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
OrigemCrud = CrudAux.build(Origem, '')
TipoMateriaCrud = CrudAux.build(
TipoMateriaLegislativa, 'tipo_materia_legislativa')
RegimeTramitacaoCrud = CrudAux.build(
RegimeTramitacao, 'regime_tramitacao')
@ -214,7 +211,8 @@ class CriarProtocoloMateriaView(CreateView):
context['form'].fields['ano'].initial = protocolo.ano
if protocolo:
if protocolo.timestamp:
context['form'].fields['data_apresentacao'].initial = protocolo.timestamp.date()
context['form'].fields['data_apresentacao'].initial = protocolo.timestamp.date(
)
elif protocolo.timestamp_data_hora_manual:
context['form'].fields['data_apresentacao'].initial = protocolo.timestamp_data_hora_manual.date()
elif protocolo.data:
@ -1115,7 +1113,8 @@ class RelatoriaCrud(MasterDetailCrud):
try:
self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(
context['form'].initial['comissao']))
comissao = Comissao.objects.get(pk=context['form'].initial['comissao'])
comissao = Comissao.objects.get(
pk=context['form'].initial['comissao'])
except:
self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(
context['form'].initial['comissao']))
@ -1125,12 +1124,19 @@ class RelatoriaCrud(MasterDetailCrud):
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(
context['form'].initial['comissao']))
materia = MateriaLegislativa.objects.get(pk=self.kwargs.get('pk'))
ano_materia = materia.ano
materia = MateriaLegislativa.objects.get(
pk=self.kwargs.get('pk'))
data_materia = materia.data_apresentacao
comissao = Comissao.objects.get(pk=context['form'].initial['comissao'])
composicoes = comissao.composicao_set.all()
composicao = comissao.composicao_set.filter(periodo__data_inicio__year=ano_materia)
comissao = Comissao.objects.get(
pk=context['form'].initial['comissao'])
composicao = comissao.composicao_set.filter(
Q(periodo__data_fim__isnull=False,
periodo__data_inicio__lte=data_materia,
periodo__data_fim__gte=data_materia) |
Q(periodo__data_fim__isnull=True,
periodo__data_inicio__lte=data_materia)
)
participacoes = Participacao.objects.select_related().filter(composicao=composicao)
@ -1182,12 +1188,15 @@ class RelatoriaCrud(MasterDetailCrud):
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(
context['form'].initial['comissao']))
relatoria = Relatoria.objects.select_related('materia').get(pk=self.kwargs.get('pk'))
relatoria = Relatoria.objects.select_related(
'materia').get(pk=self.kwargs.get('pk'))
ano_materia = relatoria.materia.ano
comissao = Comissao.objects.get(pk=context['form'].initial['comissao'])
comissao = Comissao.objects.get(
pk=context['form'].initial['comissao'])
composicoes = comissao.composicao_set.all()
composicao = comissao.composicao_set.filter(periodo__data_inicio__year=ano_materia)
composicao = comissao.composicao_set.filter(
periodo__data_inicio__year=ano_materia)
participacoes = Participacao.objects.select_related().filter(composicao=composicao)
@ -1952,11 +1961,11 @@ class AcompanhamentoMateriaView(CreateView):
"materia",
materia,
destinatario)
self.logger.debug('user=' + usuario.username + '. Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
@ -1973,7 +1982,7 @@ class AcompanhamentoMateriaView(CreateView):
return self.render_to_response(
{'form': form,
'materia': materia
})
})
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(
@ -2021,6 +2030,11 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
tz = timezone.get_current_timezone()
if len(request.POST['autor']) > 50:
msg = _('Autor tem que ter menos do que 50 caracteres.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
for materia_id in marcadas:
doc = DocumentoAcessorio()
doc.materia_id = materia_id
@ -2036,6 +2050,7 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs)
class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AnexadaEmLoteFilterSet
template_name = 'materia/em_lote/anexada.html'
@ -2049,15 +2064,31 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
context['subnav_template_name'] = 'materia/subnav.yaml'
context['title'] = _('Matérias Anexadas em Lote')
# Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid():
if not self.request.GET.get('tipo', " "):
msg =_('Por favor, selecione um tipo de matéria.')
messages.add_message(self.request, messages.ERROR, msg)
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
msg =_('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
msg =_('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
qr = self.request.GET.copy()
context['object_list'] = context['object_list'].order_by(
'ano', 'numero')
principal = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
not_list = [self.kwargs['pk']] + \
[m for m in principal.materia_principal_set.all().values_list('materia_anexada_id', flat=True)]
context['object_list'] = context['object_list'].exclude(pk__in=not_list)
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
@ -2079,10 +2110,10 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
data_desanexacao = None
else:
data_desanexacao = datetime.strptime(
request.POST['data_desanexacao'], "%d/%m/%Y").date()
request.POST['data_desanexacao'], "%d/%m/%Y").date()
principal = MateriaLegislativa.objects.get(pk = kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in = marcadas):
principal = MateriaLegislativa.objects.get(pk=kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in=marcadas):
anexada = Anexada()
anexada.materia_principal = principal
@ -2286,13 +2317,11 @@ class ImpressosView(PermissionRequiredMixin, TemplateView):
def gerar_pdf_impressos(request, context, template_name):
template = loader.get_template(template_name)
html = template.render(context, request)
pdf = weasyprint.HTML(string=html, base_url=request.build_absolute_uri()
).write_pdf()
pdf = weasyprint.HTML(
string=html, base_url=request.build_absolute_uri()).write_pdf()
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = (
'inline; filename="relatorio_impressos.pdf"')
response['Content-Disposition'] = 'inline; filename="relatorio_impressos.pdf"'
response['Content-Transfer-Encoding'] = 'binary'
return response
@ -2300,7 +2329,7 @@ def gerar_pdf_impressos(request, context, template_name):
class EtiquetaPesquisaView(PermissionRequiredMixin, FormView):
form_class = EtiquetaPesquisaForm
template_name = 'materia/impressos/etiqueta.html'
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def form_valid(self, form):
@ -2341,7 +2370,7 @@ class EtiquetaPesquisaView(PermissionRequiredMixin, FormView):
class FichaPesquisaView(PermissionRequiredMixin, FormView):
form_class = FichaPesquisaForm
template_name = 'materia/impressos/ficha.html'
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def form_valid(self, form):
@ -2359,7 +2388,7 @@ class FichaPesquisaView(PermissionRequiredMixin, FormView):
class FichaSelecionaView(PermissionRequiredMixin, FormView):
logger = logging.getLogger(__name__)
form_class = FichaSelecionaForm
template_name = 'materia/impressos/ficha_seleciona.html'
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def get_context_data(self, **kwargs):
@ -2456,3 +2485,76 @@ class ExcluirTramitacaoEmLoteView(PermissionRequiredMixin, FormView):
tramitacao.delete()
return redirect(self.get_success_url())
class MateriaPesquisaSimplesView(PermissionRequiredMixin, FormView):
form_class = MateriaPesquisaSimplesForm
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def form_valid(self, form):
template_materia = 'materia/impressos/materias_pdf.html'
kwargs = {}
if form.cleaned_data.get('tipo_materia'):
kwargs.update({'tipo': form.cleaned_data['tipo_materia']})
if form.cleaned_data.get('data_inicial'):
kwargs.update({'data__gte': form.cleaned_data['data_inicial'],
'data__lte': form.cleaned_data['data_final']})
materias = MateriaLegislativa.objects.filter(
**kwargs).order_by('-numero', 'ano')
quantidade_materias = materias.count()
materias = materias[:2000] if quantidade_materias > 2000 else materias
context = {'quantidade': quantidade_materias,
'titulo': form.cleaned_data['titulo'],
'materias': materias}
return gerar_pdf_impressos(self.request, context, template_materia)
class TipoMateriaCrud(CrudAux):
model = TipoMateriaLegislativa
class DetailView(CrudAux.DetailView):
layout_key = 'TipoMateriaLegislativaDetail'
class DeleteView(CrudAux.DeleteView):
def delete(self, request, *args, **kwargs):
d = CrudAux.DeleteView.delete(self, request, *args, **kwargs)
TipoMateriaLegislativa.objects.reordene()
return d
class ListView(CrudAux.ListView):
paginate_by = None
layout_key = 'TipoMateriaLegislativaDetail'
template_name = "materia/tipomaterialegislativa_list.html"
def hook_sigla(self, obj, default, url):
return '<a href="{}" pk="{}">{}</a>'.format(
url, obj.id, obj.sigla), ''
def get(self, request, *args, **kwargs):
if TipoMateriaLegislativa.objects.filter(
sequencia_regimental=0).exists():
TipoMateriaLegislativa.objects.reordene()
return CrudAux.ListView.get(self, request, *args, **kwargs)
class CreateView(CrudAux.CreateView):
def form_valid(self, form):
fv = super().form_valid(form)
if not TipoMateriaLegislativa.objects.exclude(
sequencia_regimental=0).exists():
TipoMateriaLegislativa.objects.reordene()
else:
sr__max = TipoMateriaLegislativa.objects.all().aggregate(
Max('sequencia_regimental'))
self.object.sequencia_regimental = sr__max['sequencia_regimental__max'] + 1
self.object.save()
return fv

24
sapl/norma/forms.py

@ -392,7 +392,7 @@ class NormaPesquisaSimplesForm(forms.Form):
logger = logging.getLogger(__name__)
def __init__(self, *args, **kwargs):
super(NormaPesquisaSimplesForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
row1 = to_row(
[('tipo_norma', 6),
@ -405,36 +405,30 @@ class NormaPesquisaSimplesForm(forms.Form):
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
('Índice de Normas'),
'Índice de Normas',
row1, row2,
form_actions(label='Pesquisar')
)
)
def clean(self):
super(NormaPesquisaSimplesForm, self).clean()
super().clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
data_inicial = cleaned_data['data_inicial']
data_final = cleaned_data['data_final']
if (data_inicial and data_final and
data_inicial > data_final):
self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(
data_final, data_inicial))
raise ValidationError(_(
'A Data Final não pode ser menor que a Data Inicial'))
else:
condicao1 = data_inicial and not data_final
condicao2 = not data_inicial and data_final
if condicao1 or condicao2:
if data_inicial or data_final:
if not(data_inicial and data_final):
self.logger.error("Caso pesquise por data, os campos de Data Inicial e "
"Data Final devem ser preenchidos obrigatoriamente")
raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e ' +
raise ValidationError(_('Caso pesquise por data, os campos de Data Inicial e '
'Data Final devem ser preenchidos obrigatoriamente'))
elif data_inicial > data_final:
self.logger.error("Data Final ({}) menor que a Data Inicial ({}).".format(data_final, data_inicial))
raise ValidationError(_('A Data Final não pode ser menor que a Data Inicial'))
return cleaned_data

31
sapl/norma/views.py

@ -345,12 +345,10 @@ class ImpressosView(PermissionRequiredMixin, TemplateView):
def gerar_pdf_impressos(request, context, template_name):
template = loader.get_template(template_name)
html = template.render(context, request)
pdf = weasyprint.HTML(string=html, base_url=request.build_absolute_uri()
).write_pdf()
pdf = weasyprint.HTML(string=html, base_url=request.build_absolute_uri()).write_pdf()
response = HttpResponse(pdf, content_type='application/pdf')
response['Content-Disposition'] = (
'inline; filename="relatorio_impressos.pdf"')
response['Content-Disposition'] = 'inline; filename="relatorio_impressos.pdf"'
response['Content-Transfer-Encoding'] = 'binary'
return response
@ -358,29 +356,28 @@ def gerar_pdf_impressos(request, context, template_name):
class NormaPesquisaSimplesView(PermissionRequiredMixin, FormView):
form_class = NormaPesquisaSimplesForm
template_name = 'materia/impressos/norma.html'
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def form_valid(self, form):
normas = NormaJuridica.objects.all().order_by(
'numero')
template_norma = 'materia/impressos/normas_pdf.html'
titulo = form.cleaned_data['titulo']
if form.cleaned_data['tipo_norma']:
normas = normas.filter(tipo=form.cleaned_data['tipo_norma'])
kwargs = {}
if form.cleaned_data.get('tipo_norma'):
kwargs.update({'tipo': form.cleaned_data['tipo_norma']})
if form.cleaned_data['data_inicial']:
normas = normas.filter(
data__gte=form.cleaned_data['data_inicial'],
data__lte=form.cleaned_data['data_final'])
if form.cleaned_data.get('data_inicial'):
kwargs.update({'data__gte': form.cleaned_data['data_inicial'],
'data__lte': form.cleaned_data['data_final']})
qtd_resultados = len(normas)
if qtd_resultados > 2000:
normas = normas[:2000]
normas = NormaJuridica.objects.filter(**kwargs).order_by('-numero', 'ano')
context = {'quantidade': qtd_resultados,
quantidade_normas = normas.count()
normas = normas[:2000] if quantidade_normas > 2000 else normas
context = {'quantidade': quantidade_normas,
'titulo': titulo,
'normas': normas}

2
sapl/parlamentares/views.py

@ -207,7 +207,7 @@ class PesquisarParlamentarView(FilterView):
data = self.filterset.data
url = ''
if data:
url = "&" + str(self.request.environ['QUERY_STRING'])
url = "&" + str(self.request.META['QUERY_STRING'])
if url.startswith("&page"):
ponto_comeco = url.find('nome_parlamentar=') - 1
url = url[ponto_comeco:]

4
sapl/protocoloadm/views.py

@ -1152,7 +1152,7 @@ class ImpressosView(PermissionRequiredMixin, TemplateView):
class FichaPesquisaAdmView(PermissionRequiredMixin, FormView):
form_class = FichaPesquisaAdmForm
template_name = 'materia/impressos/ficha.html'
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def form_valid(self, form):
@ -1170,7 +1170,7 @@ class FichaPesquisaAdmView(PermissionRequiredMixin, FormView):
class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
logger = logging.getLogger(__name__)
form_class = FichaSelecionaAdmForm
template_name = 'materia/impressos/ficha_seleciona.html'
template_name = 'materia/impressos/impressos_form.html'
permission_required = ('materia.can_access_impressos', )
def get_context_data(self, **kwargs):

47
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -6,7 +6,7 @@
"""
import os
import time
import logging
from django.template.defaultfilters import safe
from django.utils.html import strip_tags
from trml2pdf import parseString
@ -378,6 +378,7 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
"""
"""
arquivoPdf = str(int(time.time() * 100)) + ".pdf"
logger = logging.getLogger(__name__)
tmp = ''
tmp += '<?xml version="1.0" encoding="utf-8" standalone="no" ?>\n'
@ -411,21 +412,37 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
'oradores_expli': oradores(lst_oradores),
'ocorr_sessao': ocorrencias(lst_ocorrencias)
}
if ordenacao:
tmp += dict_ord_template[ordenacao.primeiro]
tmp += dict_ord_template[ordenacao.segundo]
tmp += dict_ord_template[ordenacao.terceiro]
tmp += dict_ord_template[ordenacao.quarto]
tmp += dict_ord_template[ordenacao.quinto]
tmp += dict_ord_template[ordenacao.sexto]
tmp += dict_ord_template[ordenacao.setimo]
tmp += dict_ord_template[ordenacao.oitavo]
tmp += dict_ord_template[ordenacao.nono]
tmp += dict_ord_template[ordenacao.decimo]
tmp += dict_ord_template[ordenacao.decimo_primeiro]
tmp += dict_ord_template[ordenacao.decimo_segundo]
tmp += dict_ord_template[ordenacao.decimo_terceiro]
try:
tmp += dict_ord_template[ordenacao.primeiro]
tmp += dict_ord_template[ordenacao.segundo]
tmp += dict_ord_template[ordenacao.terceiro]
tmp += dict_ord_template[ordenacao.quarto]
tmp += dict_ord_template[ordenacao.quinto]
tmp += dict_ord_template[ordenacao.sexto]
tmp += dict_ord_template[ordenacao.setimo]
tmp += dict_ord_template[ordenacao.oitavo]
tmp += dict_ord_template[ordenacao.nono]
tmp += dict_ord_template[ordenacao.decimo]
tmp += dict_ord_template[ordenacao.decimo_primeiro]
tmp += dict_ord_template[ordenacao.decimo_segundo]
tmp += dict_ord_template[ordenacao.decimo_terceiro]
except KeyError as e:
logger.error("KeyError: " + str(e) + ". Erro ao tentar utilizar "
"configuração de ordenação. Utilizando ordenação padrão.")
tmp += inf_basicas(inf_basicas_dic)
tmp += mesa(lst_mesa)
tmp += presenca(lst_presenca_sessao, lst_ausencia_sessao)
tmp += expedientes(lst_expedientes)
tmp += expediente_materia(lst_expediente_materia)
tmp += expediente_materia_vot_nom(lst_expediente_materia_vot_nom)
tmp += oradores_expediente(lst_oradores_expediente)
tmp += presenca_ordem_dia(lst_presenca_ordem_dia)
tmp += votacao(lst_votacao)
tmp += votacao_vot_nom(lst_votacao_vot_nom)
tmp += oradores(lst_oradores)
tmp += ocorrencias(lst_ocorrencias)
else:
tmp += inf_basicas(inf_basicas_dic)

5
sapl/relatorios/urls.py

@ -5,7 +5,8 @@ from .views import (relatorio_capa_processo,
relatorio_documento_administrativo, relatorio_espelho,
relatorio_etiqueta_protocolo, relatorio_materia,
relatorio_ordem_dia, relatorio_pauta_sessao,
relatorio_protocolo, relatorio_sessao_plenaria)
relatorio_protocolo, relatorio_sessao_plenaria,
resumo_ata_pdf)
app_name = AppConfig.name
@ -28,4 +29,6 @@ urlpatterns = [
relatorio_etiqueta_protocolo, name='relatorio_etiqueta_protocolo'),
url(r'^relatorios/pauta-sessao/(?P<pk>\d+)/$',
relatorio_pauta_sessao, name='relatorio_pauta_sessao'),
url(r'^relatorios/(?P<pk>\d+)/resumo_ata$',
resumo_ata_pdf, name='resumo_ata_pdf'),
]

73
sapl/relatorios/views.py

@ -2,12 +2,15 @@ from datetime import datetime as dt
import html
import logging
import re
import tempfile
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
from sapl.settings import MEDIA_URL
from sapl.base.models import Autor, CasaLegislativa
from sapl.comissoes.models import Comissao
from sapl.materia.models import (Autoria, MateriaLegislativa, Numeracao,
@ -24,12 +27,20 @@ from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data
from sapl.sessao.views import (get_identificação_basica, get_mesa_diretora,
get_presenca_sessao,get_expedientes,
get_materias_expediente,get_oradores_expediente,
get_presenca_ordem_do_dia,get_materias_ordem_do_dia,
get_oradores_explicações_pessoais, get_ocorrencias_da_sessão)
from .templates import (pdf_capa_processo_gerar,
pdf_documento_administrativo_gerar, pdf_espelho_gerar,
pdf_etiqueta_protocolo_gerar, pdf_materia_gerar,
pdf_ordem_dia_gerar, pdf_pauta_sessao_gerar,
pdf_protocolo_gerar, pdf_sessao_plenaria_gerar)
from weasyprint import HTML, CSS
def get_kwargs_params(request, fields):
kwargs = {}
@ -1199,3 +1210,65 @@ def get_pauta_sessao(sessao, casa):
return (lst_expediente_materia,
lst_votacao,
inf_basicas_dic)
def make_pdf(base_url,main_template,header_template,main_css='',header_css=''):
html = HTML(base_url=base_url, string=main_template)
main_doc = html.render(stylesheets=[])
def get_page_body(boxes):
for box in boxes:
if box.element_tag == 'body':
return box
return get_page_body(box.all_children())
# Template of header
html = HTML(base_url=base_url,string=header_template)
header = html.render(stylesheets=[CSS(string='@page {size:A4; margin:1cm;}')])
header_page = header.pages[0]
header_body = get_page_body(header_page._page_box.all_children())
header_body = header_body.copy_with_children(header_body.all_children())
for page in main_doc.pages:
page_body = get_page_body(page._page_box.all_children())
page_body.children += header_body.all_children()
pdf_file = main_doc.write_pdf()
return pdf_file
def resumo_ata_pdf(request,pk):
base_url = request.build_absolute_uri()
casa = CasaLegislativa.objects.first()
rodape = ' '.join(get_rodape(casa))
sessao_plenaria = SessaoPlenaria.objects.get(pk=pk)
context = {}
context.update(get_identificação_basica(sessao_plenaria))
context.update(get_mesa_diretora(sessao_plenaria))
context.update(get_presenca_sessao(sessao_plenaria))
context.update(get_expedientes(sessao_plenaria))
context.update(get_materias_expediente(sessao_plenaria))
context.update(get_oradores_expediente(sessao_plenaria))
context.update(get_presenca_ordem_do_dia(sessao_plenaria))
context.update(get_materias_ordem_do_dia(sessao_plenaria))
context.update(get_oradores_explicações_pessoais(sessao_plenaria))
context.update(get_ocorrencias_da_sessão(sessao_plenaria))
context.update({'object':sessao_plenaria})
context.update({'data': dt.today().strftime('%d/%m/%Y')})
context.update({'rodape':rodape})
header_context = {"casa":casa, 'logotipo':casa.logotipo, 'MEDIA_URL': MEDIA_URL}
html_template = render_to_string('relatorios/relatorio_ata.html',context)
html_header = render_to_string('relatorios/header_ata.html', header_context)
pdf_file = make_pdf(base_url=base_url,main_template=html_template,header_template=html_header)
response = HttpResponse(content_type='application/pdf;')
response['Content-Disposition'] = 'inline; filename=relatorio.pdf'
response['Content-Transfer-Encoding'] = 'binary'
response.write(pdf_file)
return response

103
sapl/sessao/tests/test_sessao_view.py

@ -4,7 +4,21 @@ from django.utils.translation import ugettext_lazy as _
from model_mommy import mommy
from sapl.parlamentares.models import Legislatura, SessaoLegislativa
from sapl.sessao.models import SessaoPlenaria, TipoSessaoPlenaria
from sapl.sessao.models import (SessaoPlenaria, TipoSessaoPlenaria,
IntegranteMesa, SessaoPlenariaPresenca,
JustificativaAusencia, ExpedienteSessao,
TipoExpediente, ExpedienteMateria,
Orador, OcorrenciaSessao)
from sapl.parlamentares.models import Parlamentar, CargoMesa, Filiacao
from sapl.sessao.views import (get_identificação_basica, get_conteudo_multimidia,
get_mesa_diretora, get_presenca_sessao,
get_expedientes, get_materias_expediente,
get_oradores_expediente, get_presenca_ordem_do_dia,
get_materias_ordem_do_dia, get_oradores_explicações_pessoais,
get_ocorrencias_da_sessão
)
@pytest.mark.django_db(transaction=False)
@ -47,3 +61,90 @@ def test_incluir_sessao_errors(admin_client):
[_('Este campo é obrigatório.')])
assert (response.context_data['form'].errors['hora_inicio'] ==
[_('Este campo é obrigatório.')])
@pytest.mark.django_db(transaction=False)
class TestResumoView():
def setup(self):
self.sessao_plenaria = mommy.make(SessaoPlenaria)
self.parlamentar = mommy.make(Parlamentar)
self.cargo_mesa = mommy.make(CargoMesa)
self.integrante_mesa = IntegranteMesa(sessao_plenaria=self.sessao_plenaria,
parlamentar=self.parlamentar,
cargo=self.cargo_mesa)
self.integrante_mesa.save()
def test_get_identificação_basica(self):
id_basica = get_identificação_basica(self.sessao_plenaria)
info_basica = id_basica['basica']
assert info_basica[0] == 'Tipo de Sessão: ' + str(self.sessao_plenaria.tipo)
data_inicio = self.sessao_plenaria.data_inicio
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else ''
assert info_basica[1] == 'Abertura: ' + abertura +' - '+ self.sessao_plenaria.hora_inicio
data_fim = self.sessao_plenaria.data_fim
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else ''
assert info_basica[2] == 'Encerramento: ' + encerramento +' '+ self.sessao_plenaria.hora_fim
def test_get_conteudo_multimidia(self):
multimidia = get_conteudo_multimidia(self.sessao_plenaria)
url_audio = _('Audio: Indisponível')
multimidia_video = _('Video: Indisponível')
if self.sessao_plenaria.url_audio:
url_audio = _('Audio: ') + str(sessao_plenaria.url_audio)
if self.sessao_plenaria.url_video:
multimidia_video = _('Video: ') + str(sessao_plenaria.url_video)
assert multimidia == {'multimidia_audio':url_audio,
'multimidia_video':multimidia_video}
def test_get_mesa_diretora(self):
mesa = get_mesa_diretora(self.sessao_plenaria)
assert mesa == {'mesa':[{
'cargo': self.cargo_mesa,
'parlamentar': self.parlamentar
}]}
def test_get_presenca_sessao(self):
justificativa = mommy.make(JustificativaAusencia,sessao_plenaria=self.sessao_plenaria)
presenca = mommy.make(SessaoPlenariaPresenca,sessao_plenaria=self.sessao_plenaria)
resposta_presenca = get_presenca_sessao(self.sessao_plenaria)
assert resposta_presenca['presenca_sessao'] == [presenca.parlamentar]
assert resposta_presenca['justificativa_ausencia'][0] == justificativa
def test_get_expedientes(self):
tipo_expediente = mommy.make(TipoExpediente)
expediente = mommy.make(ExpedienteSessao,sessao_plenaria=self.sessao_plenaria,tipo=tipo_expediente)
resposta_expediente = get_expedientes(self.sessao_plenaria)
assert resposta_expediente['expedientes'] == [{
'conteudo': expediente.conteudo,
'tipo': tipo_expediente
}]
def test_get_materias_expediente(self):
pass
def test_get_oradores_explicações_pessoais(self):
parlamentar = mommy.make(Parlamentar)
partido_sigla = mommy.make(Filiacao, parlamentar=parlamentar)
orador = mommy.make(Orador,sessao_plenaria=self.sessao_plenaria,parlamentar=parlamentar)
resultado_get_oradores = get_oradores_explicações_pessoais(self.sessao_plenaria)
assert resultado_get_oradores['oradores_explicacoes'] == [{
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': partido_sigla.partido.sigla
}]
def test_get_ocorrencias_da_sessão(self):
ocorrencia = mommy.make(OcorrenciaSessao, sessao_plenaria=self.sessao_plenaria)
resultado_get_ocorrencia = get_ocorrencias_da_sessão(self.sessao_plenaria)
assert resultado_get_ocorrencia['ocorrencias_da_sessao'][0] == ocorrencia

18
sapl/sessao/urls.py

@ -12,7 +12,7 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
PresencaOrdemDiaView, PresencaView,
ResumoOrdenacaoView, ResumoView, ResumoAtaView, RetiradaPautaCrud, SessaoCrud,
TipoJustificativaCrud, TipoExpedienteCrud, TipoResultadoVotacaoCrud,
TipoExpedienteCrud, TipoResultadoVotacaoCrud,TipoRetiradaPautaCrud,
TipoExpedienteCrud, TipoResultadoVotacaoCrud, TipoRetiradaPautaCrud,
TipoSessaoCrud, VotacaoEditView,
VotacaoExpedienteEditView,
VotacaoExpedienteView, VotacaoNominalEditView,
@ -30,7 +30,7 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
reordernar_materias_ordem,
sessao_legislativa_legislatura_ajax,
VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente,
VotacaoEmBlocoSimbolicaView,VotacaoEmBlocoNominalView)
VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView)
from .apps import AppConfig
@ -59,9 +59,13 @@ urlpatterns = [
name='remove_parlamentar_composicao'),
url(r'^sessao/recuperar-materia/', recuperar_materia),
url(r'^sessao/recuperar-numero-sessao/', recuperar_numero_sessao),
url(r'^sessao/recuperar-numero-sessao/',
recuperar_numero_sessao,
name='recuperar_numero_sessao_view'
),
url(r'^sessao/sessao-legislativa-legislatura-ajax/',
sessao_legislativa_legislatura_ajax),
sessao_legislativa_legislatura_ajax,
name='sessao_legislativa_legislatura_ajax_view'),
url(r'^sessao/(?P<pk>\d+)/(?P<spk>\d+)/abrir-votacao$',
abrir_votacao,
@ -78,7 +82,7 @@ urlpatterns = [
url(r'^sistema/sessao-plenaria/tipo-expediente/',
include(TipoExpedienteCrud.get_urls())),
url(r'^sistema/sessao-plenaria/tipo-justificativa/',
include(TipoJustificativaCrud.get_urls())),
include(TipoJustificativaCrud.get_urls())),
url(r'^sistema/sessao-plenaria/tipo-retirada-pauta/',
include(TipoRetiradaPautaCrud.get_urls())),
url(r'^sistema/bancada/',
@ -123,7 +127,7 @@ urlpatterns = [
url(r'^sessao/(?P<pk>\d+)/votacao_bloco/votnom$',
VotacaoEmBlocoNominalView.as_view(), name='votacaobloconom'),
url(r'^sessao/(?P<pk>\d+)/votacao_bloco/votsimb$',
VotacaoEmBlocoSimbolicaView.as_view(), name='votacaoblocosimb'),
VotacaoEmBlocoSimbolicaView.as_view(), name='votacaoblocosimb'),
url(r'^sessao/(?P<pk>\d+)/votacao_bloco_expediente$',
VotacaoEmBlocoExpediente.as_view(),
name='votacao_bloco_expediente'),
@ -145,7 +149,7 @@ urlpatterns = [
VotacaoEditView.as_view(), name='votacaosecretaedit'),
url(r'^sessao/(?P<pk>\d+)/matordemdia/votsimb/(?P<oid>\d+)/(?P<mid>\d+)$',
VotacaoView.as_view(), name='votacaosimbolica'),
url(r'^sessao/(?P<pk>\d+)/matordemdia/votsimbbloco/$',
VotacaoView.as_view(), name='votacaosimbolicabloco'),

614
sapl/sessao/views.py

@ -63,18 +63,29 @@ TipoRetiradaPautaCrud = CrudAux.build(TipoRetiradaPauta, 'tipo_retirada_pauta')
def reordernar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter(
sessao_plenaria_id=pk)
sessao_plenaria_id=pk
).order_by(
'materia__tipo__sequencia_regimental',
'materia__ano',
'materia__numero'
)
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 reordernar_materias_ordem(request, pk):
ordens = OrdemDia.objects.filter(
sessao_plenaria_id=pk)
sessao_plenaria_id=pk
).order_by(
'materia__tipo__sequencia_regimental',
'materia__ano',
'materia__numero'
)
for ordem_num, o in enumerate(ordens, 1):
o.numero_ordem = ordem_num
o.save()
@ -1022,9 +1033,6 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView):
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):
template_name = 'sessao/mesa.html'
@ -1295,257 +1303,344 @@ def get_turno(turno):
return ''
class ResumoView(DetailView):
template_name = 'sessao/resumo.html'
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get_identificação_basica(sessao_plenaria):
# =====================================================================
# Identificação Básica
data_inicio = sessao_plenaria.data_inicio
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else ''
data_fim = sessao_plenaria.data_fim
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else ''
return({'basica': [
_('Tipo de Sessão: %(tipo)s') % {'tipo': sessao_plenaria.tipo},
_('Abertura: %(abertura)s - %(hora_inicio)s') % {
'abertura': abertura, 'hora_inicio': sessao_plenaria.hora_inicio},
_('Encerramento: %(encerramento)s %(hora_fim)s') % {
'encerramento': encerramento, 'hora_fim': sessao_plenaria.hora_fim}
],
'sessaoplenaria': sessao_plenaria})
def get_conteudo_multimidia(sessao_plenaria):
context = {}
if sessao_plenaria.url_audio:
context['multimidia_audio'] = _(
'Audio: ') + str(sessao_plenaria.url_audio)
else:
context['multimidia_audio'] = _('Audio: Indisponível')
if sessao_plenaria.url_video:
context['multimidia_video'] = _(
'Video: ') + str(sessao_plenaria.url_video)
else:
context['multimidia_video'] = _('Video: Indisponível')
return context
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
# =====================================================================
# Identificação Básica
data_inicio = self.object.data_inicio
abertura = data_inicio.strftime('%d/%m/%Y') if data_inicio else ''
def get_mesa_diretora(sessao_plenaria):
mesa = IntegranteMesa.objects.filter(sessao_plenaria=sessao_plenaria).order_by('cargo_id')
integrantes = [{'parlamentar': m.parlamentar,
'cargo': m.cargo} for m in mesa]
return {'mesa': integrantes}
data_fim = self.object.data_fim
encerramento = data_fim.strftime('%d/%m/%Y') + ' -' if data_fim else ''
context.update({'basica': [
_('Tipo de Sessão: %(tipo)s') % {'tipo': self.object.tipo},
_('Abertura: %(abertura)s - %(hora_inicio)s') % {
'abertura': abertura, 'hora_inicio': self.object.hora_inicio},
_('Encerramento: %(encerramento)s %(hora_fim)s') % {
'encerramento': encerramento, 'hora_fim': self.object.hora_fim}
]})
# =====================================================================
# Conteúdo Multimídia
if self.object.url_audio:
context.update({'multimidia_audio':
_('Audio: ') + str(self.object.url_audio)})
else:
context.update({'multimidia_audio': _('Audio: Indisponível')})
def get_presenca_sessao(sessao_plenaria):
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(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')
return ({'presenca_sessao': parlamentares_sessao,
'justificativa_ausencia': ausentes_sessao})
if self.object.url_video:
context.update({'multimidia_video':
_('Video: ') + str(self.object.url_video)})
def get_expedientes(sessao_plenaria):
expediente = ExpedienteSessao.objects.filter(
sessao_plenaria_id=sessao_plenaria.id).order_by('tipo__nome')
expedientes = []
for e in expediente:
tipo = TipoExpediente.objects.get(id=e.tipo_id)
conteudo = e.conteudo
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
return ({'expedientes': expedientes})
def get_materias_expediente(sessao_plenaria):
materias = ExpedienteMateria.objects.filter(
sessao_plenaria_id=sessao_plenaria.id)
materias_expediente = []
for m in materias:
ementa = m.materia.ementa
titulo = m.materia
numero = m.numero_ordem
tramitacao = m.materia.tramitacao_set.last()
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
rv = m.registrovotacao_set.first()
rp = m.retiradapauta_set.filter(materia=m.materia).first()
if rv:
resultado = rv.tipo_resultado_votacao.nome
resultado_observacao = rv.observacao
elif rp:
resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao
else:
context.update({'multimidia_video': _('Video: Indisponível')})
resultado = _('Matéria não votada')
resultado_observacao = _(' ')
autoria = Autoria.objects.filter(materia_id=m.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': m.materia.numero_protocolo,
'numero_processo': m.materia.numeracao_set.last(),
'observacao': m.observacao
}
materias_expediente.append(mat)
context = {'materia_expediente': materias_expediente}
return context
# =====================================================================
# Mesa Diretora
mesa = IntegranteMesa.objects.filter(
sessao_plenaria=self.object)
integrantes = []
for m in mesa:
parlamentar = Parlamentar.objects.get(
id=m.parlamentar_id)
cargo = CargoMesa.objects.get(
id=m.cargo_id)
integrante = {'parlamentar': parlamentar, 'cargo': cargo}
integrantes.append(integrante)
def get_oradores_expediente(sessao_plenaria):
oradores = []
for orador in OradorExpediente.objects.filter(
sessao_plenaria_id=sessao_plenaria.id).order_by('numero_ordem'):
numero_ordem = orador.numero_ordem
url_discurso = orador.url_discurso
observacao = orador.observacao
parlamentar = Parlamentar.objects.get(
id=orador.parlamentar_id)
ora = {'numero_ordem': numero_ordem,
'url_discurso': url_discurso,
'parlamentar': parlamentar,
'observacao': observacao
}
oradores.append(ora)
return {'oradores': oradores}
context.update({'mesa': ordenar_integrantes_por_cargo(integrantes)})
# =====================================================================
# Presença Sessão
presencas = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=self.object.id
).order_by('parlamentar__nome_parlamentar')
def get_presenca_ordem_do_dia(sessao_plenaria):
parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')]
parlamentares_sessao = [p.parlamentar for p in presencas]
return {'presenca_ordem': parlamentares_ordem}
ausentes_sessao = JustificativaAusencia.objects.filter(
sessao_plenaria_id=self.object.id
).order_by('parlamentar__nome_parlamentar')
context.update({'presenca_sessao': parlamentares_sessao,
'justificativa_ausencia': ausentes_sessao})
def get_assinaturas(sessao_plenaria):
mesa_dia = get_mesa_diretora(sessao_plenaria)['mesa']
# =====================================================================
# Expedientes
expediente = ExpedienteSessao.objects.filter(
sessao_plenaria_id=self.object.id).order_by('tipo__nome')
presidente_dia = [next(iter(
[m['parlamentar'] for m in mesa_dia if m['cargo'].descricao == 'Presidente']),
'')]
expedientes = []
for e in expediente:
tipo = TipoExpediente.objects.get(id=e.tipo_id)
conteudo = e.conteudo
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
context.update({'expedientes': expedientes})
parlamentares_ordem = [p.parlamentar for p in PresencaOrdemDia.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar')]
# =====================================================================
# Matérias Expediente
materias = ExpedienteMateria.objects.filter(
sessao_plenaria_id=self.object.id)
parlamentares_mesa = [m['parlamentar'] for m in mesa_dia]
materias_expediente = []
for m in materias:
# filtra parlamentares retirando os que sao da mesa
parlamentares_ordem = [p for p in parlamentares_ordem if p not in parlamentares_mesa]
ementa = m.materia.ementa
titulo = m.materia
numero = m.numero_ordem
tramitacao = m.materia.tramitacao_set.last()
turno = None
context = {}
if tramitacao:
turno = get_turno(tramitacao.turno)
config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata
if config_assinatura_ata == 'T' and parlamentares_ordem:
context.update(
{'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'})
context.update({'assinatura_mesa': mesa_dia,
'assinatura_presentes': parlamentares_ordem})
elif config_assinatura_ata == 'M' and mesa_dia:
context.update(
{'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'})
context.update({'assinatura_mesa': mesa_dia})
elif config_assinatura_ata == 'P' and presidente_dia:
context.update(
{'texto_assinatura': 'Assinatura do Presidente da Sessão'})
context.update({'assinatura_mesa': presidente_dia})
rv = m.registrovotacao_set.first()
rp = m.retiradapauta_set.filter(materia=m.materia).first()
if rv:
resultado = rv.tipo_resultado_votacao.nome
resultado_observacao = rv.observacao
elif rp:
resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao
return context
def get_materias_ordem_do_dia(sessao_plenaria):
ordem = OrdemDia.objects.filter(sessao_plenaria_id=sessao_plenaria.id)
materias_ordem = []
for o in ordem:
ementa = o.materia.ementa
ementa_observacao = o.observacao
titulo = o.materia
numero = o.numero_ordem
tramitacao = o.materia.tramitacao_set.last()
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
# Verificar resultado
rv = o.registrovotacao_set.filter(materia=o.materia).first()
rp = o.retiradapauta_set.filter(materia=o.materia).first()
if rv:
resultado = rv.tipo_resultado_votacao.nome
resultado_observacao = rv.observacao
elif rp:
resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao
else:
resultado = _('Matéria não votada')
resultado_observacao = _(' ')
voto_sim = ""
voto_nao = ""
voto_abstencoes = ""
voto_nominal = []
if o.tipo_votacao == 2:
votos = VotoParlamentar.objects.filter(ordem=o.id)
for voto in votos:
aux_voto = (voto.parlamentar.nome_completo, voto.voto)
voto_nominal.append(aux_voto)
try:
voto = RegistroVotacao.objects.filter(ordem=o.id).last()
voto_sim = voto.numero_votos_sim
voto_nao = voto.numero_votos_nao
voto_abstencoes = voto.numero_abstencoes
except AttributeError:
voto_sim = " Não Informado"
voto_nao = " Não Informado"
voto_abstencoes = " Não Informado"
autoria = Autoria.objects.filter(
materia_id=o.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa,
'ementa_observacao': ementa_observacao,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': o.materia.numero_protocolo,
'numero_processo': o.materia.numeracao_set.last(),
'tipo_votacao': o.TIPO_VOTACAO_CHOICES[o.tipo_votacao],
'voto_sim': voto_sim,
'voto_nao': voto_nao,
'voto_abstencoes': voto_abstencoes,
'voto_nominal': voto_nominal,
}
materias_ordem.append(mat)
context = {'materias_ordem': materias_ordem}
return context
def get_oradores_explicações_pessoais(sessao_plenaria):
oradores_explicacoes = []
for orador in Orador.objects.filter(
sessao_plenaria_id=sessao_plenaria.id).order_by('numero_ordem'):
for parlamentar in Parlamentar.objects.filter(
id=orador.parlamentar.id):
partido_sigla = Filiacao.objects.filter(
parlamentar=parlamentar).last()
if not partido_sigla:
sigla = ''
else:
resultado = _('Matéria não votada')
resultado_observacao = _(' ')
sigla = partido_sigla.partido.sigla
oradores = {
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': sigla
}
oradores_explicacoes.append(oradores)
context = {'oradores_explicacoes': oradores_explicacoes}
return context
autoria = Autoria.objects.filter(materia_id=m.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': m.materia.numero_protocolo,
'numero_processo': m.materia.numeracao_set.last(),
'observacao': m.observacao
}
materias_expediente.append(mat)
def get_ocorrencias_da_sessão(sessao_plenaria):
ocorrencias_sessao = OcorrenciaSessao.objects.filter(
sessao_plenaria_id=sessao_plenaria.id)
context = {'ocorrencias_da_sessao': ocorrencias_sessao}
return context
class ResumoView(DetailView):
template_name = 'sessao/resumo.html'
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get_context(self, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
context.update({'materia_expediente': materias_expediente})
# Votos de Votação Nominal de Matérias Expediente
materias_expediente_votacao_nominal = ExpedienteMateria.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia')
votacoes = []
for mevn in materias_expediente_votacao_nominal:
for mevn in materias_expediente_votacao_nominal:
votos_materia = []
titulo_materia = mevn.materia
registro = RegistroVotacao.objects.filter(expediente=mevn)
if registro:
if registro:
for vp in VotoParlamentar.objects.filter(votacao=registro).order_by('parlamentar'):
votos_materia.append(vp)
dados_votacao = {
'titulo': titulo_materia,
'votos': votos_materia
}
}
votacoes.append(dados_votacao)
context.update({'votos_nominais_materia_expediente': votacoes})
# =====================================================================
# Identificação Básica
context.update(get_identificação_basica(self.object))
# =====================================================================
# Conteúdo Multimídia
context.update(get_conteudo_multimidia(self.object))
# =====================================================================
# Mesa Diretora
context.update(get_mesa_diretora(self.object))
# =====================================================================
# Presença Sessão
context.update(get_presenca_sessao(self.object))
# =====================================================================
# Expedientes
context.update(get_expedientes(self.object))
# =====================================================================
# Matérias Expediente
context.update(get_materias_expediente(self.object))
# =====================================================================
# Oradores Expediente
oradores = []
for orador in OradorExpediente.objects.filter(
sessao_plenaria_id=self.object.id).order_by('numero_ordem'):
numero_ordem = orador.numero_ordem
url_discurso = orador.url_discurso
observacao = orador.observacao
parlamentar = Parlamentar.objects.get(
id=orador.parlamentar_id)
ora = {'numero_ordem': numero_ordem,
'url_discurso': url_discurso,
'parlamentar': parlamentar,
'observacao': observacao
}
oradores.append(ora)
context.update({'oradores': oradores})
context.update(get_oradores_expediente(self.object))
# =====================================================================
# Presença Ordem do Dia
presencas = PresencaOrdemDia.objects.filter(
sessao_plenaria_id=self.object.id
).order_by('parlamentar__nome_parlamentar')
parlamentares_mesa_dia = [m['parlamentar'] for m in context['mesa']]
# composicao_mesa = ComposicaoMesa.objects.filter(sessao_legislativa=sessao)
presidente_dia = ''
for m in context['mesa']:
if m['cargo'].descricao == 'Presidente':
presidente_dia = [m['parlamentar']]
break
parlamentares_ordem = [p.parlamentar for p in presencas]
context.update({'presenca_ordem': parlamentares_ordem})
config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata
if config_assinatura_ata == 'T' and parlamentares_ordem:
context.update(
{'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'})
context.update({'assinatura_presentes': parlamentares_ordem})
elif config_assinatura_ata == 'M' and parlamentares_mesa_dia:
context.update(
{'texto_assinatura': 'Assinatura da Mesa Diretora da Sessão'})
context.update({'assinatura_presentes': parlamentares_mesa_dia})
elif config_assinatura_ata == 'P' and presidente_dia:
context.update(
{'texto_assinatura': 'Assinatura do Presidente da Sessão'})
context.update({'assinatura_presentes': presidente_dia})
context.update(get_presenca_ordem_do_dia(self.object))
# =====================================================================
# Assinaturas
context.update(get_assinaturas(self.object))
# =====================================================================
# Matérias Ordem do Dia
ordem = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id)
materias_ordem = []
for o in ordem:
ementa = o.materia.ementa
ementa_observacao = o.observacao
titulo = o.materia
numero = o.numero_ordem
tramitacao = o.materia.tramitacao_set.last()
turno = None
if tramitacao:
turno = get_turno(tramitacao.turno)
# Verificar resultado
rv = o.registrovotacao_set.filter(materia=o.materia).first()
rp = o.retiradapauta_set.filter(materia=o.materia).first()
if rv:
resultado = rv.tipo_resultado_votacao.nome
resultado_observacao = rv.observacao
elif rp:
resultado = rp.tipo_de_retirada.descricao
resultado_observacao = rp.observacao
else:
resultado = _('Matéria não votada')
resultado_observacao = _(' ')
autoria = Autoria.objects.filter(
materia_id=o.materia_id)
autor = [str(x.autor) for x in autoria]
mat = {'ementa': ementa,
'ementa_observacao': ementa_observacao,
'titulo': titulo,
'numero': numero,
'turno': turno,
'resultado': resultado,
'resultado_observacao': resultado_observacao,
'autor': autor,
'numero_protocolo': o.materia.numero_protocolo,
'numero_processo': o.materia.numeracao_set.last()
}
materias_ordem.append(mat)
context.update({'materias_ordem': materias_ordem})
# Votos de Votação Nominal de Matérias Ordem do Dia
materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id,
@ -1553,7 +1648,6 @@ class ResumoView(DetailView):
votacoes_od = []
for modvn in materias_ordem_dia_votacao_nominal:
votos_materia_od = []
t_materia = modvn.materia
registro_od = RegistroVotacao.objects.filter(ordem=modvn)
@ -1566,37 +1660,16 @@ class ResumoView(DetailView):
'votos': votos_materia_od
}
votacoes_od.append(dados_votacao_od)
context.update({'votos_nominais_materia_ordem_dia': votacoes_od})
context.update(get_materias_ordem_do_dia(self.object))
# =====================================================================
# Oradores nas Explicações Pessoais
oradores_explicacoes = []
for orador in Orador.objects.filter(
sessao_plenaria_id=self.object.id).order_by('numero_ordem'):
for parlamentar in Parlamentar.objects.filter(
id=orador.parlamentar.id):
partido_sigla = Filiacao.objects.filter(
parlamentar=parlamentar).last()
if not partido_sigla:
sigla = ''
else:
sigla = partido_sigla.partido.sigla
oradores = {
'numero_ordem': orador.numero_ordem,
'parlamentar': parlamentar,
'sgl_partido': sigla
}
oradores_explicacoes.append(oradores)
context.update({'oradores_explicacoes': oradores_explicacoes})
context.update(get_oradores_explicações_pessoais(self.object))
# =====================================================================
# Ocorrẽncias da Sessão
ocorrencias_sessao = OcorrenciaSessao.objects.filter(
sessao_plenaria_id=self.object.id)
context.update({'ocorrencias_da_sessao': ocorrencias_sessao})
context.update(get_ocorrencias_da_sessão(self.object))
# =====================================================================
# Indica a ordem com a qual o template será renderizado
ordenacao = ResumoOrdenacao.objects.first()
@ -1620,36 +1693,36 @@ class ResumoView(DetailView):
try:
context.update(
{'primeiro_ordenacao': dict_ord_template[ordenacao.primeiro],
'segundo_ordenacao': dict_ord_template[ordenacao.segundo],
'terceiro_ordenacao': dict_ord_template[ordenacao.terceiro],
'quarto_ordenacao': dict_ord_template[ordenacao.quarto],
'quinto_ordenacao': dict_ord_template[ordenacao.quinto],
'sexto_ordenacao': dict_ord_template[ordenacao.sexto],
'setimo_ordenacao': dict_ord_template[ordenacao.setimo],
'oitavo_ordenacao': dict_ord_template[ordenacao.oitavo],
'nono_ordenacao': dict_ord_template[ordenacao.nono],
'decimo_ordenacao': dict_ord_template[ordenacao.decimo],
'decimo_primeiro_ordenacao': dict_ord_template[ordenacao.decimo_primeiro],
'decimo_segundo_ordenacao': dict_ord_template[ordenacao.decimo_segundo],
'decimo_terceiro_ordenacao': dict_ord_template[ordenacao.decimo_terceiro]})
'segundo_ordenacao': dict_ord_template[ordenacao.segundo],
'terceiro_ordenacao': dict_ord_template[ordenacao.terceiro],
'quarto_ordenacao': dict_ord_template[ordenacao.quarto],
'quinto_ordenacao': dict_ord_template[ordenacao.quinto],
'sexto_ordenacao': dict_ord_template[ordenacao.sexto],
'setimo_ordenacao': dict_ord_template[ordenacao.setimo],
'oitavo_ordenacao': dict_ord_template[ordenacao.oitavo],
'nono_ordenacao': dict_ord_template[ordenacao.nono],
'decimo_ordenacao': dict_ord_template[ordenacao.decimo],
'decimo_primeiro_ordenacao': dict_ord_template[ordenacao.decimo_primeiro],
'decimo_segundo_ordenacao': dict_ord_template[ordenacao.decimo_segundo],
'decimo_terceiro_ordenacao': dict_ord_template[ordenacao.decimo_terceiro]})
except KeyError as e:
self.logger.error('user=' + request.user.username + '. ' + "KeyError: " + str(e) + ". Erro "
self.logger.error('user=' + self.request.user.username + '. ' + "KeyError: " + str(e) + ". Erro "
"ao tentar utilizar configuração de ordenação. Utilizando ordenação padrão.")
context.update(
{'primeiro_ordenacao': dict_ord_template['id_basica'],
'segundo_ordenacao': dict_ord_template['cont_mult'],
'terceiro_ordenacao': dict_ord_template['mesa_d'],
'quarto_ordenacao': dict_ord_template['lista_p'],
'quinto_ordenacao': dict_ord_template['exp'],
'sexto_ordenacao': dict_ord_template['mat_exp'],
'setimo_ordenacao': dict_ord_template['v_n_mat_exp'],
'oitavo_ordenacao': dict_ord_template['oradores_exped'],
'nono_ordenacao': dict_ord_template['lista_p_o_d'],
'decimo_ordenacao': dict_ord_template['mat_o_d'],
'decimo_primeiro_ordenacao': dict_ord_template['v_n_mat_o_d'],
'decimo_segundo_ordenacao': dict_ord_template['oradores_expli'],
'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao']
})
{'primeiro_ordenacao': dict_ord_template['id_basica'],
'segundo_ordenacao': dict_ord_template['cont_mult'],
'terceiro_ordenacao': dict_ord_template['mesa_d'],
'quarto_ordenacao': dict_ord_template['lista_p'],
'quinto_ordenacao': dict_ord_template['exp'],
'sexto_ordenacao': dict_ord_template['mat_exp'],
'setimo_ordenacao': dict_ord_template['v_n_mat_exp'],
'oitavo_ordenacao': dict_ord_template['oradores_exped'],
'nono_ordenacao': dict_ord_template['lista_p_o_d'],
'decimo_ordenacao': dict_ord_template['mat_o_d'],
'decimo_primeiro_ordenacao': dict_ord_template['v_n_mat_o_d'],
'decimo_segundo_ordenacao': dict_ord_template['oradores_expli'],
'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao']
})
else:
context.update(
{'primeiro_ordenacao': dict_ord_template['id_basica'],
@ -1667,6 +1740,10 @@ class ResumoView(DetailView):
'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao']
})
return context
def get(self, request, *args, **kwargs):
context = self.get_context()
return self.render_to_response(context)
@ -1772,6 +1849,12 @@ class OcorrenciaSessaoView(FormMixin, DetailView):
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = 'Ocorrências da Sessão <small>(%s)</small>' % (
self.object)
return context
def delete(self):
OcorrenciaSessao.objects.filter(sessao_plenaria=self.object).delete()
@ -3000,7 +3083,7 @@ class PesquisarSessaoPlenariaView(FilterView):
# Então a ordem da URL está diferente
data = self.filterset.data
if data and data.get('data_inicio__year') is not None:
url = "&" + str(self.request.environ['QUERY_STRING'])
url = "&" + str(self.request.META['QUERY_STRING'])
if url.startswith("&page"):
ponto_comeco = url.find('data_inicio__year=') - 1
url = url[ponto_comeco:]
@ -3081,6 +3164,7 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
self).get_context_data(**kwargs)
context['title'] = _('Pesquisar Matéria Legislativa')
context['root_pk'] = self.kwargs['pk']
self.filterset.form.fields['o'].label = _('Ordenação')
@ -3414,7 +3498,7 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
'origem': request.POST['origem'],
'subnav_template_name': 'sessao/subnav.yaml'
}
if 'marcadas_1' in request.POST:
context.update({'resultado_votacao': TipoResultadoVotacao.objects.all(),

7
sapl/settings.py

@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next='
SAPL_VERSION = '3.1.147'
SAPL_VERSION = '3.1.150'
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@ -95,7 +95,6 @@ INSTALLED_APPS = (
'reversion_compare',
'haystack',
'whoosh',
'speedinfo',
'webpack_loader',
@ -106,8 +105,8 @@ INSTALLED_APPS = (
# Desabilita a indexação textual até encontramos uma solução para a issue
# https://github.com/interlegis/sapl/issues/2055
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.BaseSignalProcessor' # Disable auto index
SEARCH_BACKEND = 'haystack.backends.whoosh_backend.WhooshEngine'
SEARCH_URL = ('PATH', PROJECT_DIR.child('whoosh'))
SEARCH_BACKEND = ''
SEARCH_URL = ['','']
# SOLR
USE_SOLR = config('USE_SOLR', cast=bool, default=False)

62
sapl/static/sapl/css/header-relatorio.css

@ -0,0 +1,62 @@
html body p {
border-top: 1px solid black;
text-align: center;
font-size: 11pt;
padding: 5px;
margin-top: -15px;
}
html body section {
box-sizing: border-box;
}
html body section dl {
display: flex;
flex-wrap: wrap;
rows: 2;
columns: 2;
}
html body section dt{
width: 50px;
}
html body section dd {
max-width:550px;
text-align: center;
}
html body section dd ul li {
list-style-type: none;
margin-left: 90px;
margin-bottom: -15px;
}
h2 {
font-size: 14pt;
}
h3 {
font-size: 10pt;
color: #6e6e6e;
}
ul {
padding: 0;
list-style: none;
margin-top:10px;
}
html body section dt img {
max-width:80px;
margin-left: 20px;
margin-left: 50px;
}
h3 {
font-size: 10pt;
color: #6e6e6e;
}
ul {
padding: 0;
list-style: none;
margin-top:10px;
}
html body section dt img {
max-width:80px;
margin-left: 20px;
}

56
sapl/static/sapl/css/relatorio.css

@ -0,0 +1,56 @@
@page{
margin-top: 4.5cm;
size: A4 portrait;
}
h2.gray-title{
color: gray;
font-size: 14pt;
break-after: avoid-page;
page-break-after: avoid;
}
h3 {
font-size: 10pt;
break-after: avoid-page;
page-break-after: avoid;
}
p {
font-size: 10pt;
text-align: justify;
text-justify: inter-word;
}
fieldset {
border: 0;
}
html body section {
box-sizing: border-box;
}
html body section dl {
display: flex;
flex-wrap: wrap;
columns: 5;
}
html body section dt{
width: 50px;
}
html body section dd {
text-align: center;
}
html body section dd ul li {
list-style-type: none;
margin-left: 50px;
}
fieldset {
page-break-after: avoid;
margin:5px;
padding:0px;
}

2
sapl/templates/base.html

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

67
sapl/templates/comissoes/composicao_list.html

@ -1,46 +1,45 @@
{% extends "crud/list.html" %}
{% load i18n common_tags crispy_forms_tags%}
{% block base_content %}
{% block actions %}
{% if user.is_authenticated and perms.comissoes.add_composicao %}
<div class="context-actions clearfix">
{% block actions %}
<div class="actions btn-group float-right btn-group-lg" role="group">
{% if view.create_url %}
<a href="{{ view.create_url }}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
{% endif %}
{% block more_buttons %}{% endblock more_buttons %}
</div>
{% endblock actions %}
</div>
<div class="actions btn-group float-right btn-group-lg" role="group">
{% if view.create_url %}
<a href="{{ view.create_url }}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
{% endif %}
{% block more_buttons %}{% endblock more_buttons %}
</div>
{% endif %}
{% endblock actions %}
<fieldset class="form-group">
<legend>Selecione o Período</legend>
<form method="GET">
<select name="pk" class="form-control" onChange="form.submit();">
{% for c in composicao_list %}
<option value="{{c.id}}" {% if composicao_pk == c.id %} selected {% endif %}>
{{c}}
</option>
{% endfor %}
</select>
</form>
</fieldset>
{% block extra_content %}
<form method="GET">
<fieldset class="form-group">
<legend>Selecione o Período</legend>
<select name="pk" class="form-control" onChange="form.submit();">
{% for c in composicao_list %}
<option value="{{c.id}}" {% if composicao_pk == c.id %} selected {% endif %}>
{{c}}
</option>
{% endfor %}
</select>
</fieldset>
</form>
<br/>
{% endblock %}
{% block container_table_list %}
{% if user.is_authenticated and perms.comissoes.add_participacao %}
<div class="actions btn-group mb-2" role="group">
<a href="{% url 'sapl.comissoes:participacao_create' composicao_pk %}" class="btn btn-outline-primary">
Adicionar Participação em Comissão
</a>
<div class="context-actions clearfix">
<div class="actions btn-group mb-2" role="group">
<a href="{% url 'sapl.comissoes:participacao_create' composicao_pk %}" class="btn btn-outline-primary">
Adicionar Participação em Comissão
</a>
</div>
</div>
{% endif %}
<div class="clearfix"></div>
<div class="container-table">
<table class="table table-striped table-hover table-link-ordering">
<thead>
@ -71,4 +70,4 @@
</tbody>
</table>
</div>
{% endblock base_content %}
{% endblock %}

2
sapl/templates/comissoes/materias_em_tramitacao.html

@ -12,7 +12,7 @@
{% block detail_content %}
<fieldset>
<legend>{{comissao}}</legend>
<b>Há {{page_obj|length}} matéria(s) em tramitação nesta unidade.</b> <br><br>
<b>Há {{qtde}} matéria(s) em tramitação nesta unidade.</b> <br><br>
{% for materia in page_obj %}
<b><a href="{% url 'sapl.materia:materialegislativa_detail' materia.id %}">
{{materia.tipo.sigla}} {{materia.numero}} {{materia.ano}} - {{materia.tipo}}

1
sapl/templates/compilacao/layouts.yaml

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

3
sapl/templates/compilacao/text_list.html

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

9
sapl/templates/crud/list.html

@ -5,17 +5,18 @@
<div class="context-actions clearfix">
<div class="actions search float-left">
<div class="actions search">
{% if form %}
{% crispy form %}
{% endif %}
</div>
{% block actions %}
<div class="actions btn-group float-right btn-group-lg" role="group">
{% if view.create_url %}
<a href="{{ view.create_url }}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
<a href="{{ view.create_url }}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
{% endif %}
{% block more_buttons %}{% endblock more_buttons %}
</div>

15
sapl/templates/materia/em_lote/acessorio.html

@ -79,7 +79,7 @@
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(event)" /> Marcar/Desmarcar Todos
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
</div>
@ -109,11 +109,12 @@
{% endblock detail_content %}
{% block extra_js %}
<script language="JavaScript">
function checkAll(event) {
$('[name=materia_id]').each(function() {
$(this).prop('checked', event.target.checked ? 'checked': null);
$(this).trigger('click');
});
}
function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
</script>
{% endblock %}

15
sapl/templates/materia/em_lote/anexada.html

@ -45,7 +45,7 @@
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(event)" /> Marcar/Desmarcar Todos
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
</div>
@ -73,11 +73,12 @@
{% endblock detail_content %}
{% block extra_js %}
<script language="JavaScript">
function checkAll(event) {
$('[name=materia_id]').each(function() {
$(this).prop('checked', event.target.checked ? 'checked': null);
$(this).trigger('click');
});
}
function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
</script>
{% endblock %}

15
sapl/templates/materia/em_lote/tramitacao.html

@ -96,7 +96,7 @@
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(event)" /> Marcar/Desmarcar Todos
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
</div>
@ -127,12 +127,13 @@
{% endblock detail_content %}
{% block extra_js %}
<script language="JavaScript">
function checkAll(event) {
$('[name=materia_id]').each(function() {
$(this).prop('checked', event.target.checked ? 'checked': null);
$(this).trigger('click');
});
}
function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
$(document).ready(function(){
var primeira_tramitacao = {{primeira_tramitacao|yesno:"true,false"}}

7
sapl/templates/materia/impressos/ficha.html

@ -1,7 +0,0 @@
{% extends "crud/form.html" %}
{% load i18n crispy_forms_tags %}
{% block base_content %}
<h1 class="page-header">Impressos</h1>
{% crispy form %}
{% endblock base_content %}

6
sapl/templates/materia/impressos/ficha_seleciona.html

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

66
sapl/templates/materia/impressos/impressos.html

@ -1,45 +1,29 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block actions %}
{% endblock %}
{% block detail_content %}
<h1 class="page-header">Impressos</h1>
</br>
<h2 class="legend">Etiqueta</h2>
<ul>
<li><a href="{% url 'sapl.materia:impressos_etiqueta' %}">Pesquisar</a></li>
</ul>
</br>
<h2 class="legend">Capa Processo</h2>
<ul>
<li><a href="{% url 'sapl.materia:impressos_ficha_pesquisa' %}">Pesquisar</a></li>
</ul>
</br>
<h2 class="legend">Índice de Normas Jurídicas</h2>
<ul>
<li><a href="{% url 'sapl.materia:impressos_norma_pesquisa' %}">Pesquisar</a></li>
</ul>
</br>
<h2 class="legend">Capa Documento Administrativo</h2>
<ul>
<li><a href="{% url 'sapl.materia:impressos_ficha_pesquisa_adm' %}">Pesquisar</a></li>
</ul>
{#<h2 class="legend">Guia de Remessa</h2>#}
{# <ul>#}
{# <li><a href="{% url 'sapl.materia:impressos_guiaremessa' %}">Pesquisar</a></li>#}
{# </ul>#}
{##}
{#<h2 class="legend">Espelho</h2>#}
{# <ul>#}
{# <li><a href="{% url 'sapl.materia:impressos_espelho' %}">Pesquisar</a></li>#}
{# </ul>#}
<div class="container-table">
<h1 class="page-header">Impressos</h1>
<table class="table table-striped table-hover table-link-ordering">
<tr>
<th>Capa Documento Administrativo</th>
<td><a href="{% url 'sapl.materia:impressos_ficha_pesquisa_adm' %}">Pesquisar</a></td>
</tr>
<tr>
<th>Capa Processo</th>
<td><a href="{% url 'sapl.materia:impressos_ficha_pesquisa' %}">Pesquisar</a></td>
</tr>
<tr>
<th>Etiqueta</th>
<td><a href="{% url 'sapl.materia:impressos_etiqueta' %}">Pesquisar</a></td>
</tr>
<tr>
<th>Índice de Matérias Legislativas</th>
<td><a href="{% url 'sapl.materia:impressos_materia_pesquisa' %}">Pesquisar</a></td>
</tr>
<tr>
<th>Índice de Normas Jurídicas</th>
<td><a href="{% url 'sapl.materia:impressos_norma_pesquisa' %}">Pesquisar</a></td>
</tr>
</table>
</div>
{% endblock %}

0
sapl/templates/materia/impressos/etiqueta.html → sapl/templates/materia/impressos/impressos_form.html

67
sapl/templates/materia/impressos/materias_pdf.html

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<title>Impressos</title>
<meta charset="utf-8">
</head>
<body id="corpo">
{% if titulo %}
<div id="titulo">
<strong class="text_pdf">{{ titulo }}</strong>
</div>
{% endif %}
{% if quantidade > 2000 %}
<div>
<p class="alert_message"><b>Sua pesquisa retornou mais do que 2000 impressos.<br>
Por questões de performance, foram retornados apenas os primeiros 2000 resultados.</b></p>
</div>
{% endif %}
<table>
<thead>
<tr>
<th>Tipo, Número e Data</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for materia in materias %}
<tr>
<td id="tipo_numero_data">
<span class="text_pdf">{{ materia.tipo }} nº {{ materia.numero }}, de {{ materia.ano }}</span>
</td>
<td id="ementa">
<span class="text_pdf">{{ materia.ementa }}</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
<style type="text/css">
.text_pdf {
font-family: arial;
font-size: 70%;
}
#titulo {
font-size: xx-large;
text-align: center;
vertical-align:top;
}
#corpo {
margin-left:10px;
margin-right:-50px;
margin-top: -50px;
text-align: justify;
}
#tipo_numero_data {
width:200px;
vertical-align:top;
}
#ementa {
width:440px;
vertical-align:top;
}
</style>
</html>

7
sapl/templates/materia/impressos/norma.html

@ -1,7 +0,0 @@
{% extends "crud/form.html" %}
{% load i18n crispy_forms_tags %}
{% block base_content %}
<h1 class="page-header">Impressos</h1>
{% crispy form %}
{% endblock base_content %}

111
sapl/templates/materia/impressos/normas_pdf.html

@ -1,52 +1,67 @@
<!DOCTYPE html>
<html>
<head>
<title>Impressos</title>
<meta charset="utf-8">
</head>
<body id="corpo">
{% if titulo %}
<div id="titulo">
<strong class="text_pdf">{{ titulo }}</strong>
</div>
{% endif %}
<head>
<title>Impressos</title>
<meta charset="utf-8">
</head>
{% if quantidade > 2000 %}
<div>
<p class="alert_message"><b>Sua pesquisa retornou mais do que 2000 impressos.<br>
Por questões de performance, foram retornados apenas os primeiros 2000 resultados.</b></p>
</div>
{% endif %}
<style type="text/css">
.text_pdf{
font-family: arial;
font-size: 70%;
}
#titulo
{
font-size: xx-large;
text-align: center;
}
</style>
<body style="margin-left:10px;margin-right:-50px; margin-top: -50px; text-align: justify">
{% if quantidade > 2000 %}
<b><p class="alert_message">Sua pesquisa retornou mais do que 2000 impressos.</p><p class="alert_message">Por questões de performance, foram retornados apenas os 2000 primeiros.</p></b>
</br></br></br>
{% endif %}
<div id="titulo">
<td vertical-align:top;"><strong class="text_pdf">{{titulo}}</strong></td>
</div>
</br>
{% for m in normas %}
<table>
<tr>
<td style="width:200px; vertical-align:top;"><span class="text_pdf"> {{m.tipo}} nº </span><span class="text_pdf"> {{m.numero}}, de {{m.data|date:"d/m/Y" }} </span>
</td>
<td>
</td>
<td style="width:440px; vertical-align:top;"><span class="text_pdf">{{m.ementa}}</span>
</td>
</tr>
</table>
</br>
{% endfor %}
</body>
<table>
<thead>
<tr>
<th>Tipo, Número e Data</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for norma in normas %}
<tr>
<td id="tipo_numero_data">
<span class="text_pdf">{{ norma.tipo }} nº {{ norma.numero }}, de {{ norma.data|date:"d/m/Y" }}</span>
</td>
<td id="ementa">
<span class="text_pdf">{{ norma.ementa }}</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
<style type="text/css">
.text_pdf {
font-family: arial;
font-size: 70%;
}
#titulo {
font-size: xx-large;
text-align: center;
vertical-align:top;
}
#corpo {
margin-left:10px;
margin-right:-50px;
margin-top: -50px;
text-align: justify;
}
#tipo_numero_data {
width:200px;
vertical-align:top;
}
#ementa {
width:440px;
vertical-align:top;
}
</style>
</html>

6
sapl/templates/materia/layouts.yaml

@ -3,9 +3,13 @@ Origem:
{% trans 'Origem' %}:
- nome:8 sigla
TipoMateriaLegislativaDetail:
{% trans 'Tipo Matéria Legislativa' %}:
- sigla:2 descricao sequencia_numeracao:2 sequencia_regimental:2
TipoMateriaLegislativa:
{% trans 'Tipo Matéria Legislativa' %}:
- sigla:4 descricao sequencia_numeracao
- sigla:2 descricao sequencia_numeracao:3
RegimeTramitacao:
{% trans 'Tipo de Documento' %}:

55
sapl/templates/materia/tipomaterialegislativa_list.html

@ -0,0 +1,55 @@
{% extends "crud/list_tabaux.html" %}
{% load i18n %}
{% load common_tags %}
{% block container_table_list %}
<div style="cursor: all-scroll">
{{ block.super }}
</div>
{% endblock %}
{% block extra_js %}
<script type="text/javascript">
$('tbody').sortable({
revert: false,
distance: 15,
start: function(event, ui) {
ui.item.startPos = ui.item.index();
},
stop: function(event, ui) {
var pos_ini = ui.item.startPos + 1;
var pos_fim = ui.item.index() + 1;
var pk = ui.item.find('a[pk]').attr('pk');
var url = "{% url 'sapl.api:tipomaterialegislativa-change-position' 0 %}";
url = url.replace('0', pk) ;
$.ajax({
url: url,
type: 'POST',
contentType: "application/json",
data: JSON.stringify({
"pos_ini": pos_ini,
"pos_fim": pos_fim,
}),
headers: {
'X-CSRFToken': getCookie('csrftoken')
},
error: function(e) {
console.log(e);
}
});
setTimeout(function(){ window.location.reload(true) }, 500);
}
});
$(window).on('beforeunload', function () {
$('tbody').sortable('disable');
$("input[type=submit], input[type=button]").prop("disabled", "disabled");
});
</script>
{% endblock %}

8
sapl/templates/protocoloadm/MateriaTemplate.html

@ -3,17 +3,17 @@
{% block base_content %}
<div class="alert alert-success alert-dismissible " role="alert">
<p align="center"><b><font color="green">Matéria protocolada com sucesso!</font></b></p>
Matéria protocolada com sucesso!
</div>
<div align="center">
<div class="row" style="width:50%;">
<div class="row mb-3" style="width:50%;">
<div class="col-md-6">
<a onclick="window.open('{% url 'sapl.relatorios:relatorio_etiqueta_protocolo' protocolo.numero protocolo.ano %}','Comprovante','width=400, height=200')"class="btn btn-secondary">Imprimir Etiqueta</a>
<span onclick="window.open('{% url 'sapl.relatorios:relatorio_etiqueta_protocolo' protocolo.numero protocolo.ano %}','Comprovante','width=400, height=200')"class="btn btn-secondary">Imprimir Etiqueta</span>
</div>
<div class="col-md-6">
<a target="popup" class="btn btn-secondary" onclick="window.open('{% url 'sapl.protocoloadm:comprovante_protocolo' protocolo.pk %}','Comprovante','width=800, height=700')">Imprimir Comprovante</a>
<span target="popup" class="btn btn-secondary" onclick="window.open('{% url 'sapl.protocoloadm:comprovante_protocolo' protocolo.pk %}','Comprovante','width=800, height=700')">Imprimir Comprovante</span>
</div>
</div>

85
sapl/templates/protocoloadm/em_lote/anexado.html

@ -0,0 +1,85 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block actions %}
{% endblock %}
{% block detail_content %}
{% if not show_results %}
{% crispy filter.form %}
{% endif %}
{% if show_results %}
{% if numero_res > 0 %}
{% if numero_res == 1 %}
<h3 style="text-align: right;">{% trans 'Pesquisa concluída com sucesso! Foi encontrado 1 documento.' %}</h3>
{% else %}
<h3 style="text-align: right;">Foram encontrados {{ numero_res }} documentos.</h3>
{% endif %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>Data Anexação*</label>
<input type="text" name="data_anexacao" class="form-control dateinput" required="True">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>Data Desanexação</label>
<input type="text" name="data_desanexacao" class="form-control dateinput">
</div>
</div>
</div>
</fieldset>
<br/>
<fieldset>
<legend>Documentos para Anexar em Lote</legend>
<table class="table table-striped table-hover">
<div class="controls">
<div class="checkbox">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)"/>Marcar/Desmarcar Todos
</label>
</div>
</div>
<thead>
<tr>
<th>Documento</th>
</tr>
</thead>
<tbody>
{% for documento in object_list %}
<tr>
<td>
<input type="checkbox" name="documento_id" value="{{documento.id}}" {% if check %} checked {% endif %}/>
{{documento.tipo.sigla}} {{documento.numero}}/{{documento.ano}} - {{documento.tipo.descricao}}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
<input type="submit" value="Salvar" class="btn btn-primary"S>
</form>
{% else %}
<tr>
<td>
<h3 style="text-align: right;">Nenhum documento encontrado.</h3>
</td>
</tr>
{% endif %}
{% endif %}
{% endblock detail_content %}
{% block extra_js %}
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
</script>
{% endblock %}

31
sapl/templates/relatorios/header_ata.html

@ -0,0 +1,31 @@
{% load common_tags %}
{% load render_bundle from webpack_loader %}
{% load webpack_static from webpack_loader %}
{% load static %}
<!DOCTYPE html>
<meta charset="utf-8">
</meta>
<html lang="pt-br">
<head>
<link rel="stylesheet" href="{% static 'sapl/css/header-relatorio.css'%}">
</head>
<body>
<section id="informations">
<dl>
<dt class="image-header">
<img src="{% if logotipo %}{{ MEDIA_URL }}{{ logotipo }}{% else %}{% webpack_static 'img/logo.png' %}{% endif %}">
</dt>
<dd class="title">
<ul>
<li style="margin-top:10px"><h2>{{casa.nome}}</h2></li>
<li><h3>Sistema de Apoio ao Processo Legislativo</h3></li>
</ul>
</dd>
</dl>
</section>
<p></p>
</body>
</html>

102
sapl/templates/relatorios/relatorio_ata.html

@ -0,0 +1,102 @@
{% load common_tags %}
{% load static %}
<head>
<style>
@page{
@bottom-right {
content: "Página" counter(page);
height: 3cm;
font-size: 8pt;
}
@bottom-center {
border-top: 1px solid black;
font-size: 8pt;
height: 1cm;
content: "{{rodape|safe}}";
font-style:italic;
}
@bottom-left {
content: "{{data}}";
height: 3cm;
font-size: 8pt;
}
@top-center {
content: string(title);
}
header {
width: 0;
height: 0;
visibility: hidden;
string-set: title content();
}
}
</style>
<link rel="stylesheet" href="{% static '/sapl/css/relatorio.css'%}">
</head>
<body>
<h3 style="text-align:center;">Extrato Eletrônico da {{sessaoplenaria}}</h3>
{% include 'sessao/blocos_ata/identificacao_basica.html' %}
{% include 'sessao/blocos_ata/mesa_diretora.html' %}
{% include 'sessao/blocos_ata/lista_presenca.html' %}
{% include 'sessao/blocos_ata/expedientes.html' %}
{% include 'sessao/blocos_ata/materias_expediente.html' %}
{% include 'sessao/blocos_ata/oradores_expediente.html' %}
{% include 'sessao/blocos_ata/lista_presenca_ordem_dia.html' %}
{% include 'sessao/blocos_ata/materias_ordem_dia.html' %}
{% include 'sessao/blocos_ata/oradores_explicacoes.html' %}
{% include 'sessao/blocos_ata/ocorrencias_da_sessao.html' %}
{% if assinatura_mesa or assinatura_presentes %}
<div style="page-break-before: always;padding:5px;margin-top:0px;border-top: 1px solid black;">
<legend >{{texto_assinatura}}</legend>
<table style="margin-top:80px">
<colgroup>
<col>
</colgroup>
<tbody>
{% for p in assinatura_mesa %}
{% if forloop.counter0|divisibleby:2 %}
<tr style="margin-top:20px">
<td>
<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>
</br></br></br>
</div>
{% else %}
<div style="float: left; position: relative; top: -50px; left: 142px; width: 120px; margin-right:-220px;">____________________ </br>
<p style="font-size:8pt"><b>{{p.cargo}}: </b> {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}</p>
</br></br></br>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
{% for p in assinatura_presentes %}
{% if forloop.counter0|divisibleby:2 %}
<tr style="margin-top:20px">
<td>
<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>
</br></br></br>
</div>
{% else %}
<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>
</br></br></br>
</div>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% endif%}
</div>
</body>

23
sapl/templates/sessao/adicionar_varias_materias_expediente.html

@ -3,24 +3,21 @@
{% load crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block sections_nav %}
{% endblock %}
{% block detail_content %}
{% block buttons %}
{% block buttons %}
{% if filter_url and not filter.form.errors %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:adicionar_varias_materias_expediente' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
{% if filter_url and not filter.form.errors %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:adicionar_varias_materias_expediente' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:expedientemateria_list' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Matérias do Expediente' %}</a>
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:expedientemateria_list' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Matérias do Expediente' %}</a>
</div>
{% endif %}
{% endif %}
{% endblock %}
{% endblock %}
{% if filter.form.errors %}
{% crispy filter.form %}

18
sapl/templates/sessao/adicionar_varias_materias_ordem.html

@ -4,16 +4,16 @@
{% block buttons %}
{% if filter_url and not filter.form.errors %}
{% if filter_url and not filter.form.errors %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:adicionar_varias_materias_ordem_dia' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:adicionar_varias_materias_ordem_dia' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:ordemdia_list' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Matérias da Ordem do Dia' %}</a>
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.sessao:ordemdia_list' pk_sessao %}" class="btn btn-outline-primary">{% trans 'Matérias da Ordem do Dia' %}</a>
</div>
{% endif %}
{% endif %}
{% endblock %}
{% endblock %}

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

@ -1,15 +1,19 @@
{% load common_tags %}
</p>
</p>
<fieldset>
<legend>{{texto_assinatura}}</legend>
<div class="row">
</br></br>
{% for p in assinatura_presentes %}
{% for p in assinatura_mesa %}
<div class="col-md-6">___________________________________________ </br>
{{p.nome_parlamentar}} / {{ p|filiacao_data_filter:object.data_inicio }}
<b>{{p.cargo}}: </b> {{p.parlamentar.nome_completo}} / {{ p.parlamentar|filiacao_data_filter:object.data_inicio }}
</br></br></br>
</div>
{% endfor %}
{% for p in assinatura_presentes %}
<div class="col-md-6">___________________________________________ </br>
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
</br></br></br>
</div>
{% endfor %}
</div>
</fieldset>

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

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

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

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

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

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

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

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

8
sapl/templates/sessao/blocos_ata/ocorrencias_da_sessao.html

@ -1,8 +1,8 @@
<fieldset>
<p align="justify">
{% if object.ocorrenciasessao.conteudo %}
<strong>Ocorrências da Sessão: </strong>
{{object.ocorrenciasessao.conteudo|striptags|safe}}
<p align="justify">
{% if object.ocorrenciasessao.conteudo %}
<strong>Ocorrências da Sessão: </strong>
{{object.ocorrenciasessao.conteudo|striptags|safe}}
{% endif %}
</p>
</fieldset>

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

@ -3,7 +3,7 @@
{% if oradores %}
<strong>Oradores do Expediente: </strong>
{% for o in oradores %}
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar}}</div>
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}}</div>
<div>{{o.url_discurso}}</div>
<div>{{o.observacao}}</div>
</br>

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

@ -3,7 +3,7 @@
{% if oradores_explicacoes %}
<strong>Oradores das Explicações Pessoais: </strong>
{% for o in oradores_explicacoes %}
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_parlamentar}} / {{ o.parlamentar.filiacao_atual }} ;
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }} ;
{{o.url_discurso}}
{% endfor %}
{% endif %}

3
sapl/templates/sessao/ocorrencia_sessao.html

@ -4,9 +4,6 @@
{% load common_tags %}
{% block actions %}{% endblock %}
{% block title %}<font size="6" face="SourceSansProSemiBold" color="#364347" >Ocorrências da Sessão </font> <b><small><font face="SourceSansProSemiBold" size="5" color="#93a4aa"> ({{ object }}) </font> </small></b>{% endblock %}
{% block detail_content %}
{% if perms|get_add_perm:view %}
<form method="post" accept-charset="ISO-8859-1">

31
sapl/templates/sessao/painel.html

@ -26,11 +26,11 @@
<h2><span id="relogio"></span></h2>
<br />
<div class="row">
<div class="col-md-12"><h3>Cronômetro do Discurso</h3></div>
<div class="col-md-12 mb-2"><h3>Cronômetro do Discurso</h3></div>
</div>
<div class="row">
<div class="col-xs-2"><input size="2" id="discurso" name="discurso" value="" readyonly="true" class="form-control"></div>
<div class="col-md-2"><input size="2" id="discurso" name="discurso" value="" readyonly="true" class="form-control"></div>
</div>
<br />
@ -41,11 +41,11 @@
<br /><br >
<div class="row">
<div class="col-md-12"><h3>Cronômetro do Aparte</h3></div>
<div class="col-md-12 mb-2"><h3>Cronômetro do Aparte</h3></div>
</div>
<div class="row">
<div class="col-xs-2"><input size="2" id="aparte" name="aparte" value="" readyonly="true" class="form-control"></div>
<div class="col-md-2"><input size="2" id="aparte" name="aparte" value="" readyonly="true" class="form-control"></div>
</div>
<br />
@ -56,11 +56,11 @@
<br /><br >
<div class="row">
<div class="col-md-12"><h3>Cronômetro da Questão de Ordem </h3></div>
<div class="col-md-12 mb-2"><h3>Cronômetro da Questão de Ordem </h3></div>
</div>
<div class="row">
<div class="col-xs-2"><input size="2" id="ordem" name="ordem" value="" readyonly="true" class="form-control"></div>
<div class="col-md-2"><input size="2" id="ordem" name="ordem" value="" readyonly="true" class="form-control"></div>
</div>
<br />
@ -68,25 +68,28 @@
<div class="col-md-6"><button type="button" id="ordemStart" class="btn btn-success">Iniciar</button></div>
<div class="col-md-6"><button type="button" id="ordemReset" class="btn btn-success">Reiniciar</button></div>
</div>
<br/>
<br/>
<div class="row">
<div class="col-md-12"><h3>Cronômetro de Considerações Finais</h3></div>
<br/>
<br/>
<div class="row">
<div class="col-md-12 mb-2"><h3>Cronômetro de Considerações Finais</h3></div>
</div>
<div class="row">
<div class="col-xs-2"><input size="2" id="consideracoes" name="consideracoes" value="" readyonly="true" class="form-control"></div>
<div class="col-md-4"><input size="2" id="consideracoes" name="consideracoes" value="" readyonly="true" class="form-control"></div>
</div>
<br />
<br />
<div class="row">
<div class="col-md-6"><button type="button" id="consideracoesStart" class="btn btn-success">Iniciar</button></div>
<div class="col-md-6"><button type="button" id="consideracoesReset" class="btn btn-success">Reiniciar</button></div>
</div>
<br /><br >
<div class="row">
<div class="row">
<div class="col-md-6"><button type="button" id="sinalSonoro" class="btn btn-success" onclick="document.getElementById('audio').play();">Sinal Sonoro</button></div>
</div>
</div>
{% endblock detail_content %}

12
sapl/templates/sessao/resumo_ata.html

@ -6,7 +6,17 @@
<h1 class="page-header">
Extrato Eletrônico da {{sessaoplenaria}}
</h1>
{% endblock %}
<div>
<p align="right">
<strong>
<a href="{% url 'sapl.relatorios:resumo_ata_pdf' sessaoplenaria.pk %}">
Impressão PDF
</a>
</strong>
</p>
</div>
{% endblock title %}
{% block detail_content %}
{% include 'sessao/blocos_ata/'|add:primeiro_ordenacao %}

6
sapl/templates/sessao/sessaoplenaria_form.html

@ -13,10 +13,10 @@
var sessao = $("#id_sessao_legislativa").val()
if (tipo) {
$.get("/sessao/recuperar-numero-sessao",{tipo: tipo, sessao_legislativa:sessao},
$.get("{% url 'sapl.sessao:recuperar_numero_sessao_view' %}",{tipo: tipo, sessao_legislativa:sessao},
function(data, status) {
$("#id_numero").val(data.numero);
console.log(data)
// console.log(data)
});
}
else{
@ -35,7 +35,7 @@
var id_sessao_leg = $("#id_sessao_legislativa").val();
$("#id_sessao_legislativa option").remove();
if (id_legislatura) {
$.get("/sessao/sessao-legislativa-legislatura-ajax", {legislatura: id_legislatura}, function(data) {
$.get("{% url 'sapl.sessao:sessao_legislativa_legislatura_ajax_view' %}", {legislatura: id_legislatura}, function(data) {
lista_sessoes = data['sessao_legislativa'];
$('#id_sessao_legislativa').append('<option value="">' + '---------' + '</option>');

4
sapl/templates/sessao/subnav.yaml

@ -27,7 +27,7 @@
url: oradorexpediente_list
- title: {% trans 'Votação em Bloco' %}
url: votacao_bloco_expediente
check_permission: sessao.add_votacao
check_permission: sessao.add_sessaoplenaria
- title: {% trans 'Ordem do Dia' %}
children:
@ -37,7 +37,7 @@
url: presencaordemdia
- title: {% trans 'Votação em Bloco' %}
url: votacao_bloco_ordemdia
check_permission: sessao.add_votacao
check_permission: sessao.add_sessaoplenaria
- title: {% trans 'Painel Eletrônico' %}
url: painel

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

@ -110,35 +110,16 @@
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('marcadas_1');
if (elem.checked) {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = true;
}
}
} else {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = false;
}
}
}
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
checkboxes = document.getElementsByName('marcadas_2');
if (elem.checked) {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = true;
}
}
} else {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = false;
}
}
}
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
function alteraTipoVotacao() {

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

@ -110,35 +110,16 @@
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('marcadas_1');
if (elem.checked) {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = true;
}
}
} else {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = false;
}
}
}
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
checkboxes = document.getElementsByName('marcadas_2');
if (elem.checked) {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = true;
}
}
} else {
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = false;
}
}
}
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
function alteraTipoVotacao() {

7
setup.py

@ -20,7 +20,7 @@ install_requires = [
'django-extra-views==0.12.0',
'django-model-utils==3.1.2',
'django-reversion==3.0.2',
'django-reversion-compare==0.8.6'
'django-reversion-compare==0.8.6',
'django-speedinfo==1.4.0',
'django-extensions==2.1.4',
'django-image-cropping==1.2.0',
@ -36,17 +36,14 @@ install_requires = [
'unipath==1.1',
'WeasyPrint==44',
'gunicorn==19.9.0',
'textract==1.5.0',
'pysolr==3.6.0',
'whoosh==2.7.4',
# 'git+git://github.com/interlegis/trml2pdf.git',
# 'git+git://github.com/interlegis/django-admin-bootstrapped',
]
setup(
name='interlegis-sapl',
version='3.1.147',
version='3.1.150',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',

BIN
solr/sapl_configset/conf/saplconfigset.zip

Binary file not shown.

2
solr/sapl_configset/conf/schema.xml

@ -151,7 +151,7 @@
<field name="django_id" type="string" indexed="true" stored="true" multiValued="false"/>
<field name="_version_" type="plong" indexed="true" stored ="true"/>
<field name="text" type="text_pt" indexed="true" stored="true" multiValued="false" />
<field name="indextime" type="pdate" default="NOW" />
<field name="last_update" type="pdate" indexed="true" stored="true" default="NOW" />
</fields>

Loading…
Cancel
Save