Browse Source

Merge tag '3.1.157-RC5' into migracao

migracao
Marcio Mazza 6 years ago
parent
commit
559ba5a0c1
  1. 2
      docker-compose.yml
  2. 106
      release.sh
  3. 2
      requirements/requirements.txt
  4. 8
      sapl/api/views.py
  5. 88
      sapl/base/forms.py
  6. 25
      sapl/base/migrations/0037_auto_20190527_0901.py
  7. 8
      sapl/base/models.py
  8. 10
      sapl/base/urls.py
  9. 140
      sapl/base/views.py
  10. 8
      sapl/comissoes/forms.py
  11. 6
      sapl/comissoes/urls.py
  12. 161
      sapl/comissoes/views.py
  13. 101
      sapl/materia/forms.py
  14. 29
      sapl/materia/migrations/0049_pautareuniao.py
  15. 28
      sapl/materia/migrations/0050_auto_20190521_1148.py
  16. 40
      sapl/materia/models.py
  17. 152
      sapl/materia/tests/test_materia.py
  18. 112
      sapl/materia/views.py
  19. 4
      sapl/norma/forms.py
  20. 2
      sapl/norma/views.py
  21. 67
      sapl/parlamentares/migrations/0029_auto_20190517_1531.py
  22. 368
      sapl/protocoloadm/forms.py
  23. 521
      sapl/protocoloadm/tests/test_protocoloadm.py
  24. 10
      sapl/protocoloadm/urls.py
  25. 206
      sapl/protocoloadm/views.py
  26. 2
      sapl/relatorios/templates/pdf_pauta_sessao_gerar.py
  27. 422
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  28. 26
      sapl/relatorios/views.py
  29. 1
      sapl/rules/map_rules.py
  30. 67
      sapl/sessao/forms.py
  31. 23
      sapl/sessao/migrations/0040_auto_20190523_1130.py
  32. 3
      sapl/sessao/tests/test_sessao_view.py
  33. 147
      sapl/sessao/views.py
  34. 2
      sapl/settings.py
  35. 2
      sapl/static/sapl/css/relatorio.css
  36. 2
      sapl/static/sapl/frontend/css/global.d160bbe2.css
  37. BIN
      sapl/static/sapl/frontend/css/global.d160bbe2.css.gz
  38. 2
      sapl/static/sapl/frontend/js/compilacao.7625546b.js
  39. BIN
      sapl/static/sapl/frontend/js/compilacao.7625546b.js.gz
  40. 2
      sapl/static/sapl/frontend/js/global.522fd995.js
  41. BIN
      sapl/static/sapl/frontend/js/global.522fd995.js.gz
  42. BIN
      sapl/static/sapl/frontend/js/global.a87c35c2.js.gz
  43. 2
      sapl/templates/base.html
  44. 51
      sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html
  45. 48
      sapl/templates/base/RelatorioHistoricoTramitacaoAdm_filter.html
  46. 51
      sapl/templates/base/RelatorioHistoricoTramitacao_filter.html
  47. 3
      sapl/templates/base/layouts.yaml
  48. 8
      sapl/templates/base/relatorios_list.html
  49. 68
      sapl/templates/comissoes/pauta.html
  50. 65
      sapl/templates/comissoes/reuniao_detail.html
  51. 4
      sapl/templates/compilacao/subnav.html
  52. 36
      sapl/templates/materia/materia_detail.html
  53. 4
      sapl/templates/materia/tramitacao_detail.html
  54. 9
      sapl/templates/navbar.yaml
  55. 2
      sapl/templates/norma/subnav.yaml
  56. 39
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  57. 5
      sapl/templates/protocoloadm/em_lote/subnav_em_lote.yaml
  58. 46
      sapl/templates/protocoloadm/em_lote/tramitacaoadm.html
  59. 2
      sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html
  60. 85
      sapl/templates/relatorios/relatorio_doc_administrativos.html
  61. 25
      sapl/templates/search/search.html
  62. 8
      sapl/templates/sessao/blocos_ata/expedientes.html
  63. 2
      sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html
  64. 5
      sapl/templates/sessao/blocos_resumo/expedientes.html
  65. 5
      sapl/templates/sessao/blocos_resumo/identificacao_basica.html
  66. 63
      sapl/templates/sessao/blocos_resumo/lista_presenca.html
  67. 5
      sapl/templates/sessao/blocos_resumo/lista_presenca_ordem_dia.html
  68. 6
      sapl/templates/sessao/blocos_resumo/materias_expediente.html
  69. 5
      sapl/templates/sessao/blocos_resumo/materias_ordem_dia.html
  70. 5
      sapl/templates/sessao/blocos_resumo/mesa_diretora.html
  71. 5
      sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html
  72. 3
      sapl/templates/sessao/blocos_resumo/oradores_expediente.html
  73. 5
      sapl/templates/sessao/blocos_resumo/oradores_explicacoes.html
  74. 5
      sapl/templates/sessao/blocos_resumo/oradores_ordemdia.html
  75. 53
      sapl/templates/sessao/blocos_resumo/votos_nominais_materias_expediente.html
  76. 53
      sapl/templates/sessao/blocos_resumo/votos_nominais_materias_ordem_dia.html
  77. 5
      sapl/templates/sessao/pauta_sessao_filter.html
  78. 14
      sapl/templates/sessao/resumo.html
  79. 166
      sapl/templates/sessao/votacao/votacao_bloco.html
  80. 161
      sapl/templates/sessao/votacao/votacao_bloco_expediente.html
  81. 162
      sapl/templates/sessao/votacao/votacao_bloco_ordem.html
  82. 21
      sapl/utils.py
  83. 2
      sapl/webpack-stats.json
  84. 4
      setup.py

2
docker-compose.yml

@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
image: interlegis/sapl:3.1.156
image: interlegis/sapl:3.1.157-RC5
# build: .
restart: always
environment:

106
release.sh

@ -1,51 +1,113 @@
#/bin/bash
VERSION=`git describe --tags --abbrev=0`
LAST_DIGIT=`echo $VERSION | cut -f 3 -d '.'`
MAIN_REV=`echo $VERSION | cut -f 1,2 -d '.'`
##
## Versioning info: [major].[minor].[patch][-RC[num]], example: 3.1.159, 3.1.159-RC1
##
# TODO: verificar porque só pega versões superiores (3.1.200 ao invés de 3.1.200-RC9)
# VERSION=`git describe --tags --abbrev=0`
VERSION_PATTERN='([0-9]+)\.([0-9]+)\.([0-9]+)(-RC[0-9]+)?'
SED_AWKWARD_PATTERN="[0-9]+\.[0-9]+\.[0-9]+(-RC[0-9]+){0,1}"
LATEST_VERSION=$(git tag | egrep $VERSION_PATTERN | sort --version-sort | tail -1)
MAJOR_VERSION=$(echo $LATEST_VERSION | cut -d"-" -f1)
IS_RC=$(echo $LATEST_VERSION | egrep '(-RC)')
MAJOR_TAG_CREATED=$(git tag | egrep $MAJOR_VERSION"$")
if [ -n "$MAJOR_TAG_CREATED" ]; then
LATEST_VERSION=$MAJOR_VERSION
fi
LAST_DIGIT=`echo $MAJOR_VERSION | cut -f 3 -d '.'`
MAIN_REV=`echo $MAJOR_VERSION | cut -f 1,2 -d '.'`
NEXT_NUMBER=$(($LAST_DIGIT + 1))
NEXT_VERSION=$MAIN_REV'.'$NEXT_NUMBER
FINAL_VERSION=
function change_files {
OLD_VERSION=$(grep -E 'interlegis/sapl:'$VERSION_PATTERN docker-compose.yml | cut -d':' -f3)
function bump_version {
sed -e s/$VERSION/$NEXT_VERSION/g docker-compose.yml > tmp1
echo "Atualizando de "$OLD_VERSION" para "$FINAL_VERSION
sed -E s/$OLD_VERSION/$FINAL_VERSION/g docker-compose.yml > tmp1
mv tmp1 docker-compose.yml
sed -e s/$VERSION/$NEXT_VERSION/g setup.py > tmp2
sed -E s/$OLD_VERSION/$FINAL_VERSION/g setup.py > tmp2
mv tmp2 setup.py
sed -e s/$VERSION/$NEXT_VERSION/g sapl/templates/base.html > tmp3
sed -E s/$OLD_VERSION/$FINAL_VERSION/g sapl/templates/base.html > tmp3
mv tmp3 sapl/templates/base.html
sed -e s/$VERSION/$NEXT_VERSION/g sapl/settings.py > tmp4
sed -E s/$OLD_VERSION/$FINAL_VERSION/g sapl/settings.py > tmp4
mv tmp4 sapl/settings.py
}
function set_major_version {
if [ -z "$IS_RC" ] || [ -n "$MAJOR_TAG_CREATED" ]; then
FINAL_VERSION=$NEXT_VERSION
else
FINAL_VERSION=$MAJOR_VERSION
fi
}
function set_rc_version {
if [ -z "$IS_RC" ]; then
NEXT_RC_VERSION=$NEXT_VERSION"-RC0"
else
LAST_RC_DIGIT=$(echo $LATEST_VERSION | rev | cut -d"-" -f1 | rev | sed s/RC//)
NEXT_RC_NUMBER=$(($LAST_RC_DIGIT + 1))
NEXT_RC_VERSION=$(echo $LATEST_VERSION | cut -d"-" -f1)'-RC'$NEXT_RC_NUMBER
fi
FINAL_VERSION=$NEXT_RC_VERSION
}
function commit_and_push {
echo "committing..."
git add docker-compose.yml setup.py sapl/settings.py sapl/templates/base.html
git commit -m "Release: $NEXT_VERSION"
git tag $NEXT_VERSION
git commit -m "Release: $FINAL_VERSION"
git tag $FINAL_VERSION
echo "sending to github..."
git push origin $NEXT_VERSION
git push origin
git push origin $FINAL_VERSION
echo "done."
}
case "$1" in
--dry-run)
echo "Dry run"
bump_version
echo "done."
echo "Run git checkout -- docker-compose.yml setup.py to undo the files"
exit 0
;;
--publish)
echo "generating release"
bump_version
--latest)
echo $LATEST_VERSION
exit 0
;;
--major)
set_major_version
echo "generating major release: "$FINAL_VERSION
# git tag $FINAL_VERSION
change_files
commit_and_push
exit 0
;;
--rc)
set_rc_version
echo "generating release candidate: "$FINAL_VERSION
# git tag $FINAL_VERSION
change_files
commit_and_push
exit 0
;;
--undo)
git tag -d $LATEST_VERSION
exit 0
;;
--top)
git tag | sort --version-sort | tail "-$2"
exit 0
;;
esac

2
requirements/requirements.txt

@ -1,7 +1,7 @@
django>=1.11.19,<2.0
django-haystack==2.8.1
django-filter==2.0.0
djangorestframework==3.9.0
djangorestframework==3.9.1
dj-database-url==0.5.0
django-braces==1.9.0
django-crispy-forms==1.7.2

8
sapl/api/views.py

@ -168,7 +168,7 @@ SaplApiViewSetConstrutor.build_class()
http://localhost:9000/api/
desde que settings.DEBUG=True
**SaplSetViews** é um dict de dicts de models conforme:
**SaplApiViewSetConstrutor._built_sets** é um dict de dicts de models conforme:
{
...
@ -201,8 +201,6 @@ SaplApiViewSetConstrutor.build_class()
# rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor
# decorator para recuperar e transformar o default
class customize(object):
def __init__(self, model):
self.model = model
@ -243,7 +241,7 @@ class _AutorViewSet:
/api/base/autor/{pk}/ PATCH - partial_update
/api/base/autor/{pk}/ DELETE - destroy
* rotas desta classe local:
* rotas desta classe local criadas pelo método build:
/api/base/autor/parlamentar
devolve apenas autores que são parlamentares
/api/base/autor/comissao
@ -256,8 +254,6 @@ class _AutorViewSet:
devolve apenas autores que são Frene parlamentares
/api/base/autor/orgao
devolve apenas autores que são Órgãos
"""
def list_for_content_type(self, content_type):

88
sapl/base/forms.py

@ -30,6 +30,7 @@ from sapl.materia.models import (
MateriaLegislativa, UnidadeTramitacao, StatusTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.parlamentares.models import SessaoLegislativa, Partido
from sapl.protocoloadm.models import DocumentoAdministrativo
from sapl.sessao.models import SessaoPlenaria
from sapl.settings import MAX_IMAGE_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
@ -898,34 +899,35 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'tramitacao__unidade_tramitacao_local',
'tramitacao__status', 'tramitacao__data_tramitacao']
fields = ['tipo', 'tramitacao__status', 'tramitacao__data_tramitacao',
'tramitacao__unidade_tramitacao_local', 'tramitacao__unidade_tramitacao_destino']
def __init__(self, *args, **kwargs):
super(RelatorioHistoricoTramitacaoFilterSet, self).__init__(
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['tramitacao__unidade_tramitacao_local'
].label = _('Unidade Local')
self.filters['tramitacao__status'].label = _('Status')
row1 = to_row([('tramitacao__data_tramitacao', 12)])
self.filters['tramitacao__unidade_tramitacao_local'].label = _('Unidade Local (Origem)')
self.filters['tramitacao__unidade_tramitacao_destino'].label = _('Unidade Destino')
row2 = to_row(
[('tipo', 4),
('tramitacao__unidade_tramitacao_local', 4),
('tramitacao__status', 4)])
row1 = to_row([('tramitacao__data_tramitacao', 12)])
row2 = to_row([('tramitacao__unidade_tramitacao_local', 6),
('tramitacao__unidade_tramitacao_destino', 6)])
row3 = to_row(
[('tipo', 6),
('tramitacao__status', 6)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Histórico de Tramitação'),
row1, row2,
Fieldset(_(''),
row1, row2, row3,
form_actions(label='Pesquisar'))
)
class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
@property
@ -936,6 +938,7 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'tramitacao__unidade_tramitacao_local',
'tramitacao__unidade_tramitacao_destino',
'tramitacao__status', 'tramitacao__data_fim_prazo']
def __init__(self, *args, **kwargs):
@ -943,20 +946,22 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['tramitacao__unidade_tramitacao_local'].label = 'Unidade de tramitação local'
self.filters['tramitacao__unidade_tramitacao_local'].label = 'Unidade Local (Origem)'
self.filters['tramitacao__unidade_tramitacao_destino'].label = 'Unidade Destino'
self.filters['tramitacao__status'].label = 'Status de tramitação'
row1 = to_row([('tramitacao__data_fim_prazo', 12)])
row2 = to_row(
[('tipo', 4),
('tramitacao__unidade_tramitacao_local', 4),
('tramitacao__status', 4)])
row2 = to_row([('tramitacao__unidade_tramitacao_local', 6),
('tramitacao__unidade_tramitacao_destino', 6)])
row3 = to_row(
[('tipo', 6),
('tramitacao__status', 6)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Tramitações por fim de prazo'),
row1, row2,
row1, row2, row3,
form_actions(label='Pesquisar'))
)
@ -1220,7 +1225,9 @@ class ConfiguracoesAppForm(ModelForm):
'receber_recibo_proposicao',
'assinatura_ata',
'estatisticas_acesso_normas',
'escolher_numero_materia_proposicao']
'escolher_numero_materia_proposicao',
'tramitacao_materia',
'tramitacao_documento']
def __init__(self, *args, **kwargs):
super(ConfiguracoesAppForm, self).__init__(*args, **kwargs)
@ -1422,4 +1429,43 @@ class PartidoForm(FileFieldCheckMixin, ModelForm):
if cleaned_data['data_criacao'] > cleaned_data['data_extincao']:
raise ValidationError("Certifique-se de que a data de criação seja anterior à data de extinção.")
return cleaned_data
return cleaned_data
class RelatorioHistoricoTramitacaoAdmFilterSet(django_filters.FilterSet):
@property
def qs(self):
parent = super(RelatorioHistoricoTramitacaoAdmFilterSet, self).qs
return parent.distinct().prefetch_related('tipo').order_by('-ano', 'tipo', 'numero')
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
fields = ['tipo', 'tramitacaoadministrativo__status',
'tramitacaoadministrativo__data_tramitacao',
'tramitacaoadministrativo__unidade_tramitacao_local',
'tramitacaoadministrativo__unidade_tramitacao_destino']
def __init__(self, *args, **kwargs):
super(RelatorioHistoricoTramitacaoAdmFilterSet, self).__init__(
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Documento'
self.filters['tramitacaoadministrativo__status'].label = _('Status')
self.filters['tramitacaoadministrativo__unidade_tramitacao_local'].label = _('Unidade Local (Origem)')
self.filters['tramitacaoadministrativo__unidade_tramitacao_destino'].label = _('Unidade Destino')
row1 = to_row([('tramitacaoadministrativo__data_tramitacao', 12)])
row2 = to_row([('tramitacaoadministrativo__unidade_tramitacao_local', 6),
('tramitacaoadministrativo__unidade_tramitacao_destino', 6)])
row3 = to_row(
[('tipo', 6),
('tramitacaoadministrativo__status', 6)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_(''),
row1, row2, row3,
form_actions(label='Pesquisar'))
)

25
sapl/base/migrations/0037_auto_20190527_0901.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-27 12:01
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0036_auto_20190417_1432'),
]
operations = [
migrations.AddField(
model_name='appconfig',
name='tramitacao_documento',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Tramitar documentos anexados junto com os documentos principais?'),
),
migrations.AddField(
model_name='appconfig',
name='tramitacao_materia',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Tramitar matérias anexadas junto com as matérias principais?'),
),
]

8
sapl/base/models.py

@ -176,6 +176,14 @@ class AppConfig(models.Model):
verbose_name=_('Indicar número da matéria a ser gerada na proposição?'),
choices=YES_NO_CHOICES, default=False)
tramitacao_materia = models.BooleanField(
verbose_name=_('Tramitar matérias anexadas junto com as matérias principais?'),
choices=YES_NO_CHOICES, default=True)
tramitacao_documento = models.BooleanField(
verbose_name=_('Tramitar documentos anexados junto com os documentos principais?'),
choices=YES_NO_CHOICES, default=True)
class Meta:
verbose_name = _('Configurações da Aplicação')
verbose_name_plural = _('Configurações da Aplicação')

10
sapl/base/urls.py

@ -38,7 +38,9 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
ListarParlFiliacoesIntersecaoView,
ListarAutoresDuplicadosView,
ListarBancadaComissaoAutorExternoView,
ListarLegislaturaInfindavelView)
ListarLegislaturaInfindavelView,
pesquisa_textual,
RelatorioHistoricoTramitacaoAdmView)
app_name = AppConfig.name
@ -134,6 +136,9 @@ urlpatterns = [
url(r'^sistema/relatorios/audiencia$',
RelatorioAudienciaView.as_view(),
name='audiencia'),
url(r'^sistema/relatorios/historico-tramitacoesadm$',
RelatorioHistoricoTramitacaoAdmView.as_view(),
name='historico_tramitacoes_adm'),
url(r'^email/validate/(?P<uidb64>[0-9A-Za-z_\-]+)/'
'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',
@ -175,6 +180,9 @@ urlpatterns = [
url(r'^sistema/inconsistencias/legislatura_infindavel$',
ListarLegislaturaInfindavelView.as_view(),
name='lista_legislatura_infindavel'),
url(r'^sistema/pesquisa-textual',
pesquisa_textual,
name='pesquisa_textual'),
url(r'^sistema/estatisticas', get_estatistica),

140
sapl/base/views.py

@ -27,6 +27,7 @@ from django.views.generic import (CreateView, DeleteView, FormView, ListView,
from django.views.generic.base import RedirectView, TemplateView
from django_filters.views import FilterView
from haystack.views import SearchView
from haystack.query import SearchQuerySet
from sapl import settings
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
@ -38,13 +39,14 @@ from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato, Filiacao
from sapl.protocoloadm.models import Protocolo
from sapl.protocoloadm.models import (Protocolo, TipoDocumentoAdministrativo,
StatusTramitacaoAdministrativo,
DocumentoAdministrativo)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca, Bancada)
from sapl.utils import (parlamentares_ativos, gerar_hash_arquivo, SEPARADOR_HASH_PROPOSICAO,
show_results_filter_set, mail_service_configured,
intervalos_tem_intersecao,)
intervalos_tem_intersecao, remover_acentos)
from .forms import (AlterarSenhaForm, CasaLegislativaForm,
ConfiguracoesAppForm, RelatorioAtasFilterSet,
RelatorioAudienciaFilterSet,
@ -57,7 +59,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm,
RelatorioReuniaoFilterSet, UsuarioCreateForm,
UsuarioEditForm, RelatorioNormasMesFilterSet,
RelatorioNormasVigenciaFilterSet,
EstatisticasAcessoNormasForm, UsuarioFilterSet)
EstatisticasAcessoNormasForm, UsuarioFilterSet,
RelatorioHistoricoTramitacaoAdmFilterSet)
from .models import AppConfig, CasaLegislativa
@ -294,11 +297,8 @@ class RelatoriosListView(TemplateView):
def get_context_data(self, **kwargs):
context = super(TemplateView, self).get_context_data(**kwargs)
estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas
if estatisticas_acesso_normas == 'S':
context['estatisticas_acesso_normas'] = True
else:
context['estatisticas_acesso_normas'] = False
context['estatisticas_acesso_normas'] = True if estatisticas_acesso_normas == 'S' else False
return context
@ -450,7 +450,7 @@ class RelatorioHistoricoTramitacaoView(FilterView):
def get_context_data(self, **kwargs):
context = super(RelatorioHistoricoTramitacaoView,
self).get_context_data(**kwargs)
context['title'] = _('Histórico de Tramitações')
context['title'] = _('Histórico de Tramitações de Matérias Legislativas')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
@ -465,16 +465,25 @@ class RelatorioHistoricoTramitacaoView(FilterView):
str(TipoMateriaLegislativa.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['tramitacao__status']:
tramitacao_status = self.request.GET['tramitacao__status']
context['tramitacao__status'] = (
str(StatusTramitacao.objects.get(id=tramitacao_status)))
else:
context['tramitacao__status'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_local']:
context['tramitacao__unidade_tramitacao_local'] = \
(str(UnidadeTramitacao.objects.get(
id=self.request.GET['tramitacao__unidade_tramitacao_local'])))
else:
context['tramitacao__unidade_tramitacao_local'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_destino']:
context['tramitacao__unidade_tramitacao_destino'] = \
(str(UnidadeTramitacao.objects.get(
id=self.request.GET['tramitacao__unidade_tramitacao_destino'])))
else:
context['tramitacao__unidade_tramitacao_destino'] = ''
@ -505,16 +514,25 @@ class RelatorioDataFimPrazoTramitacaoView(FilterView):
str(TipoMateriaLegislativa.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['tramitacao__status']:
tramitacao_status = self.request.GET['tramitacao__status']
context['tramitacao__status'] = (
str(StatusTramitacao.objects.get(id=tramitacao_status)))
else:
context['tramitacao__status'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_local']:
context['tramitacao__unidade_tramitacao_local'] = \
(str(UnidadeTramitacao.objects.get(
id=self.request.GET['tramitacao__unidade_tramitacao_local'])))
else:
context['tramitacao__unidade_tramitacao_local'] = ''
if self.request.GET['tramitacao__unidade_tramitacao_destino']:
context['tramitacao__unidade_tramitacao_destino'] = \
(str(UnidadeTramitacao.objects.get(
id=self.request.GET['tramitacao__unidade_tramitacao_destino'])))
else:
context['tramitacao__unidade_tramitacao_destino'] = ''
@ -1748,3 +1766,105 @@ class LogotipoView(RedirectView):
casa = get_casalegislativa()
logo = casa and casa.logotipo and casa.logotipo.name
return os.path.join(settings.MEDIA_URL, logo) if logo else STATIC_LOGO
def filtro_campos(dicionario):
chaves_desejadas = ['ementa',
'ano',
'numero',
'em_tramitacao',
'data_apresentacao',
'apelido',
'indexacao',
'data_publicacao',
'data',
'data_vigencia']
del_list = []
for key in dicionario.keys():
if key not in chaves_desejadas:
del_list = del_list + [key]
for key in del_list:
del dicionario[key]
return dicionario
def pesquisa_textual(request):
if 'q' not in request.GET:
return JsonResponse({'total': 0,
'resultados': []})
results = SearchQuerySet().filter(content=request.GET['q'])
json_dict = {
'total': results.count(),
'parametros': request.GET['q'],
'resultados': [],
}
for e in results:
sec_dict = {}
try:
sec_dict['pk'] = e.object.pk
except:
# Index and db are out of sync. Object has been deleted from database
continue
dici = filtro_campos(e.object.__dict__)
sec_dict['objeto'] = str(dici)
sec_dict['text'] = str(e.object.ementa)
sec_dict['model'] = str(type(e.object))
json_dict['resultados'].append(sec_dict)
return JsonResponse(json_dict)
class RelatorioHistoricoTramitacaoAdmView(FilterView):
model = DocumentoAdministrativo
filterset_class = RelatorioHistoricoTramitacaoAdmFilterSet
template_name = 'base/RelatorioHistoricoTramitacaoAdm_filter.html'
def get_context_data(self, **kwargs):
context = super(RelatorioHistoricoTramitacaoAdmView,
self).get_context_data(**kwargs)
context['title'] = _('Histórico de Tramitações de Documento Administrativo')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
context['data_tramitacao'] = (self.request.GET['tramitacaoadministrativo__data_tramitacao_0'] + ' - ' +
self.request.GET['tramitacaoadministrativo__data_tramitacao_1'])
if self.request.GET['tipo']:
tipo = self.request.GET['tipo']
context['tipo'] = (
str(TipoDocumentoAdministrativo.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['tramitacaoadministrativo__status']:
tramitacao_status = self.request.GET['tramitacaoadministrativo__status']
context['tramitacaoadministrativo__status'] = (
str(StatusTramitacaoAdministrativo.objects.get(id=tramitacao_status)))
else:
context['tramitacaoadministrativo__status'] = ''
if self.request.GET['tramitacaoadministrativo__unidade_tramitacao_local']:
context['tramitacaoadministrativo__unidade_tramitacao_local'] = \
(str(UnidadeTramitacao.objects.get(
id=self.request.GET['tramitacaoadministrativo__unidade_tramitacao_local'])))
else:
context['tramitacaoadministrativo__unidade_tramitacao_local'] = ''
if self.request.GET['tramitacaoadministrativo__unidade_tramitacao_destino']:
context['tramitacaoadministrativo__unidade_tramitacao_destino'] = \
(str(UnidadeTramitacao.objects.get(
id=self.request.GET['tramitacaoadministrativo__unidade_tramitacao_destino'])))
else:
context['tramitacaoadministrativo__unidade_tramitacao_destino'] = ''
return context

8
sapl/comissoes/forms.py

@ -11,6 +11,7 @@ from django.utils.translation import ugettext_lazy as _
from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import (Comissao, Composicao, DocumentoAcessorio,
Participacao, Reuniao, Periodo)
from sapl.materia.models import PautaReuniao
from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar
from sapl.utils import FileFieldCheckMixin
@ -383,6 +384,13 @@ class ReuniaoForm(ModelForm):
return self.cleaned_data
class PautaReuniaoForm(forms.ModelForm):
class Meta:
model = PautaReuniao
exclude = ['reuniao']
class DocumentoAcessorioCreateForm(FileFieldCheckMixin, forms.ModelForm):
parent_pk = forms.CharField(required=False) # widget=forms.HiddenInput())

6
sapl/comissoes/urls.py

@ -1,7 +1,8 @@
from django.conf.urls import include, url
from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud,
DocumentoAcessorioCrud, MateriasTramitacaoListView, ParticipacaoCrud,
PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud, get_participacoes_comissao)
PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud, get_participacoes_comissao,
AdicionaPautaView, RemovePautaView)
from .apps import AppConfig
@ -17,6 +18,9 @@ urlpatterns = [
url(r'^comissao/(?P<pk>\d+)/materias-em-tramitacao$',
MateriasTramitacaoListView.as_view(), name='materias_em_tramitacao'),
url(r'^comissao/(?P<pk>\d+)/pauta/add', AdicionaPautaView.as_view(), name='pauta_add'),
url(r'^comissao/(?P<pk>\d+)/pauta/remove', RemovePautaView.as_view(), name='pauta_remove'),
url(r'^sistema/comissao/cargo/', include(CargoCrud.get_urls())),
url(r'^sistema/comissao/periodo-composicao/',
include(PeriodoComposicaoCrud.get_urls())),

161
sapl/comissoes/views.py

@ -1,13 +1,16 @@
import logging
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import F
from django.http.response import HttpResponseRedirect, JsonResponse
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import ListView
from django.views.generic import ListView, CreateView, DeleteView
from django.views.generic.base import RedirectView
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from django.views.generic.edit import FormMixin, UpdateView
from django.utils.translation import ugettext_lazy as _
from sapl.base.models import AppConfig as AppsAppConfig
from sapl.comissoes.apps import AppConfig
@ -15,11 +18,11 @@ from sapl.comissoes.forms import (ComissaoForm, ComposicaoForm,
DocumentoAcessorioCreateForm,
DocumentoAcessorioEditForm,
ParticipacaoCreateForm, ParticipacaoEditForm,
PeriodoForm, ReuniaoForm)
PeriodoForm, ReuniaoForm, PautaReuniaoForm)
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud,
PermissionRequiredForAppCrudMixin)
from sapl.materia.models import MateriaLegislativa, Tramitacao
from sapl.materia.models import MateriaLegislativa, Tramitacao, PautaReuniao
from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio,
Participacao, Periodo, Reuniao, TipoComissao)
@ -162,25 +165,26 @@ class ComissaoCrud(Crud):
return super(Crud.UpdateView, self).form_valid(form)
def lista_materias_comissao(comissao_pk):
ts = Tramitacao.objects.order_by(
'materia', '-data_tramitacao', '-id').annotate(
comissao=F('unidade_tramitacao_destino__comissao')).distinct(
'materia').values_list('materia', 'comissao')
ts = [m for (m,c) in ts if c == int(comissao_pk)]
materias = MateriaLegislativa.objects.filter(
pk__in=ts).order_by('tipo', '-ano', '-numero')
return materias
class MateriasTramitacaoListView(ListView):
template_name = "comissoes/materias_em_tramitacao.html"
paginate_by = 10
def get_queryset(self):
# FIXME: Otimizar consulta
ts = Tramitacao.objects.order_by(
'materia', '-data_tramitacao', '-id').annotate(
comissao=F('unidade_tramitacao_destino__comissao')).distinct(
'materia').values_list('materia', 'comissao')
ts = list(filter(lambda x: x[1] == int(self.kwargs['pk']), ts))
ts = list(zip(*ts))
ts = ts[0] if ts else []
materias = MateriaLegislativa.objects.filter(
pk__in=ts).order_by('tipo', '-ano', '-numero')
return materias
return lista_materias_comissao(self.kwargs['pk'])
def get_context_data(self, **kwargs):
context = super(
@ -193,13 +197,38 @@ class MateriasTramitacaoListView(ListView):
class ReuniaoCrud(MasterDetailCrud):
model = Reuniao
parent_field = 'comissao'
model_set = 'documentoacessorio_set'
public = [RP_LIST, RP_DETAIL, ]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['data', 'nome', 'tema', 'upload_ata']
ordering = '-data'
class DetailView(MasterDetailCrud.DetailView):
template_name = "comissoes/reuniao_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
docs = []
documentos = DocumentoAcessorio.objects.filter(reuniao=self.kwargs['pk']).order_by('nome')
docs.extend(documentos)
context['docs'] = docs
context['num_docs'] = len(docs)
mats = []
materias_pauta = PautaReuniao.objects.filter(reuniao=self.kwargs['pk'])
materias_pk = [materia_pauta.materia.pk for materia_pauta in materias_pauta]
context['mats'] = MateriaLegislativa.objects.filter(
pk__in=materias_pk
).order_by('tipo', '-ano', '-numero')
context['num_mats'] = len(context['mats'])
context['reuniao_pk'] = self.kwargs['pk']
return context
class ListView(MasterDetailCrud.ListView):
logger = logging.getLogger(__name__)
paginate_by = 10
@ -249,6 +278,100 @@ class ReuniaoCrud(MasterDetailCrud):
return {'comissao': comissao}
class RemovePautaView(PermissionRequiredMixin, CreateView):
model = PautaReuniao
form_class = PautaReuniaoForm
template_name = 'comissoes/pauta.html'
permission_required = ('comissoes.add_reuniao', )
def get_context_data(self, **kwargs):
context = super(
RemovePautaView, self
).get_context_data(**kwargs)
# Remove = 0; Adiciona = 1
context['opcao'] = 0
context['object'] = Reuniao.objects.get(pk=self.kwargs['pk'])
context['root_pk'] = context['object'].comissao.pk
materias_pauta = PautaReuniao.objects.filter(reuniao=context['object'])
materias_pk = [materia_pauta.materia.pk for materia_pauta in materias_pauta]
context['materias'] = MateriaLegislativa.objects.filter(
pk__in=materias_pk
).order_by('tipo', '-ano', '-numero')
context['num_materias'] = len(context['materias'])
return context
def post(self, request, *args, **kwargs):
success_url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk':kwargs['pk']})
marcadas = request.POST.getlist('materia_id')
if not marcadas:
msg=_('Nenhuma matéria foi selecionada.')
messages.add_message(request, messages.WARNING, msg)
return HttpResponseRedirect(success_url)
reuniao = Reuniao.objects.get(pk=kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in=marcadas):
PautaReuniao.objects.filter(reuniao=reuniao,materia=materia).delete()
msg=_('Matéria(s) removida(s) com sucesso!')
messages.add_message(request, messages.SUCCESS, msg)
return HttpResponseRedirect(success_url)
class AdicionaPautaView(PermissionRequiredMixin, CreateView):
model = PautaReuniao
form_class = PautaReuniaoForm
template_name = 'comissoes/pauta.html'
permission_required = ('comissoes.add_reuniao', )
def get_context_data(self, **kwargs):
context = super(
AdicionaPautaView, self
).get_context_data(**kwargs)
# Adiciona = 1; Remove = 0
context['opcao'] = 1
context['object'] = Reuniao.objects.get(pk=self.kwargs['pk'])
context['root_pk'] = context['object'].comissao.pk
materias_comissao = lista_materias_comissao(context['object'].comissao.pk)
materias_pauta = PautaReuniao.objects.filter(reuniao=context['object'])
nao_listar = [mp.materia.pk for mp in materias_pauta]
context['materias'] = materias_comissao.exclude(pk__in=nao_listar)
context['num_materias'] = len(context['materias'])
return context
def post(self, request, *args, **kwargs):
success_url = reverse('sapl.comissoes:reuniao_detail', kwargs={'pk':kwargs['pk']})
marcadas = request.POST.getlist('materia_id')
if not marcadas:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.WARNING, msg)
return HttpResponseRedirect(success_url)
reuniao = Reuniao.objects.get(pk=kwargs['pk'])
pautas = []
for materia in MateriaLegislativa.objects.filter(id__in=marcadas):
pauta = PautaReuniao()
pauta.reuniao = reuniao
pauta.materia = materia
pautas.append(pauta)
PautaReuniao.objects.bulk_create(pautas)
msg = _('Matéria(s) adicionada(s) com sucesso!')
messages.add_message(request, messages.SUCCESS, msg)
return HttpResponseRedirect(success_url)
class DocumentoAcessorioCrud(MasterDetailCrud):
model = DocumentoAcessorio
parent_field = 'reuniao__comissao'

101
sapl/materia/forms.py

@ -194,6 +194,10 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
model = MateriaLegislativa
exclude = ['texto_articulado', 'autores', 'proposicao',
'anexadas', 'data_ultima_atualizacao']
widgets = {
'user': forms.HiddenInput(),
'ip': forms.HiddenInput()
}
def __init__(self, *args, **kwargs):
super(MateriaLegislativaForm, self).__init__(*args, **kwargs)
@ -557,28 +561,30 @@ class TramitacaoForm(ModelForm):
materia.em_tramitacao = False if tramitacao.status.indicador == "F" else True
materia.save()
lista_tramitacao = []
lista_anexadas = lista_anexados(materia)
for ma in lista_anexadas:
if not ma.tramitacao_set.all() \
or ma.tramitacao_set.last().unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
ma.em_tramitacao = False if tramitacao.status.indicador == "F" else True
ma.save()
lista_tramitacao.append(Tramitacao(
status=tramitacao.status,
materia=ma,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
turno=tramitacao.turno,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip
))
Tramitacao.objects.bulk_create(lista_tramitacao)
tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
if tramitar_anexadas:
lista_tramitacao = []
anexadas_list = lista_anexados(materia)
for ma in anexadas_list:
if not ma.tramitacao_set.all() \
or ma.tramitacao_set.last().unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
ma.em_tramitacao = False if tramitacao.status.indicador == "F" else True
ma.save()
lista_tramitacao.append(Tramitacao(
status=tramitacao.status,
materia=ma,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
turno=tramitacao.turno,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip
))
Tramitacao.objects.bulk_create(lista_tramitacao)
return tramitacao
@ -653,17 +659,6 @@ class TramitacaoUpdateForm(TramitacaoForm):
'Você não pode mudar a Unidade de Destino desta '
'tramitação, pois irá conflitar com a Unidade '
'Local da tramitação seguinte')
# Se não houve qualquer alteração em um dos dados, mantém o usuário e ip
if not (cd['data_tramitacao'] != obj.data_tramitacao or \
cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or \
cd['status'] != obj.status or cd['texto'] != obj.texto or \
cd['data_encaminhamento'] != obj.data_encaminhamento or \
cd['data_fim_prazo'] != obj.data_fim_prazo or \
cd['urgente'] != obj.urgente or \
cd['turno'] != obj.turno):
cd['user'] = obj.user
cd['ip'] = obj.ip
cd['data_tramitacao'] = obj.data_tramitacao
cd['unidade_tramitacao_local'] = obj.unidade_tramitacao_local
@ -678,25 +673,27 @@ class TramitacaoUpdateForm(TramitacaoForm):
materia.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True
materia.save()
lista_anexadas = lista_anexados(materia)
for ma in lista_anexadas:
tram_anexada = ma.tramitacao_set.last()
if compara_tramitacoes_mat(ant_tram_principal, tram_anexada):
tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local
tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento
tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino
tram_anexada.urgente = nova_tram_principal.urgente
tram_anexada.turno = nova_tram_principal.turno
tram_anexada.texto = nova_tram_principal.texto
tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo
tram_anexada.user = nova_tram_principal.user
tram_anexada.ip = nova_tram_principal.ip
tram_anexada.save()
ma.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True
ma.save()
tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
if tramitar_anexadas:
anexadas_list = lista_anexados(materia)
for ma in anexadas_list:
tram_anexada = ma.tramitacao_set.last()
if compara_tramitacoes_mat(ant_tram_principal, tram_anexada):
tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local
tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento
tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino
tram_anexada.urgente = nova_tram_principal.urgente
tram_anexada.turno = nova_tram_principal.turno
tram_anexada.texto = nova_tram_principal.texto
tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo
tram_anexada.user = nova_tram_principal.user
tram_anexada.ip = nova_tram_principal.ip
tram_anexada.save()
ma.em_tramitacao = False if nova_tram_principal.status.indicador == "F" else True
ma.save()
return nova_tram_principal
class LegislacaoCitadaForm(ModelForm):

29
sapl/materia/migrations/0049_pautareuniao.py

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-14 20:11
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('comissoes', '0019_auto_20181214_1023'),
('materia', '0048_merge_20190426_0828'),
]
operations = [
migrations.CreateModel(
name='PautaReuniao',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('materia', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materia_set', to='materia.MateriaLegislativa', verbose_name='Matéria')),
('reuniao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reuniao_set', to='comissoes.Reuniao', verbose_name='Reunião')),
],
options={
'verbose_name': 'Matéria da Pauta',
'verbose_name_plural': 'Matérias da Pauta',
},
),
]

28
sapl/materia/migrations/0050_auto_20190521_1148.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-21 14:48
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('materia', '0049_pautareuniao'),
]
operations = [
migrations.AddField(
model_name='materialegislativa',
name='ip',
field=models.CharField(blank=True, default='', max_length=30, verbose_name='IP'),
),
migrations.AddField(
model_name='materialegislativa',
name='user',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Usuário'),
),
]

40
sapl/materia/models.py

@ -11,7 +11,7 @@ from model_utils import Choices
import reversion
from sapl.base.models import SEQUENCIA_NUMERACAO_PROTOCOLO, Autor
from sapl.comissoes.models import Comissao
from sapl.comissoes.models import Comissao, Reuniao
from sapl.compilacao.models import (PerfilEstruturalTextoArticulado,
TextoArticulado)
from sapl.parlamentares.models import Parlamentar
@ -279,6 +279,20 @@ class MateriaLegislativa(models.Model):
auto_now=True,
verbose_name=_('Data'))
user = models.ForeignKey(
get_settings_auth_user_model(),
verbose_name=_('Usuário'),
on_delete=models.PROTECT,
null=True,
blank=True
)
ip = models.CharField(
verbose_name=_('IP'),
max_length=30,
blank=True,
default=''
)
class Meta:
verbose_name = _('Matéria Legislativa')
verbose_name_plural = _('Matérias Legislativas')
@ -401,6 +415,30 @@ class AcompanhamentoMateria(models.Model):
}
@reversion.register()
class PautaReuniao(models.Model):
reuniao = models.ForeignKey(
Reuniao, related_name='reuniao_set',
on_delete=models.CASCADE,
verbose_name=_('Reunião')
)
materia = models.ForeignKey(
MateriaLegislativa, related_name='materia_set',
verbose_name=_('Matéria')
)
class Meta:
verbose_name = _('Matéria da Pauta')
verbose_name_plural = ('Matérias da Pauta')
def __str__(self):
return _('Reunião: %(reuniao)s'
' - Matéria: %(materia)s') % {
'reuniao': self.reuniao,
'materia': self.materia
}
@reversion.register()
class Anexada(models.Model):
materia_principal = models.ForeignKey(

152
sapl/materia/tests/test_materia.py

@ -7,7 +7,7 @@ from django.db.models import Max
from model_mommy import mommy
import pytest
from sapl.base.models import Autor, TipoAutor
from sapl.base.models import Autor, TipoAutor, AppConfig
from sapl.comissoes.models import Comissao, TipoComissao
from sapl.materia.models import (Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa,
@ -78,6 +78,51 @@ def test_lista_materias_anexadas():
assert lista[1] == materia_anexada_anexada
@pytest.mark.django_db(transaction=False)
def test_lista_materias_anexadas_ciclo():
tipo_materia = mommy.make(
TipoMateriaLegislativa,
descricao="Tipo_Teste"
)
regime_tramitacao = mommy.make(
RegimeTramitacao,
descricao="Regime_Teste"
)
materia_principal = mommy.make(
MateriaLegislativa,
numero=20,
ano=2018,
data_apresentacao="2018-01-04",
regime_tramitacao=regime_tramitacao,
tipo=tipo_materia
)
materia_anexada = mommy.make(
MateriaLegislativa,
numero=21,
ano=2019,
data_apresentacao="2019-05-04",
regime_tramitacao=regime_tramitacao,
tipo=tipo_materia
)
mommy.make(
Anexada,
materia_principal=materia_principal,
materia_anexada=materia_anexada,
data_anexacao="2019-05-11"
)
mommy.make(
Anexada,
materia_principal=materia_anexada,
materia_anexada=materia_principal,
data_anexacao="2020-11-05"
)
lista = lista_anexados(materia_principal)
assert len(lista) == 1
assert lista[0] == materia_anexada
@pytest.mark.django_db(transaction=False)
def make_unidade_tramitacao(descricao):
# Cria uma comissão para ser a unidade de tramitação
@ -643,6 +688,8 @@ def test_numeracao_materia_legislativa_por_ano(admin_client):
@pytest.mark.django_db(transaction=False)
def test_tramitacoes_materias_anexadas(admin_client):
config = mommy.make(AppConfig, tramitacao_materia=True)
tipo_materia = mommy.make(
TipoMateriaLegislativa,
descricao="Tipo_Teste"
@ -813,4 +860,105 @@ def test_tramitacoes_materias_anexadas(admin_client):
kwargs={'pk': tramitacao_anexada.pk})
response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True)
assert Tramitacao.objects.filter(id=tramitacao_anexada.pk).count() == 0
assert Tramitacao.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0
assert Tramitacao.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0
# Agora testando para caso não seja desejado tramitar as matérias anexadas
# junto com as matérias principais
assert Tramitacao.objects.all().count() == 0
config.tramitacao_materia = False
config.save()
# Teste criação de Tramitacao
form = TramitacaoForm(data={})
form.data = {'data_tramitacao':date(2019, 5, 6),
'unidade_tramitacao_local':unidade_tramitacao_local_1.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk,
'status':status.pk,
'urgente': False,
'texto': "Texto de teste"}
form.instance.materia_id=materia_principal.pk
assert form.is_valid()
tramitacao_principal = form.save()
tramitacao_anexada = materia_anexada.tramitacao_set.last()
tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last()
# Deve ser criada tramitação apenas para a matéria principal
assert materia_principal.tramitacao_set.last() == tramitacao_principal
assert not tramitacao_anexada
assert not tramitacao_anexada_anexada
# Criação de uma tramitação igual para a anexada à principal para testar a edição
form = TramitacaoForm(data={})
form.data = {'data_tramitacao':date(2019, 5, 6),
'unidade_tramitacao_local':unidade_tramitacao_local_1.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk,
'status':status.pk,
'urgente': False,
'texto': "Texto de teste"}
form.instance.materia_id=materia_anexada.pk
assert form.is_valid()
tramitacao_anexada = form.save()
tramitacao_principal = materia_principal.tramitacao_set.last()
tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last()
assert materia_anexada.tramitacao_set.last() == tramitacao_anexada
assert materia_principal.tramitacao_set.all().count() == 1
assert compara_tramitacoes_mat(tramitacao_principal, tramitacao_anexada)
assert not tramitacao_anexada_anexada
# Teste Edição de Tramitacao
form = TramitacaoUpdateForm(data={})
# Alterando unidade_tramitacao_destino
form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao,
'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk,
'status':tramitacao_principal.status.pk,
'urgente': tramitacao_principal.urgente,
'texto': tramitacao_principal.texto}
form.instance = tramitacao_principal
assert form.is_valid()
tramitacao_principal = form.save()
tramitacao_anexada = materia_anexada.tramitacao_set.last()
tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last()
assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_2
assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_1
assert not tramitacao_anexada_anexada
# Alterando a tramitação anexada para testar a remoção de tramitações
# Alterando unidade_tramitacao_destino
form = TramitacaoUpdateForm(data={})
form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao,
'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk,
'status':tramitacao_principal.status.pk,
'urgente': tramitacao_principal.urgente,
'texto': tramitacao_principal.texto}
form.instance = tramitacao_anexada
assert form.is_valid()
tramitacao_anexada = form.save()
tramitacao_principal = materia_principal.tramitacao_set.last()
tramitacao_anexada_anexada = materia_anexada_anexada.tramitacao_set.last()
assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_2
assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2
assert not tramitacao_anexada_anexada
assert compara_tramitacoes_mat(tramitacao_principal, tramitacao_anexada)
# Testando a remoção
# Removendo a tramitação pricipal, as tramitações anexadas não devem ser removidas
url = reverse('sapl.materia:tramitacao_delete',
kwargs={'pk': tramitacao_principal.pk})
response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True)
assert Tramitacao.objects.filter(id=tramitacao_principal.pk).count() == 0
assert Tramitacao.objects.filter(id=tramitacao_anexada.pk).count() == 1

112
sapl/materia/views.py

@ -1256,18 +1256,29 @@ class TramitacaoCrud(MasterDetailCrud):
layout_key = 'TramitacaoUpdate'
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial['ip'] = get_client_ip(self.request)
initial['user'] = self.request.user
return initial
def form_valid(self, form):
dict_objeto_antigo = Tramitacao.objects.get(pk=self.kwargs['pk']).__dict__
self.object = form.save()
username = self.request.user.username
dict_objeto_novo = self.object.__dict__
user = self.request.user
atributos = [
'data_tramitacao', 'unidade_tramitacao_destino_id', 'status_id', 'texto',
'data_encaminhamento', 'data_fim_prazo', 'urgente', 'turno'
]
# Se não houve qualquer alteração em um dos dados, mantém o usuário e ip
for atributo in atributos:
if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]:
self.object.user = user
self.object.ip = get_client_ip(self.request)
self.object.save()
break
try:
self.logger.debug("user=" + username + ". Tentando enviar Tramitacao (sender={}, post={}, request={}"
self.logger.debug("user=" + user.username + ". Tentando enviar Tramitacao (sender={}, post={}, request={}"
.format(Tramitacao, self.object, self.request))
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
@ -1276,7 +1287,7 @@ class TramitacaoCrud(MasterDetailCrud):
msg = _('Tramitação atualizada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
self.logger.warning('user=' + username + '. Tramitação atualizada, mas e-mail de acompanhamento '
self.logger.warning('user=' + user.username + '. Tramitação atualizada, mas e-mail de acompanhamento '
'de matéria não enviado. Há problemas na configuração '
'do e-mail.')
messages.add_message(self.request, messages.WARNING, msg)
@ -1317,12 +1328,21 @@ class TramitacaoCrud(MasterDetailCrud):
return HttpResponseRedirect(url)
else:
tramitacoes_deletar = [tramitacao.id]
mat_anexadas = lista_anexados(materia)
for ma in mat_anexadas:
tram_anexada = ma.tramitacao_set.last()
if compara_tramitacoes_mat(tram_anexada, tramitacao):
tramitacoes_deletar.append(tram_anexada.id)
if materia.tramitacao_set.count() == 0:
materia.em_tramitacao = False
materia.save()
tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
if tramitar_anexadas:
mat_anexadas = lista_anexados(materia)
for ma in mat_anexadas:
tram_anexada = ma.tramitacao_set.last()
if compara_tramitacoes_mat(tram_anexada, tramitacao):
tramitacoes_deletar.append(tram_anexada.id)
if ma.tramitacao_set.count() == 0:
ma.em_tramitacao = False
ma.save()
Tramitacao.objects.filter(id__in=tramitacoes_deletar).delete()
return HttpResponseRedirect(url)
class DetailView(MasterDetailCrud.DetailView):
@ -1596,6 +1616,15 @@ class MateriaLegislativaCrud(Crud):
form_class = MateriaLegislativaForm
def form_valid(self, form):
self.object = form.instance
self.object.user = self.request.user
self.object.ip = get_client_ip(self.request)
self.object.save()
return super().form_valid(form)
@property
def cancel_url(self):
return self.search_url
@ -1605,8 +1634,28 @@ class MateriaLegislativaCrud(Crud):
form_class = MateriaLegislativaForm
def form_valid(self, form):
dict_objeto_antigo = MateriaLegislativa.objects.get(
pk=self.kwargs['pk']
).__dict__
self.object = form.save()
username = self.request.user.username
dict_objeto_novo = self.object.__dict__
atributos = [
'tipo_id', 'ano', 'numero', 'data_apresentacao', 'numero_protocolo',
'tipo_apresentacao', 'texto_original', 'apelido', 'dias_prazo', 'polemica',
'objeto', 'regime_tramitacao_id', 'em_tramitacao', 'data_fim_prazo',
'data_publicacao', 'complementar', 'tipo_origem_externa_id',
'numero_origem_externa', 'ano_origem_externa', 'local_origem_externa_id',
'data_origem_externa', 'ementa', 'indexacao', 'observacao'
]
for atributo in atributos:
if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]:
self.object.user = self.request.user
self.object.ip = get_client_ip(self.request)
self.object.save()
break
if Anexada.objects.filter(materia_principal=self.kwargs['pk']).exists():
materia = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
@ -1615,7 +1664,7 @@ class MateriaLegislativaCrud(Crud):
for anexada in anexadas:
anexada.em_tramitacao = True if form.instance.em_tramitacao else False
anexada.save()
return super().form_valid(form)
@property
@ -1630,6 +1679,13 @@ class MateriaLegislativaCrud(Crud):
class DetailView(Crud.DetailView):
layout_key = 'MateriaLegislativaDetail'
template_name = "materia/materia_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
context['materia'] = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
return context
class ListView(Crud.ListView, RedirectView):
@ -2183,8 +2239,8 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
msg = _('Matéria(s) anexada(s).')
messages.add_message(request, messages.SUCCESS, msg)
sucess_url = reverse('sapl_index') + 'materia/' + kwargs['pk'] + '/anexada'
return HttpResponseRedirect(sucess_url)
success_url = reverse('sapl.materia:anexada_list', kwargs={'pk': kwargs['pk']})
return HttpResponseRedirect(success_url)
class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
@ -2288,12 +2344,12 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
flag_error = False
materias_principais = [m for m in MateriaLegislativa.objects.filter(id__in=marcadas)]
materias_anexadas = [m.anexadas.all() for m in MateriaLegislativa.objects.filter(id__in=marcadas) if m.anexadas.all()]
materias_anexadas = list(itertools.chain.from_iterable(materias_anexadas))
tramitacao_local = int(request.POST['unidade_tramitacao_local'])
materias_anexadas = list(filter(lambda ma : not ma.tramitacao_set.all() or \
ma.tramitacao_set.last().unidade_tramitacao_destino.id == tramitacao_local,
materias_anexadas))
tramitar_anexadas = sapl.base.models.AppConfig.attr('tramitacao_materia')
materias_anexadas = []
if tramitar_anexadas:
for materia in materias_principais:
materias_anexadas = materias_anexadas + lista_anexados(materia)
materias = set(materias_principais + materias_anexadas)
for materia in materias:
@ -2351,11 +2407,13 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
materia.em_tramitacao = True
materia.save()
msg = _('Tramitação completa.')
msg = _('Tramitação completa. ' + "Foram tramitadas " + str(len(materias)) + " matéria(s).")
self.logger.info('user=' + username + '. Tramitação completa.')
messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs)
if self.primeira_tramitacao:
return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
return HttpResponseRedirect(reverse('sapl.materia:tramitacao_em_lote'))
class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
filterset_class = TramitacaoEmLoteFilterSet

4
sapl/norma/forms.py

@ -18,7 +18,7 @@ from sapl.materia.forms import choice_anos_com_materias
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import NormaPesquisaOrderingFilter, RangeWidgetOverride, \
choice_anos_com_normas, FilterOverridesMetaMixin, FileFieldCheckMixin
choice_anos_com_normas, FilterOverridesMetaMixin, FileFieldCheckMixin, ANO_CHOICES
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoNormaJuridica, AutoriaNorma)
@ -106,7 +106,7 @@ class NormaJuridicaForm(FileFieldCheckMixin, ModelForm):
ano_materia = forms.ChoiceField(
label='Ano Matéria',
required=False,
choices=choice_anos_com_materias,
choices=ANO_CHOICES,
widget=forms.Select(attrs={'autocomplete': 'off'})
)

2
sapl/norma/views.py

@ -79,7 +79,7 @@ class NormaPesquisaView(FilterView):
qs = qs.extra({
'nm_i': "CAST(regexp_replace(numero,'[^0-9]','', 'g') AS INTEGER)",
'norma_letra': "regexp_replace(numero,'[^a-zA-Z]','', 'g')"
}).order_by('-data', '-nm_i', '-norma_letra')
}).order_by('-data', '-nm_i', 'norma_letra')
return qs

67
sapl/parlamentares/migrations/0029_auto_20190517_1531.py

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-17 18:31
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0028_auto_20190515_1744'),
]
operations = [
migrations.RunSQL("""
INSERT INTO django_content_type (app_label, model)
SELECT 'parlamentares', 'bloco'
WHERE NOT EXISTS (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco');
"""),
migrations.RunSQL("""
INSERT INTO base_tipoautor (descricao, content_type_id)
SELECT 'Bloco Parlamentar', (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco')
WHERE NOT EXISTS (SELECT id
FROM base_tipoautor
WHERE content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco'));
"""),
migrations.RunSQL("""
UPDATE auth_permission
SET content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco')
WHERE content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'sessao' AND model = 'bloco')
AND NOT EXISTS (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco');
"""),
migrations.RunSQL("""
UPDATE base_autor
SET tipo_id = (SELECT id
FROM base_tipoautor
WHERE content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco')),
content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'parlamentares' AND model = 'bloco')
WHERE tipo_id = (SELECT id
FROM base_tipoautor
WHERE content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'sessao' AND model = 'bloco'));
"""),
migrations.RunSQL("""
DELETE FROM base_tipoautor
WHERE content_type_id = (SELECT id
FROM django_content_type
WHERE app_label = 'sessao' AND model = 'bloco');
"""),
]

368
sapl/protocoloadm/forms.py

@ -1,9 +1,9 @@
import logging
from crispy_forms.bootstrap import InlineRadios, Alert
from crispy_forms.bootstrap import InlineRadios, Alert, FormActions
from sapl.crispy_layout_mixin import SaplFormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Div
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout, Div, Submit
from django import forms
from django.core.exceptions import (MultipleObjectsReturned,
ObjectDoesNotExist, ValidationError)
@ -170,6 +170,7 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
o = AnoNumeroOrderingFilter(help_text='')
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
fields = ['tipo',
@ -207,17 +208,33 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
row4 = to_row(
[
('tramitacao', 2),
('tramitacaoadministrativo__status', 5),
('tramitacaoadministrativo__unidade_tramitacao_destino', 5),
('tramitacaoadministrativo__status', 4),
('tramitacaoadministrativo__unidade_tramitacao_destino', 6),
])
buttons = FormActions(
*[
HTML('''
<div class="form-check">
<input name="relatorio" type="checkbox" class="form-check-input" id="relatorio">
<label class="form-check-label" for="relatorio">Gerar relatório PDF</label>
</div>
''' )
],
Submit('pesquisar', _('Pesquisar'), css_class='float-right',
onclick='return true;'),
css_class='form-group row justify-content-between'
,
)
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisar Documento'),
row1, row2,
row3, row4,
form_actions(label='Pesquisar'))
row1, row2,
row3, row4,
buttons,)
)
@ -752,28 +769,30 @@ class TramitacaoAdmForm(ModelForm):
documento.tramitacao = False if tramitacao.status.indicador == "F" else True
documento.save()
lista_tramitacao = []
list_anexados = lista_anexados(documento, False)
for da in list_anexados:
if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
da.tramitacao = False if tramitacao.status.indicador == "F" else True
da.save()
lista_tramitacao.append(TramitacaoAdministrativo(
status=tramitacao.status,
documento=da,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip
))
TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao)
tramitar_anexados = AppConfig.attr('tramitacao_documento')
if tramitar_anexados:
lista_tramitacao = []
anexados_list = lista_anexados(documento, False)
for da in anexados_list:
if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
da.tramitacao = False if tramitacao.status.indicador == "F" else True
da.save()
lista_tramitacao.append(TramitacaoAdministrativo(
status=tramitacao.status,
documento=da,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip
))
TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao)
return tramitacao
@ -860,31 +879,32 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
@transaction.atomic
def save(self, commit=True):
# tram_principal = super(TramitacaoAdmEditForm, self).save(commit)
ant_tram_principal = TramitacaoAdministrativo.objects.get(id=self.instance.id)
nova_tram_principal = super(TramitacaoAdmEditForm, self).save(commit)
documento = nova_tram_principal.documento
documento.tramitacao = False if nova_tram_principal.status.indicador == "F" else True
documento.save()
list_anexados = lista_anexados(documento, False)
for da in list_anexados:
tram_anexada = da.tramitacaoadministrativo_set.last()
if compara_tramitacoes_doc(ant_tram_principal, tram_anexada):
tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local
tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento
tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino
tram_anexada.urgente = nova_tram_principal.urgente
tram_anexada.texto = nova_tram_principal.texto
tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo
tram_anexada.user = nova_tram_principal.user
tram_anexada.ip = nova_tram_principal.ip
tram_anexada.save()
da.tramitacao = False if nova_tram_principal.status.indicador == "F" else True
da.save()
tramitar_anexados = AppConfig.attr('tramitacao_documento')
if tramitar_anexados:
anexados_list = lista_anexados(documento, False)
for da in anexados_list:
tram_anexada = da.tramitacaoadministrativo_set.last()
if compara_tramitacoes_doc(ant_tram_principal, tram_anexada):
tram_anexada.status = nova_tram_principal.status
tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao
tram_anexada.unidade_tramitacao_local = nova_tram_principal.unidade_tramitacao_local
tram_anexada.data_encaminhamento = nova_tram_principal.data_encaminhamento
tram_anexada.unidade_tramitacao_destino = nova_tram_principal.unidade_tramitacao_destino
tram_anexada.urgente = nova_tram_principal.urgente
tram_anexada.texto = nova_tram_principal.texto
tram_anexada.data_fim_prazo = nova_tram_principal.data_fim_prazo
tram_anexada.user = nova_tram_principal.user
tram_anexada.ip = nova_tram_principal.ip
tram_anexada.save()
da.tramitacao = False if nova_tram_principal.status.indicador == "F" else True
da.save()
return nova_tram_principal
@ -1407,3 +1427,255 @@ class FichaSelecionaAdmForm(forms.Form):
form_actions(label='Gerar Impresso')
)
)
class PrimeiraTramitacaoEmLoteAdmFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
fields = ['tipo', 'data']
def __init__(self, *args, **kwargs):
super(PrimeiraTramitacaoEmLoteAdmFilterSet, self).__init__(
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Documento'
self.filters['data'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data'].required = False
row1 = to_row([('tipo', 12)])
row2 = to_row([('data', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Primeira Tramitação'),
row1, row2, form_actions(label='Pesquisar')))
class TramitacaoEmLoteAdmForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = TramitacaoAdministrativo
fields = ['data_tramitacao',
'unidade_tramitacao_local',
'status',
'urgente',
'unidade_tramitacao_destino',
'data_encaminhamento',
'data_fim_prazo',
'texto',
'user',
'ip']
widgets = {'user': forms.HiddenInput(),
'ip': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteAdmForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date()
ust = UnidadeTramitacao.objects.select_related().all()
unidade_tramitacao_destino = [('', '---------')] + [(ut.pk, ut)
for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.orgao])
unidade_tramitacao_destino.extend(
[(ut.pk, ut) for ut in ust if ut.parlamentar])
self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
self.fields['urgente'].label = "Urgente? *"
row1 = to_row([
('data_tramitacao', 4),
('data_encaminhamento', 4),
('data_fim_prazo', 4)
])
row2 = to_row([
('unidade_tramitacao_local', 6),
('unidade_tramitacao_destino', 6),
])
row3 = to_row([
('status', 6),
('urgente', 6)
])
row4 = to_row([
('texto', 12)
])
documentos_checkbox_HTML = '''
<br\><br\><br\>
<fieldset>
<legend style="font-size: 24px;">Selecione os documentos para tramitação:</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="documentos" value="{{documento.id}}" {% if check %} checked {% endif %}/>
<a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' documento.id %}">
{{documento.tipo.sigla}} {{documento.tipo.descricao}} {{documento.numero}}/{{documento.ano}}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
'''
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
'Detalhes da tramitação:',
row1, row2, row3, row4,
HTML(documentos_checkbox_HTML),
form_actions(label='Salvar')
)
)
def clean(self):
cleaned_data = super(TramitacaoEmLoteAdmForm, self).clean()
if not self.is_valid():
return self.cleaned_data
if 'data_encaminhamento' in cleaned_data:
data_enc_form = cleaned_data['data_encaminhamento']
if 'data_fim_prazo' in cleaned_data:
data_prazo_form = cleaned_data['data_fim_prazo']
if 'data_tramitacao' in cleaned_data:
data_tram_form = cleaned_data['data_tramitacao']
if not self.instance.data_tramitacao:
if cleaned_data['data_tramitacao'] > timezone.now().date():
self.logger.error('A data de tramitação ({}) deve ser '
'menor ou igual a data de hoje ({})!'
.format(cleaned_data['data_tramitacao'], timezone.now().date()))
msg = _(
'A data de tramitação deve ser ' +
'menor ou igual a data de hoje!')
raise ValidationError(msg)
if data_enc_form:
if data_enc_form < data_tram_form:
self.logger.error('A data de encaminhamento ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_enc_form, data_tram_form))
msg = _('A data de encaminhamento deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
if data_prazo_form:
if data_prazo_form < data_tram_form:
self.logger.error('A data fim de prazo ({}) deve ser '
'maior que a data de tramitação ({})!'
.format(data_prazo_form, data_tram_form))
msg = _('A data fim de prazo deve ser ' +
'maior que a data de tramitação!')
raise ValidationError(msg)
if cleaned_data['unidade_tramitacao_local'] == cleaned_data['unidade_tramitacao_destino']:
msg = _('Unidade tramitação local deve ser diferente da unidade tramitação destino.')
self.logger.error('Unidade tramitação local ({}) deve ser diferente da unidade tramitação destino'
.format(cleaned_data['unidade_tramitacao_local']))
raise ValidationError(msg)
return cleaned_data
@transaction.atomic
def save(self, commit=True):
cd = self.cleaned_data
documentos = self.initial['documentos']
user = self.initial['user'] if 'user' in self.initial else None
ip = self.initial['ip'] if 'ip' in self.initial else ''
tramitar_anexados = AppConfig.attr('tramitacao_documento')
for doc_id in documentos:
doc = DocumentoAdministrativo.objects.get(id=doc_id)
tramitacao = TramitacaoAdministrativo.objects.create(
status=cd['status'],
documento=doc,
data_tramitacao=cd['data_tramitacao'],
unidade_tramitacao_local=cd['unidade_tramitacao_local'],
unidade_tramitacao_destino=cd['unidade_tramitacao_destino'],
data_encaminhamento=cd['data_encaminhamento'],
urgente=cd['urgente'],
texto=cd['texto'],
data_fim_prazo=cd['data_fim_prazo'],
user=user,
ip=ip
)
doc.tramitacao = False if tramitacao.status.indicador == "F" else True
doc.save()
if tramitar_anexados:
lista_tramitacao = []
anexados = lista_anexados(doc, False)
for da in anexados:
if not da.tramitacaoadministrativo_set.all() \
or da.tramitacaoadministrativo_set.last() \
.unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local:
da.tramitacao = False if tramitacao.status.indicador == "F" else True
da.save()
lista_tramitacao.append(TramitacaoAdministrativo(
status=tramitacao.status,
documento=da,
data_tramitacao=tramitacao.data_tramitacao,
unidade_tramitacao_local=tramitacao.unidade_tramitacao_local,
data_encaminhamento=tramitacao.data_encaminhamento,
unidade_tramitacao_destino=tramitacao.unidade_tramitacao_destino,
urgente=tramitacao.urgente,
texto=tramitacao.texto,
data_fim_prazo=tramitacao.data_fim_prazo,
user=tramitacao.user,
ip=tramitacao.ip
))
TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao)
return tramitacao
class TramitacaoEmLoteAdmFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
fields = ['tipo', 'data', 'tramitacaoadministrativo__status',
'tramitacaoadministrativo__unidade_tramitacao_destino']
def __init__(self, *args, **kwargs):
super(TramitacaoEmLoteAdmFilterSet, self).__init__(
*args, **kwargs)
self.filters['tipo'].label = _('Tipo de Documento')
self.filters['data'].label = _('Data (Inicial - Final)')
self.filters['tramitacaoadministrativo__unidade_tramitacao_destino'
].label = _('Unidade Destino (Último Destino)')
self.filters['tramitacaoadministrativo__status'].label = _('Status')
self.form.fields['tipo'].required = True
self.form.fields['data'].required = False
self.form.fields['tramitacaoadministrativo__status'].required = True
self.form.fields[
'tramitacaoadministrativo__unidade_tramitacao_destino'].required = True
row1 = to_row([
('tipo', 4),
('tramitacaoadministrativo__unidade_tramitacao_destino', 4),
('tramitacaoadministrativo__status', 4)])
row2 = to_row([('data', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Tramitação em Lote'),
row1, row2, form_actions(label=_('Pesquisar'))))

521
sapl/protocoloadm/tests/test_protocoloadm.py

@ -1,10 +1,11 @@
from datetime import date, timedelta, datetime
from datetime import date, timedelta
from django.core.urlresolvers import reverse
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from model_mommy import mommy
from urllib.parse import urlencode
import pytest
from sapl.base.models import AppConfig
@ -15,7 +16,8 @@ from sapl.protocoloadm.forms import (AnularProtocoloAdmForm,
MateriaLegislativa, ProtocoloDocumentForm,
ProtocoloMateriaForm, TramitacaoAdmForm,
TramitacaoAdmEditForm,
compara_tramitacoes_doc)
compara_tramitacoes_doc,
TramitacaoEmLoteAdmForm)
from sapl.protocoloadm.models import (DocumentoAdministrativo, Protocolo,
StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo,
@ -532,6 +534,9 @@ def make_unidade_tramitacao(descricao):
@pytest.mark.django_db(transaction=False)
def test_tramitacoes_documentos_anexados(admin_client):
config = mommy.make(AppConfig, tramitacao_documento=True)
tipo_documento = mommy.make(
TipoDocumentoAdministrativo,
descricao="Tipo_Teste"
@ -703,3 +708,515 @@ def test_tramitacoes_documentos_anexados(admin_client):
response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True)
assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada.pk).count() == 0
assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada_anexada.pk).count() == 0
# Agora testando para caso não seja desejado tramitar os documentos anexados
# junto com os documentos principais
config.tramitacao_documento = False
config.save()
# Teste criação de Tramitacao
form = TramitacaoAdmForm(data={})
form.data = {'data_tramitacao':date(2019, 5, 6),
'unidade_tramitacao_local':unidade_tramitacao_local_1.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk,
'status':status.pk,
'urgente': False,
'texto': "Texto de teste"}
form.instance.documento_id=documento_principal.pk
assert form.is_valid()
tramitacao_principal = form.save()
tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last()
tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last()
# Verifica se não foram criadas as tramitações para os documentos anexados e anexados aos anexados
assert documento_principal.tramitacaoadministrativo_set.last() == tramitacao_principal
assert tramitacao_principal.documento.tramitacao == (tramitacao_principal.status.indicador != "F")
assert not tramitacao_anexada
assert not tramitacao_anexada_anexada
# Cria uma tramitação igual na tramitação anexada para testar a edição
form = TramitacaoAdmForm(data={})
form.data = {'data_tramitacao':date(2019, 5, 6),
'unidade_tramitacao_local':unidade_tramitacao_local_1.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_1.pk,
'status':status.pk,
'urgente': False,
'texto': "Texto de teste"}
form.instance.documento_id=documento_anexado.pk
assert form.is_valid()
tramitacao_anexada = form.save()
tramitacao_principal = documento_principal.tramitacaoadministrativo_set.last()
tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last()
assert documento_principal.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado.tramitacaoadministrativo_set.last() == tramitacao_anexada
assert not tramitacao_anexada_anexada
form = TramitacaoAdmEditForm(data={})
# Alterando unidade_tramitacao_destino da matéria principal,
# as anexadas não devem ser alteradas
form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao,
'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk,
'status':tramitacao_principal.status.pk,
'urgente': tramitacao_principal.urgente,
'texto': tramitacao_principal.texto}
form.instance = tramitacao_principal
assert form.is_valid()
tramitacao_principal = form.save()
tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last()
tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last()
assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_2
assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_1
assert not tramitacao_anexada_anexada
form = TramitacaoAdmEditForm(data={})
# Alterando a anexada da principal para testar a remoção de tramitação
form.data = {'data_tramitacao':tramitacao_principal.data_tramitacao,
'unidade_tramitacao_local':tramitacao_principal.unidade_tramitacao_local.pk,
'unidade_tramitacao_destino':unidade_tramitacao_destino_2.pk,
'status':tramitacao_principal.status.pk,
'urgente': tramitacao_principal.urgente,
'texto': tramitacao_principal.texto}
form.instance = tramitacao_anexada
assert form.is_valid()
tramitacao_anexada = form.save()
tramitacao_principal = documento_principal.tramitacaoadministrativo_set.last()
tramitacao_anexada_anexada = documento_anexado_anexado.tramitacaoadministrativo_set.last()
assert tramitacao_principal.unidade_tramitacao_destino == unidade_tramitacao_destino_2
assert tramitacao_anexada.unidade_tramitacao_destino == unidade_tramitacao_destino_2
assert not tramitacao_anexada_anexada
assert compara_tramitacoes_doc(tramitacao_anexada, tramitacao_principal)
# Removendo a tramitação principal, a tramitação anexada não deve ser removida
url = reverse('sapl.protocoloadm:tramitacaoadministrativo_delete',
kwargs={'pk': tramitacao_principal.pk})
response = admin_client.post(url, {'confirmar':'confirmar'} ,follow=True)
assert TramitacaoAdministrativo.objects.filter(id=tramitacao_principal.pk).count() == 0
assert TramitacaoAdministrativo.objects.filter(id=tramitacao_anexada.pk).count() == 1
@pytest.mark.django_db(transaction=False)
def test_tramitacao_lote_documentos_form(admin_client):
tipo_documento = mommy.make(
TipoDocumentoAdministrativo,
descricao="Tipo_Teste"
)
documento = mommy.make(
DocumentoAdministrativo,
numero=20,
ano=2018,
data="2019-05-16",
tipo=tipo_documento
)
unidade_tramitacao_local_1 = make_unidade_tramitacao(descricao="Teste 1")
unidade_tramitacao_destino_1 = make_unidade_tramitacao(descricao="Teste 2")
status = mommy.make(
StatusTramitacaoAdministrativo,
indicador='R')
# Form sem campos obrigatórios
documentos = []
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
errors = form.errors
assert errors['data_tramitacao'] == ['Este campo é obrigatório.']
assert errors['unidade_tramitacao_local'] == ['Este campo é obrigatório.']
assert errors['status'] == ['Este campo é obrigatório.']
assert errors['unidade_tramitacao_destino'] == ['Este campo é obrigatório.']
assert errors['texto'] == ['Este campo é obrigatório.']
assert not form.is_valid()
# Tramitar apenas um documento sem anexados
documentos = [documento.id]
now = timezone.now().date()
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
form.data = {'data_tramitacao': now + timedelta(days=5),
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa'}
assert form.errors['__all__'] == \
["A data de tramitação deve ser menor ou igual a data de hoje!"]
assert not form.is_valid()
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
form.data = {'data_tramitacao': '2019-05-14',
'data_encaminhamento' : '2019-05-09',
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa'}
assert form.errors['__all__'] == \
["A data de encaminhamento deve ser maior que a data de tramitação!"]
assert not form.is_valid()
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
form.data = {'data_tramitacao': '2019-05-14',
'data_encaminhamento' : '2019-05-15',
'data_fim_prazo': '2019-05-09',
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa'}
assert form.errors['__all__'] == \
["A data fim de prazo deve ser maior que a data de tramitação!"]
assert not form.is_valid()
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
form.data = {'data_tramitacao': '2019-05-14',
'data_encaminhamento' : '2019-05-15',
'data_fim_prazo': '2019-05-18',
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_local_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa'}
assert form.errors['__all__'] == \
["Unidade tramitação local deve ser diferente da unidade tramitação destino."]
assert not form.is_valid()
form = TramitacaoEmLoteAdmForm(initial={'documentos': documentos}, data={})
form.data = {'data_tramitacao': '2019-05-14',
'data_encaminhamento' : '2019-05-15',
'data_fim_prazo': '2019-05-18',
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa'}
assert form.is_valid()
@pytest.mark.django_db(transaction=False)
def test_tramitacao_lote_documentos_views(admin_client):
config = mommy.make(AppConfig, tramitacao_documento=True)
tipo_documento = mommy.make(
TipoDocumentoAdministrativo,
descricao="Tipo_Teste"
)
documento_principal = mommy.make(
DocumentoAdministrativo,
numero=20,
ano=2018,
data="2018-01-04",
tipo=tipo_documento
)
documento_anexado = mommy.make(
DocumentoAdministrativo,
numero=21,
ano=2019,
data="2019-05-04",
tipo=tipo_documento
)
documento_anexado_anexado = mommy.make(
DocumentoAdministrativo,
numero=22,
ano=2020,
data="2020-01-05",
tipo=tipo_documento
)
documento_sem_anexados = mommy.make(
DocumentoAdministrativo,
numero=23,
ano=2020,
data="2021-01-05",
tipo=tipo_documento
)
mommy.make(
Anexado,
documento_principal=documento_principal,
documento_anexado=documento_anexado,
data_anexacao="2019-05-11"
)
mommy.make(
Anexado,
documento_principal=documento_anexado,
documento_anexado=documento_anexado_anexado,
data_anexacao="2020-11-05"
)
unidade_tramitacao_local_1 = make_unidade_tramitacao(descricao="Teste 1")
unidade_tramitacao_destino_1 = make_unidade_tramitacao(descricao="Teste 2")
unidade_tramitacao_destino_2 = make_unidade_tramitacao(descricao="Teste 3")
unidade_tramitacao_destino_3 = make_unidade_tramitacao(descricao="Teste 4")
status = mommy.make(
StatusTramitacaoAdministrativo,
indicador='R')
url = reverse('sapl.protocoloadm:primeira_tramitacao_em_lote_docadm')
url = url + '?' + urlencode({'tipo':tipo_documento.id, 'data_0':'', 'data_1':''})
response = admin_client.post(url, {'salvar':'salvar'}, follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert len(msgs) == 1
assert msgs[0] == 'Escolha algum Documento para ser tramitado.'
documentos = [documento_sem_anexados.id, documento_anexado_anexado.id]
response = admin_client.post(url, {'documentos': documentos,'salvar':'salvar'}, follow=True)
msgs = [m.message for m in response.context['messages']]
assert 'Data Tramitação: Este campo é obrigatório.' in msgs
assert 'Unidade Local: Este campo é obrigatório.' in msgs
assert 'Status: Este campo é obrigatório.' in msgs
assert 'Unidade Destino: Este campo é obrigatório.' in msgs
assert 'Texto da Ação: Este campo é obrigatório.' in msgs
# Primeira tramitação em lote
response = admin_client.post(url,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
assert TramitacaoAdministrativo.objects.all().count() == 2
assert documento_sem_anexados.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 1
# Segunda tramitação em lote
url_lote = reverse('sapl.protocoloadm:tramitacao_em_lote_docadm')
url_lote = url_lote + '?' + urlencode(
{'tipo':tipo_documento.id,
'tramitacaoadministrativo__unidade_tramitacao_destino':unidade_tramitacao_destino_1.id,
'tramitacaoadministrativo__status': status.id,
'data_0':'',
'data_1':''})
response = admin_client.post(url_lote, {'salvar':'salvar'}, follow=True)
assert response.status_code == 200
assert response.context_data['object_list'].count() == 2
msgs = [m.message for m in response.context['messages']]
assert len(msgs) == 1
assert msgs[0] == 'Escolha algum Documento para ser tramitado.'
response = admin_client.post(url_lote, {'documentos':documentos, 'salvar':'salvar'}, follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert 'Data Tramitação: Este campo é obrigatório.' in msgs
assert 'Unidade Local: Este campo é obrigatório.' in msgs
assert 'Status: Este campo é obrigatório.' in msgs
assert 'Unidade Destino: Este campo é obrigatório.' in msgs
assert 'Texto da Ação: Este campo é obrigatório.' in msgs
response = admin_client.post(url_lote,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert 'Unidade tramitação local deve ser diferente da unidade tramitação destino.' in msgs
response = admin_client.post(url_lote,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert 'Tramitação completa.' in msgs
assert TramitacaoAdministrativo.objects.all().count() == 4
assert documento_sem_anexados.tramitacaoadministrativo_set.all().count() == 2
assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 2
# Tramitar documentos com anexados
# O documento anexado ao anexado não deve tramitar junto porque já está com tramitação diferente
documentos = [documento_principal.id]
response = admin_client.post(url,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
assert TramitacaoAdministrativo.objects.all().count() == 6
assert documento_principal.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado.tramitacaoadministrativo_set.all().count() == 1
# Segunda tramitação com documentos anexados
response = admin_client.post(url_lote,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert 'Tramitação completa.' in msgs
assert TramitacaoAdministrativo.objects.all().count() == 8
assert documento_principal.tramitacaoadministrativo_set.all().count() == 2
assert documento_anexado.tramitacaoadministrativo_set.all().count() == 2
# Terceira tramitação em lote
# Agora, o documento anexado ao anexado deve tramitar junto com o documento principal,
# pois suas tramitações convergiram
response = admin_client.post(url_lote,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_destino_2.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_3.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert 'Tramitação completa.' in msgs
assert TramitacaoAdministrativo.objects.all().count() == 11
assert documento_principal.tramitacaoadministrativo_set.all().count() == 3
assert documento_anexado.tramitacaoadministrativo_set.all().count() == 3
assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 3
# Agora testando para caso não seja desejado tramitar os documentos anexados
# junto com os documentos principais
config.tramitacao_documento = False
config.save()
TramitacaoAdministrativo.objects.all().delete()
assert TramitacaoAdministrativo.objects.all().count() == 0
# Primeira tramitação em lote
# Tramitar documentos com anexados
# O documento anexado não deve tramitar junto com o prinicpal
documentos = [documento_principal.id]
response = admin_client.post(url,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
assert TramitacaoAdministrativo.objects.all().count() == 1
assert documento_principal.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado.tramitacaoadministrativo_set.all().count() == 0
assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 0
# Tramitar o doc anexado ao principal para testar a segunda tramitação em lote
documentos = [documento_anexado.id]
response = admin_client.post(url,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_local_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_1.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
assert TramitacaoAdministrativo.objects.all().count() == 2
assert documento_principal.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 0
tramitacao_principal = documento_principal.tramitacaoadministrativo_set.last()
tramitacao_anexada = documento_anexado.tramitacaoadministrativo_set.last()
assert compara_tramitacoes_doc(tramitacao_anexada, tramitacao_principal)
documentos = [documento_principal.id]
# Segunda tramitação, o documento anexado não deve tramitar com o principal
response = admin_client.post(url_lote,
{'documentos': documentos,
'data_tramitacao': date(2019, 5, 15),
'unidade_tramitacao_local': unidade_tramitacao_destino_1.id,
'unidade_tramitacao_destino': unidade_tramitacao_destino_2.id,
'status': status.id,
'urgente': False,
'texto': 'aaaa',
'salvar':'salvar'},
follow=True)
assert response.status_code == 200
msgs = [m.message for m in response.context['messages']]
assert 'Tramitação completa.' in msgs
assert TramitacaoAdministrativo.objects.all().count() == 3
assert documento_principal.tramitacaoadministrativo_set.all().count() == 2
assert documento_anexado.tramitacaoadministrativo_set.all().count() == 1
assert documento_anexado_anexado.tramitacaoadministrativo_set.all().count() == 0

10
sapl/protocoloadm/urls.py

@ -22,7 +22,9 @@ from sapl.protocoloadm.views import (AcompanhamentoDocumentoView,
doc_texto_integral,
DesvincularDocumentoView,
DesvincularMateriaView,
AnexadoCrud, DocumentoAnexadoEmLoteView)
AnexadoCrud, DocumentoAnexadoEmLoteView,
PrimeiraTramitacaoEmLoteAdmView,
TramitacaoEmLoteAdmView)
from .apps import AppConfig
@ -98,6 +100,12 @@ urlpatterns_protocolo = [
url(r'^protocoloadm/recuperar-materia',
recuperar_materia_protocolo, name='recuperar_materia_protocolo'),
url(r'^protocoloadm/primeira-tramitacao-em-lote',
PrimeiraTramitacaoEmLoteAdmView.as_view(),
name='primeira_tramitacao_em_lote_docadm'),
url(r'^protocoloadm/tramitacao-em-lote', TramitacaoEmLoteAdmView.as_view(),
name='tramitacao_em_lote_docadm'),
]

206
sapl/protocoloadm/views.py

@ -24,18 +24,19 @@ from django_filters.views import FilterView
import sapl
from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.base.models import Autor, CasaLegislativa
from sapl.base.models import Autor, CasaLegislativa, AppConfig
from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao
from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination,
RP_LIST, RP_DETAIL)
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao
from sapl.materia.views import gerar_pdf_impressos
from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo
from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, lista_anexados,
show_results_filter_set, mail_service_configured)
from sapl.relatorios.views import relatorio_doc_administrativos
from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm,
DocumentoAcessorioAdministrativoForm,
@ -47,6 +48,9 @@ from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm,
filtra_tramitacao_adm_destino_and_status,
filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status,
AnexadoForm, AnexadoEmLoteFilterSet,
PrimeiraTramitacaoEmLoteAdmFilterSet,
TramitacaoEmLoteAdmForm,
TramitacaoEmLoteAdmFilterSet,
compara_tramitacoes_doc)
from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo, StatusTramitacaoAdministrativo,
@ -90,7 +94,7 @@ def doc_texto_integral(request, pk):
can_see = True
if not request.user.is_authenticated():
app_config = sapl.base.models.AppConfig.objects.last()
app_config = AppConfig.objects.last()
if app_config and app_config.documentos_administrativos == 'R':
can_see = False
@ -312,7 +316,7 @@ class AcompanhamentoDocumentoView(CreateView):
class DocumentoAdministrativoMixin:
def has_permission(self):
app_config = sapl.base.models.AppConfig.objects.last()
app_config = AppConfig.objects.last()
if app_config and app_config.documentos_administrativos == 'O':
return True
@ -541,7 +545,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
self.logger.debug("user=" + username +
". Tentando obter sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last(
numeracao = AppConfig.objects.last(
).sequencia_numeracao_protocolo
if not numeracao:
self.logger.error("user=" + username + ". É preciso definir a sequencia de "
@ -727,7 +731,7 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
username = self.request.user.username
self.logger.debug("user=" + username +
". Tentando obter sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last(
numeracao = AppConfig.objects.last(
).sequencia_numeracao_protocolo
if not numeracao:
self.logger.error("user=" + username + ". É preciso definir a sequencia de "
@ -898,17 +902,16 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
context = super(PesquisarDocumentoAdministrativoView,
self).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
if self.paginate_by:
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
return context
def get(self, request, *args, **kwargs):
super(PesquisarDocumentoAdministrativoView, self).get(request)
# Se a pesquisa estiver quebrando com a paginação
# Olhe esta função abaixo
# Provavelmente você criou um novo campo no Form/FilterSet
@ -921,9 +924,7 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
url = url[ponto_comeco:]
else:
url = ''
self.filterset.form.fields['o'].label = _('Ordenação')
# é usada essa verificação anônima para quando os documentos administrativos
# estão no modo ostensivo, mas podem existir documentos administrativos
# restritos
@ -931,18 +932,21 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
length = self.object_list.filter(restrito=False).count()
else:
length = self.object_list.count()
is_relatorio = url!='' and request.GET.get('relatorio',None)
self.paginate_by = None if is_relatorio else self.paginate_by
context = self.get_context_data(filter=self.filterset,
filter_url=url,
numero_res=length
)
context['show_results'] = show_results_filter_set(
self.request.GET.copy())
return self.render_to_response(context)
if is_relatorio:
return relatorio_doc_administrativos(request,context)
else:
return self.render_to_response(context)
class AnexadoCrud(MasterDetailCrud):
model = Anexado
parent_field = 'documento_principal'
@ -1087,7 +1091,7 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
msg = _('Documento(s) anexado(s).')
messages.add_message(request, messages.SUCCESS, msg)
success_url = reverse('sapl_index') + 'docadm/' + kwargs['pk'] + '/anexado'
success_url = reverse('sapl.protocoloadm:anexado_list', kwargs={'pk': kwargs['pk']})
return HttpResponseRedirect(success_url)
@ -1251,12 +1255,21 @@ class TramitacaoAdmCrud(MasterDetailCrud):
return HttpResponseRedirect(url)
else:
tramitacoes_deletar = [tramitacao.id]
docs_anexados = lista_anexados(documento, False)
for da in docs_anexados:
tram_anexada = da.tramitacaoadministrativo_set.last()
if compara_tramitacoes_doc(tram_anexada, tramitacao):
tramitacoes_deletar.append(tram_anexada.id)
if documento.tramitacaoadministrativo_set.count() == 0:
documento.tramitacao = False
documento.save()
tramitar_anexados = AppConfig.attr('tramitacao_documento')
if tramitar_anexados:
docs_anexados = lista_anexados(documento, False)
for da in docs_anexados:
tram_anexada = da.tramitacaoadministrativo_set.last()
if compara_tramitacoes_doc(tram_anexada, tramitacao):
tramitacoes_deletar.append(tram_anexada.id)
if da.tramitacaoadministrativo_set.count() == 0:
da.tramitacao = False
da.save()
TramitacaoAdministrativo.objects.filter(id__in=tramitacoes_deletar).delete()
return HttpResponseRedirect(url)
@ -1437,3 +1450,142 @@ class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
return gerar_pdf_impressos(self.request, context,
'materia/impressos/ficha_adm_pdf.html')
class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
filterset_class = PrimeiraTramitacaoEmLoteAdmFilterSet
template_name = 'protocoloadm/em_lote/tramitacaoadm.html'
permission_required = ('materia.add_tramitacao', )
primeira_tramitacao = True
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteAdmView,
self).get_context_data(**kwargs)
context['subnav_template_name'] = 'protocoloadm/em_lote/subnav_em_lote.yaml'
context['primeira_tramitacao'] = self.primeira_tramitacao
# Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid():
return context
context['object_list'] = context['object_list'].order_by(
'ano', 'numero')
qr = self.request.GET.copy()
form = TramitacaoEmLoteAdmForm()
context['form'] = form
if self.primeira_tramitacao:
context['title'] = _('Primeira Tramitação em Lote')
# Pega somente documentos que não possuem tramitação
context['object_list'] = [obj for obj in context['object_list']
if obj.tramitacaoadministrativo_set.all().count() == 0]
else:
context['title'] = _('Tramitação em Lote')
context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
id=qr['tramitacaoadministrativo__unidade_tramitacao_destino'])
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
return context
def post(self, request, *args, **kwargs):
user = request.user
ip = get_client_ip(request)
documentos_ids = request.POST.getlist('documentos')
if not documentos_ids:
msg = _("Escolha algum Documento para ser tramitado.")
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
form = TramitacaoEmLoteAdmForm(request.POST,
initial= {'documentos': documentos_ids,
'user': user, 'ip':ip})
if form.is_valid():
form.save()
msg = _('Tramitação completa.')
self.logger.info('user=' + user.username + '. Tramitação completa.')
messages.add_message(request, messages.SUCCESS, msg)
return self.get_success_url()
return self.form_invalid(form)
def get_success_url(self):
return HttpResponseRedirect(reverse('sapl.protocoloadm:primeira_tramitacao_em_lote_docadm'))
def form_invalid(self, form, *args, **kwargs):
for key, erros in form.errors.items():
if not key=='__all__':
[messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
else:
[messages.add_message(self.request, messages.ERROR, e) for e in erros]
return self.get(self.request, kwargs, {'form':form})
class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
filterset_class = TramitacaoEmLoteAdmFilterSet
primeira_tramitacao = False
def get_context_data(self, **kwargs):
context = super(TramitacaoEmLoteAdmView,
self).get_context_data(**kwargs)
qr = self.request.GET.copy()
context['primeira_tramitacao'] = False
if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and
qr['tramitacao__status'] and
qr['tramitacao__unidade_tramitacao_destino']):
lista = self.filtra_tramitacao_destino_and_status(
qr['tramitacao__status'],
qr['tramitacao__unidade_tramitacao_destino'])
context['object_list'] = context['object_list'].filter(
id__in=lista).distinct()
return context
def pega_ultima_tramitacao(self):
return TramitacaoAdministrativo.objects.values(
'documento_id').annotate(data_encaminhamento=Max(
'data_encaminhamento'),
id=Max('id')).values_list('id', flat=True)
def filtra_tramitacao_status(self, status):
lista = self.pega_ultima_tramitacao()
return TramitacaoAdministrativo.objects.filter(
id__in=lista,
status=status).distinct().values_list('documento_id', flat=True)
def filtra_tramitacao_destino(self, destino):
lista = self.pega_ultima_tramitacao()
return TramitacaoAdministrativo.objects.filter(
id__in=lista,
unidade_tramitacao_destino=destino).distinct().values_list(
'documento_id', flat=True)
def filtra_tramitacao_destino_and_status(self, status, destino):
lista = self.pega_ultima_tramitacao()
return TramitacaoAdministrativo.objects.filter(
id__in=lista,
status=status,
unidade_tramitacao_destino=destino).distinct().values_list(
'documento_id', flat=True)

2
sapl/relatorios/templates/pdf_pauta_sessao_gerar.py

@ -76,7 +76,7 @@ def paraStyle():
tmp += '\t\t\t<paraStyle name="all" alignment="justify"/>\n'
tmp += '\t\t</initialize>\n'
tmp += '\t\t<paraStyle name="style.Title" fontName="Helvetica" fontSize="11" leading="13" alignment="RIGHT"/>\n'
tmp += '\t\t<paraStyle name="P1" fontName="Helvetica-Bold" fontSize="12.0" textColor="silver" leading="14" spaceBefore="12" alignment="LEFT"/>\n'
tmp += '\t\t<paraStyle name="P1" fontName="Helvetica-Bold" fontSize="12.0" textColor="#444444" leading="14" spaceBefore="12" alignment="LEFT"/>\n'
tmp += '\t\t<paraStyle name="P2" fontName="Helvetica" fontSize="10.0" leading="10" alignment="JUSTIFY"/>\n'
tmp += '\t\t<paraStyle name="P3" fontName="Helvetica" fontSize="9" leading="10" spaceAfter="3" alignment="LEFT"/>\n'
tmp += '\t\t<paraStyle name="P4" fontName="Helvetica" fontSize="8" leading="9" spaceAfter="3" alignment="JUSTIFY"/>\n'

422
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -103,9 +103,9 @@ def inf_basicas(inf_basicas_dic):
"""
tmp = ""
nom_sessao = inf_basicas_dic['nom_sessao']
num_sessao_plen = inf_basicas_dic["num_sessao_plen"]
num_sessao_leg = inf_basicas_dic["num_sessao_leg"]
num_legislatura = inf_basicas_dic["num_legislatura"]
# num_sessao_plen = inf_basicas_dic["num_sessao_plen"]
# num_sessao_leg = inf_basicas_dic["num_sessao_leg"]
# num_legislatura = inf_basicas_dic["num_legislatura"]
dat_inicio_sessao = inf_basicas_dic["dat_inicio_sessao"]
hr_inicio_sessao = inf_basicas_dic["hr_inicio_sessao"]
dat_fim_sessao = inf_basicas_dic["dat_fim_sessao"]
@ -113,17 +113,21 @@ def inf_basicas(inf_basicas_dic):
if hr_fim_sessao is None:
hr_fim_sessao = ''
tmp += '\t\t<para style="P1">Informações Básicas</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Tipo da Sessão: </b> ' + \
nom_sessao + '</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Abertura: </b> ' + \
dat_inicio_sessao + ' <b>- </b> ' + hr_inicio_sessao + '</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Encerramento: </b> ' + \
dat_fim_sessao + ' <b>- </b> ' + hr_fim_sessao + '</para>\n'
if nom_sessao or dat_inicio_sessao or hr_inicio_sessao \
or dat_fim_sessao or hr_fim_sessao:
tmp += '\t\t<para style="P1">Informações Básicas</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
if nom_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Tipo da Sessão: </b> ' + \
nom_sessao + '</para>\n'
if hr_inicio_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Abertura: </b> ' + \
dat_inicio_sessao + ' <b>- </b> ' + hr_inicio_sessao + '</para>\n'
if dat_fim_sessao or hr_fim_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Encerramento: </b> ' + \
dat_fim_sessao + ' <b>- </b> ' + hr_fim_sessao + '</para>\n'
return tmp
@ -136,277 +140,259 @@ def multimidia(cont_mult_dic):
mul_audio = cont_mult_dic['multimidia_audio']
mul_video = cont_mult_dic['multimidia_video']
tmp += '\t\t<para style="P1">Conteúdo Multimídia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Audio: </b> ' + mul_audio + '</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Video: </b> ' + mul_video + '</para>\n'
if mul_audio or mul_video:
tmp += '\t\t<para style="P1">Conteúdo Multimídia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
if mul_audio:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Audio: </b> ' + mul_audio + '</para>\n'
if mul_video:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Video: </b> ' + mul_video + '</para>\n'
return tmp
def mesa(lst_mesa):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Mesa Diretora</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for mesa in lst_mesa:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
str(mesa['des_cargo']) + ':</b> ' + str(mesa['nom_parlamentar']
) + '/' + str(mesa['sgl_partido']) + '</para>\n'
if lst_mesa:
tmp += '\t\t<para style="P1">Mesa Diretora</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for mesa in lst_mesa:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
str(mesa['des_cargo']) + ':</b> ' + str(mesa['nom_parlamentar']
) + '/' + str(mesa['sgl_partido']) + '</para>\n'
return tmp
def presenca(lst_presenca_sessao, lst_ausencia_sessao):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Lista de Presença da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for presenca in lst_presenca_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \
str(presenca['nom_parlamentar']) + '/' + \
str(presenca['sgl_partido']) + '</para>\n'
tmp += '\t\t<para style="P1">Justificativas de Ausência da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Parlamentar</td><td>Justificativa</td><td>Ausente em</td></tr>\n'
for ausencia in lst_ausencia_sessao:
tmp += '<tr><td>' + \
str(ausencia['parlamentar']) + '</td><td> ' + \
str(ausencia['justificativa']) + '</td><td>' + \
str(ausencia['tipo']) + '</td></tr>\n'
tmp += '</blockTable>'
if lst_presenca_sessao or lst_ausencia_sessao:
if lst_ausencia_sessao:
tmp += '\t\t<para style="P1">Lista de Presença da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for presenca in lst_presenca_sessao:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \
str(presenca['nom_parlamentar']) + '/' + \
str(presenca['sgl_partido']) + '</para>\n'
if lst_ausencia_sessao:
tmp += '\t\t<para style="P1">Justificativas de Ausência da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Parlamentar</td><td>Justificativa</td><td>Ausente em</td></tr>\n'
for ausencia in lst_ausencia_sessao:
tmp += '<tr><td>' + \
str(ausencia['parlamentar']) + '</td><td> ' + \
str(ausencia['justificativa']) + '</td><td>' + \
str(ausencia['tipo']) + '</td></tr>\n'
tmp += '</blockTable>'
return tmp
def expedientes(lst_expedientes):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Expedientes</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
for expediente in lst_expedientes:
tmp += '\t\t<para style="P2"><b>' + '<br/> ' + \
expediente['nom_expediente'] + ': </b></para>\n' + \
'<para style="P3">' + \
expediente['txt_expediente'] + '</para>\n'
if lst_expedientes:
tmp += '\t\t<para style="P1">Expedientes</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
for expediente in lst_expedientes:
tmp += '\t\t<para style="P2"><b>' + '<br/> ' + \
expediente['nom_expediente'] + ': </b></para>\n' + \
'<para style="P3">' + \
expediente['txt_expediente'] + '</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
return tmp
def expediente_materia(lst_expediente_materia):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1" colWidths="3.5cm,11.5cm,3.5cm">>\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for expediente_materia in lst_expediente_materia:
tmp += '<tr><td><para style="P3"><b>' + str(expediente_materia['num_ordem']) + '</b> - ' + expediente_materia['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno: </b>' + expediente_materia[
'des_turno'] + '</para>\n' + '<para style="P3"><b>' + expediente_materia['num_autores'] + ': </b>' + str(expediente_materia['nom_autor']) + '</para></td>\n'
txt_ementa = expediente_materia['txt_ementa'].replace('&', '&amp;')
# txt_ementa = dont_break_out(expediente_materia['txt_ementa'])
# if len(txt_ementa) > 800:
# txt_ementa = txt_ementa[:800] + "..."
tmp += '<td><para style="P4">' + txt_ementa + '</para>' + '<para style="P4">' + expediente_materia['ordem_observacao'] + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(expediente_materia['nom_resultado']) + \
'</b></para>\n' + '<para style="P3">'
if expediente_materia['votacao_observacao'] != txt_ementa:
tmp += str(expediente_materia['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n'
if lst_expediente_materia:
tmp += '\t\t<para style="P1">Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1" colWidths="3.5cm,11.5cm,3.5cm">>\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for expediente_materia in lst_expediente_materia:
tmp += '<tr><td><para style="P3"><b>' + str(expediente_materia['num_ordem']) + '</b> - ' + expediente_materia['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno: </b>' + expediente_materia[
'des_turno'] + '</para>\n' + '<para style="P3"><b>' + expediente_materia['num_autores'] + ': </b>' + str(expediente_materia['nom_autor']) + '</para></td>\n'
txt_ementa = expediente_materia['txt_ementa'].replace('&', '&amp;')
# txt_ementa = dont_break_out(expediente_materia['txt_ementa'])
# if len(txt_ementa) > 800:
# txt_ementa = txt_ementa[:800] + "..."
tmp += '<td><para style="P4">' + txt_ementa + '</para>' + '<para style="P4">' + expediente_materia['ordem_observacao'] + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(expediente_materia['nom_resultado']) + \
'</b></para>\n' + '<para style="P3">'
if expediente_materia['votacao_observacao'] != txt_ementa:
tmp += str(expediente_materia['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
def expediente_materia_vot_nom(lst_expediente_materia_vot_nom):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Votações Nominais - Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Votos</td></tr>\n'
for expediente_materia_vot_nom in lst_expediente_materia_vot_nom:
tmp += '<tr><td><para style="P3">' + str(expediente_materia_vot_nom['titulo']) + '</para></td>'
if expediente_materia_vot_nom['votos']:
tmp += '<td>'
for v in expediente_materia_vot_nom['votos']:
tmp += '<para style="P3"><b>' + str(v.parlamentar) + '</b> - ' + v.voto + '</para>'
tmp += '</td>'
else:
tmp += '<td><para style="P3"><b>Matéria não votada</b></para></td>'
tmp += '</tr>\n'
tmp += '\t\t</blockTable>\n'
if lst_expediente_materia_vot_nom:
tmp += '\t\t<para style="P1">Votações Nominais - Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Votos</td></tr>\n'
for expediente_materia_vot_nom in lst_expediente_materia_vot_nom:
tmp += '<tr><td><para style="P3">' + str(expediente_materia_vot_nom['titulo']) + '</para></td>'
if expediente_materia_vot_nom['votos']:
tmp += '<td>'
for v in expediente_materia_vot_nom['votos']:
tmp += '<para style="P3"><b>' + str(v.parlamentar) + '</b> - ' + v.voto + '</para>'
tmp += '</td>'
else:
tmp += '<td><para style="P3"><b>Matéria não votada</b></para></td>'
tmp += '</tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
def oradores_expediente(lst_oradores_expediente):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Oradores do Expediente</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador_expediente in lst_oradores_expediente:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + str(orador_expediente[
'num_ordem']) + '</b> - ' + orador_expediente[
'nom_parlamentar'] + '/' + str(orador_expediente[
'sgl_partido']) + ' - ' + str(orador_expediente[
'observacao']) + '</para>\n'
if lst_oradores_expediente:
tmp += '\t\t<para style="P1">Oradores do Expediente</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador_expediente in lst_oradores_expediente:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + str(orador_expediente[
'num_ordem']) + '</b> - ' + orador_expediente[
'nom_parlamentar'] + '/' + str(orador_expediente[
'sgl_partido']) + ' - ' + str(orador_expediente[
'observacao']) + '</para>\n'
return tmp
def presenca_ordem_dia(lst_presenca_ordem_dia):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Lista de Presença da Ordem do Dia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for presenca_ordem_dia in lst_presenca_ordem_dia:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \
str(presenca_ordem_dia['nom_parlamentar']) + '/' + \
str(presenca_ordem_dia['sgl_partido']) + '</para>\n'
if lst_presenca_ordem_dia:
tmp += '\t\t<para style="P1">Lista de Presença da Ordem do Dia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for presenca_ordem_dia in lst_presenca_ordem_dia:
tmp += '\t\t<para style="P2" spaceAfter="5">' + \
str(presenca_ordem_dia['nom_parlamentar']) + '/' + \
str(presenca_ordem_dia['sgl_partido']) + '</para>\n'
return tmp
def votacao(lst_votacao):
"""
"""
tmp = ''
tmp += '<para style="P1">Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for votacao in lst_votacao:
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + votacao['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno:</b> ' + votacao[
'des_turno'] + '</para>\n' + '<para style="P3"><b>' + votacao['num_autores'] + ': </b>' + str(votacao['nom_autor']) + '</para></td>\n'
txt_ementa = votacao['txt_ementa'].replace('&', '&amp;')
if len(txt_ementa) > 1000:
txt_ementa = txt_ementa[:1000] + "..."
tmp += '<td><para style="P4">' + txt_ementa + '</para>' + '<para style="P4">' + votacao['ordem_observacao'] + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(votacao['nom_resultado']) + \
'</b></para>\n' + '<para style="P3">'
if votacao['votacao_observacao'] != txt_ementa:
tmp += str(votacao['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n'
if lst_votacao:
tmp += '<para style="P1">Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for votacao in lst_votacao:
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + votacao['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno:</b> ' + votacao[
'des_turno'] + '</para>\n' + '<para style="P3"><b>' + votacao['num_autores'] + ': </b>' + str(votacao['nom_autor']) + '</para></td>\n'
txt_ementa = votacao['txt_ementa'].replace('&', '&amp;')
if len(txt_ementa) > 1000:
txt_ementa = txt_ementa[:1000] + "..."
tmp += '<td><para style="P4">' + txt_ementa + '</para>' + '<para style="P4">' + votacao['ordem_observacao'] + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(votacao['nom_resultado']) + \
'</b></para>\n' + '<para style="P3">'
if votacao['votacao_observacao'] != txt_ementa:
tmp += str(votacao['votacao_observacao'])
else:
tmp += ' '
tmp += '</para></td></tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
def votacao_vot_nom(lst_votacao_vot_nom):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Votações Nominais - Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Votos</td></tr>\n'
for votacao_vot_nom in lst_votacao_vot_nom:
tmp += '<tr><td><para style="P3">' + str(votacao_vot_nom['titulo']) + '</para></td>'
if votacao_vot_nom['votos']:
tmp += '<td>'
for v in votacao_vot_nom['votos']:
tmp += '<para style="P3"><b>' + str(v.parlamentar) + '</b> - ' + v.voto + '</para>'
tmp += '</td>'
else:
tmp += '<td><para style="P3"><b>Matéria não votada</b></para></td>'
tmp += '</tr>\n'
tmp += '\t\t</blockTable>\n'
if lst_votacao_vot_nom:
tmp += '\t\t<para style="P1">Votações Nominais - Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Votos</td></tr>\n'
for votacao_vot_nom in lst_votacao_vot_nom:
tmp += '<tr><td><para style="P3">' + str(votacao_vot_nom['titulo']) + '</para></td>'
if votacao_vot_nom['votos']:
tmp += '<td>'
for v in votacao_vot_nom['votos']:
tmp += '<para style="P3"><b>' + str(v.parlamentar) + '</b> - ' + v.voto + '</para>'
tmp += '</td>'
else:
tmp += '<td><para style="P3"><b>Matéria não votada</b></para></td>'
tmp += '</tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
def oradores_ordemdia(lst_oradores_ordemdia):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Oradores da Ordem do Dia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador_ordemdia in lst_oradores_ordemdia:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
str(orador_ordemdia['num_ordem']) + '</b> - ' + \
orador_ordemdia['nome_parlamentar'] + '/' + \
str(orador_ordemdia['sigla']) + ' - ' + \
str(orador_ordemdia['observacao']) + '</para>\n'
if lst_oradores_ordemdia:
tmp += '\t\t<para style="P1">Oradores da Ordem do Dia</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador_ordemdia in lst_oradores_ordemdia:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
str(orador_ordemdia['num_ordem']) + '</b> - ' + \
orador_ordemdia['nome_parlamentar'] + '/' + \
str(orador_ordemdia['sigla']) + ' - ' + \
str(orador_ordemdia['observacao']) + '</para>\n'
return tmp
def oradores(lst_oradores):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Oradores das Explicações Pessoais</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador in lst_oradores:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
str(orador['num_ordem']) + '</b> - ' + orador['nom_parlamentar'] + \
'/' + str(orador['sgl_partido']) + '</para>\n'
if lst_oradores:
tmp += '\t\t<para style="P1">Oradores das Explicações Pessoais</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
for orador in lst_oradores:
tmp += '\t\t<para style="P2" spaceAfter="5"><b>' + \
str(orador['num_ordem']) + '</b> - ' + orador['nom_parlamentar'] + \
'/' + str(orador['sgl_partido']) + '</para>\n'
return tmp
def ocorrencias(lst_ocorrencias):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Ocorrências da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
for ocorrencia in lst_ocorrencias:
tmp += '\t\t<para style="P3">' + \
str(ocorrencia.conteudo) + '</para>\n'
if lst_ocorrencias:
tmp += '\t\t<para style="P1">Ocorrências da Sessão</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
for ocorrencia in lst_ocorrencias:
tmp += '\t\t<para style="P3">' + \
str(ocorrencia.conteudo) + '</para>\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> </font>\n'
tmp += '\t\t</para>\n'
return tmp

26
sapl/relatorios/views.py

@ -1325,4 +1325,28 @@ def resumo_ata_pdf(request,pk):
response['Content-Transfer-Encoding'] = 'binary'
response.write(pdf_file)
return response
return response
def relatorio_doc_administrativos(request, context):
base_url = request.build_absolute_uri()
casa = CasaLegislativa.objects.first()
rodape = ' '.join(get_rodape(casa))
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_doc_administrativos.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

1
sapl/rules/map_rules.py

@ -103,6 +103,7 @@ rules_group_protocolo = {
rules_group_comissoes = {
'group': SAPL_GROUP_COMISSOES,
'rules': [
(materia.PautaReuniao, __base__, __perms_publicas__),
(comissoes.Comissao, __base__, __perms_publicas__),
(comissoes.Composicao, __base__, __perms_publicas__),
(comissoes.Participacao, __base__, __perms_publicas__),

67
sapl/sessao/forms.py

@ -256,9 +256,15 @@ class RetiradaPautaForm(ModelForm):
def save(self, commit=False):
retirada = super(RetiradaPautaForm, self).save(commit=commit)
if retirada.ordem:
retirada.materia = retirada.ordem.materia
ordem = retirada.ordem
retirada.materia = ordem.materia
ordem.votacao_aberta = False
ordem.save()
elif retirada.expediente:
retirada.materia = retirada.expediente.materia
expediente = retirada.expediente
retirada.materia = expediente.materia
expediente.votacao_aberta = False
expediente.save()
retirada.save()
return retirada
@ -631,19 +637,11 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
class OradorForm(ModelForm):
def __init__(self, *args, **kwargs):
super(OradorForm, self).__init__(*args, **kwargs)
id_sessao = int(self.initial['id_sessao'])
ids = [s.parlamentar.id for
s in SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=id_sessao)]
super().__init__(*args, **kwargs)
self.fields['parlamentar'].queryset = \
Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
self.fields['parlamentar'].queryset = Parlamentar.objects.filter(
id__in=ids).order_by('nome_parlamentar')
def clean(self):
super(OradorForm, self).clean()
cleaned_data = self.cleaned_data
@ -659,30 +657,23 @@ class OradorForm(ModelForm):
numero_ordem=numero_ordem
).exists()
if ordem and numero_ordem != numero:
if ordem and numero_ordem != numero:
raise ValidationError(_(
"Já existe orador nesta posição de ordem de pronunciamento"
))
return self.cleaned_data
class Meta:
model = Orador
exclude = ['sessao_plenaria']
class OradorExpedienteForm(ModelForm):
def __init__(self, *args, **kwargs):
super(OradorExpedienteForm, self).__init__(*args, **kwargs)
legislatura_vigente = SessaoPlenaria.objects.get(
pk=kwargs['initial']['id_sessao']).legislatura
if legislatura_vigente:
self.fields['parlamentar'].queryset = \
Parlamentar.objects.filter(ativo=True,
mandato__legislatura=legislatura_vigente
).order_by('nome_parlamentar')
super().__init__(*args, **kwargs)
self.fields['parlamentar'].queryset = \
Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
def clean(self):
super(OradorExpedienteForm, self).clean()
@ -692,7 +683,7 @@ class OradorExpedienteForm(ModelForm):
return self.cleaned_data
sessao_id = self.initial['id_sessao']
numero = self.initial.get('numero') # Retorna None se inexistente
numero = self.initial.get('numero', None)
ordem = OradorExpediente.objects.filter(
sessao_plenaria_id=sessao_id,
numero_ordem=cleaned_data['numero_ordem']
@ -710,20 +701,10 @@ class OradorExpedienteForm(ModelForm):
class OradorOrdemDiaForm(ModelForm):
def __init__(self, *args, **kwargs):
super(OradorOrdemDiaForm, self).__init__(*args, **kwargs)
id_sessao = int(self.initial['id_sessao'])
ids = [p.parlamentar.id for p in PresencaOrdemDia.objects.filter(
sessao_plenaria_id=id_sessao
)]
self.fields['parlamentar'].queryset = Parlamentar.objects.filter(
id__in=ids
).order_by('nome_parlamentar')
super().__init__(*args, **kwargs)
self.fields['parlamentar'].queryset = \
Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
def clean(self):
super(OradorOrdemDiaForm, self).clean()
@ -740,11 +721,11 @@ class OradorOrdemDiaForm(ModelForm):
numero_ordem=numero_ordem
).exists()
if ordem and numero_ordem != numero:
if ordem and numero_ordem != numero:
raise ValidationError(_(
"Já existe orador nesta posição de ordem de pronunciamento"
))
return self.cleaned_data
class Meta:
@ -849,7 +830,7 @@ class ResumoOrdenacaoForm(forms.Form):
self.helper.layout = Layout(
Fieldset(_(''),
row1, row2, row3, row4, row5,
row6, row7, row8, row9, row10,
row6, row7, row8, row9, row10,
row11, row12, row13, row14,
form_actions(label='Atualizar'))
)

23
sapl/sessao/migrations/0040_auto_20190523_1130.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-23 14:30
from __future__ import unicode_literals
from django.db import migrations
def unifica_opcaoes_ordenacao_resumo(apps, schema_editor):
ResumoOrdenacao = apps.get_model('sessao', 'ResumoOrdenacao')
ro = ResumoOrdenacao.objects.get_or_create()[0]
if 'oradores_o_d' not in ro.__dict__:
ro.decimo_quarto = 'oradores_o_d'
ro.save()
class Migration(migrations.Migration):
dependencies = [
('sessao', '0039_auto_20190430_0825'),
]
operations = [
migrations.RunPython(unifica_opcaoes_ordenacao_resumo)
]

3
sapl/sessao/tests/test_sessao_view.py

@ -146,5 +146,4 @@ class TestResumoView():
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
assert resultado_get_ocorrencia['ocorrencias_da_sessao'][0] == ocorrencia

147
sapl/sessao/views.py

@ -587,7 +587,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
class OradorCrud(MasterDetailCrud):
model = ''
model = Orador
parent_field = 'sessao_plenaria'
help_topic = 'sessao_plenaria_oradores'
public = [RP_LIST, RP_DETAIL]
@ -596,6 +596,30 @@ class OradorCrud(MasterDetailCrud):
ordering = ['numero_ordem', 'parlamentar']
class CreateView(MasterDetailCrud.CreateView):
form_class = OradorForm
def get_initial(self):
return {'id_sessao': self.kwargs['pk']}
def get_success_url(self):
return reverse('sapl.sessao:orador_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorForm
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero':self.object.numero_ordem})
return initial
class OradorExpedienteCrud(OradorCrud):
model = OradorExpediente
@ -643,32 +667,6 @@ class OradorOrdemDiaCrud(OradorCrud):
return initial
class OradorCrud(OradorCrud):
model = Orador
class CreateView(MasterDetailCrud.CreateView):
form_class = OradorForm
def get_initial(self):
return {'id_sessao': self.kwargs['pk']}
def get_success_url(self):
return reverse('sapl.sessao:orador_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorForm
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero':self.object.numero_ordem})
return initial
class BancadaCrud(CrudAux):
model = Bancada
@ -1491,8 +1489,7 @@ def get_assinaturas(sessao_plenaria):
parlamentares_ordem = [p for p in parlamentares_ordem if p not in parlamentares_mesa]
context = {}
config_assinatura_ata = AppsAppConfig.objects.first().assinatura_ata
config_assinatura_ata = AppsAppConfig.attr('assinatura_ata')
if config_assinatura_ata == 'T' and parlamentares_ordem:
context.update(
{'texto_assinatura': 'Assinatura de Todos os Parlamentares Presentes na Sessão'})
@ -1758,23 +1755,42 @@ class ResumoView(DetailView):
}
ordenacao = ResumoOrdenacao.objects.get_or_create()[0]
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],
'decimo_quarto_ordenacao': dict_ord_template[ordenacao.decimo_quarto]
})
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],
'decimo_quarto_ordenacao': dict_ord_template[ordenacao.decimo_quarto]
})
except KeyError as e:
self.logger.error("KeyError: " + str(e) + ". Erro ao tentar utilizar "
"configuração de ordenação. Utilizando ordenação padrão.")
context.update({
'primeiro_ordenacao': 'identificacao_basica.html',
'segundo_ordenacao': 'conteudo_multimidia.html',
'terceiro_ordenacao': 'mesa_diretora.html',
'quarto_ordenacao': 'lista_presenca.html',
'quinto_ordenacao': 'expedientes.html',
'sexto_ordenacao': 'materias_expediente.html',
'setimo_ordenacao': 'votos_nominais_materias_expediente.html',
'oitavo_ordenacao': 'oradores_expediente.html',
'nono_ordenacao': 'lista_presenca_ordem_dia.html',
'decimo_ordenacao': 'materias_ordem_dia.html',
'decimo_primeiro_ordenacao': 'votos_nominais_materias_ordem_dia.html',
'decimo_segundo_ordenacao': 'oradores_ordemdia.html',
'decimo_terceiro_ordenacao': 'oradores_explicacoes.html',
'decimo_quarto_ordenacao': 'ocorrencias_da_sessao.html'
})
return context
def get(self, request, *args, **kwargs):
@ -3480,16 +3496,14 @@ class JustificativaAusenciaCrud(MasterDetailCrud):
class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView):
model = ExpedienteMateria
template_name = 'sessao/votacao/votacao_bloco_expediente.html'
template_name = 'sessao/votacao/votacao_bloco.html'
app_label = AppConfig.label
context_object_name = 'expedientes'
logger = logging.getLogger(__name__)
expediente = True
def get_queryset(self):
return ExpedienteMateria.objects.filter(sessao_plenaria_id=self.kwargs['pk'],
resultado='')
resultado='',
retiradapauta=None)
def get_context_data(self, **kwargs):
context = super(VotacaoEmBlocoExpediente,
@ -3502,33 +3516,20 @@ class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView):
context['sessao_iniciada'] = True
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
if self.expediente:
context['expediente'] = True
else:
context['expediente'] = False
return context
class VotacaoEmBlocoOrdemDia(PermissionRequiredForAppCrudMixin, ListView):
model = OrdemDia
template_name = 'sessao/votacao/votacao_bloco_ordem.html'
app_label = AppConfig.label
logger = logging.getLogger(__name__)
context_object_name = 'ordem_dia'
parent_field = 'sessao_plenaria'
class VotacaoEmBlocoOrdemDia(VotacaoEmBlocoExpediente):
expediente = False
def get_queryset(self):
return OrdemDia.objects.filter(sessao_plenaria_id=self.kwargs['pk'],
resultado='')
def get_context_data(self, **kwargs):
context = super(VotacaoEmBlocoOrdemDia,
self).get_context_data(**kwargs)
context['pk'] = self.kwargs['pk']
context['root_pk'] = self.kwargs['pk']
if not verifica_sessao_iniciada(self.request, self.kwargs['pk']):
context['sessao_iniciada'] = False
return context
context['sessao_iniciada'] = True
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
return context
resultado='',
retiradapauta=None)
class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateView):

2
sapl/settings.py

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

2
sapl/static/sapl/css/relatorio.css

@ -16,7 +16,7 @@ h3 {
page-break-after: avoid;
}
p {
p, a {
font-size: 10pt;
text-align: justify;
text-justify: inter-word;

2
sapl/static/sapl/frontend/css/global.83a4a89d.css → sapl/static/sapl/frontend/css/global.d160bbe2.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/global.83a4a89d.css.gz → sapl/static/sapl/frontend/css/global.d160bbe2.css.gz

Binary file not shown.

2
sapl/static/sapl/frontend/js/compilacao.411d8643.js → sapl/static/sapl/frontend/js/compilacao.7625546b.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/compilacao.411d8643.js.gz → sapl/static/sapl/frontend/js/compilacao.7625546b.js.gz

Binary file not shown.

2
sapl/static/sapl/frontend/js/global.a87c35c2.js → sapl/static/sapl/frontend/js/global.522fd995.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/global.522fd995.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/global.a87c35c2.js.gz

Binary file not shown.

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.156</span>
<span>Release: 3.1.157-RC5</span>
</p>
</div>
<div class="col-md-4">

51
sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html

@ -4,10 +4,9 @@
{% block base_content %}
{% if not show_results %}
<br>
{% crispy filter.form %}
{% endif %}
{% if show_results %}
{% else %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.base:data_fim_prazo_tramitacoes' %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
@ -16,24 +15,34 @@
&emsp;Período: {{ data_tramitacao }} <br />
&emsp;Tipo de matéria: {{ tipo }}<br />
&emsp;Status atual: {{ tramitacao__status }}<br />
&emsp;Local atual: {{ tramitacao__unidade_tramitacao_local }}<br /><br /><br />
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Matéria</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td>
<td>{{materia.ementa}}</td>
&emsp;Local de origem: {{ tramitacao__unidade_tramitacao_local }}<br />
&emsp;Local de destino: {{ tramitacao__unidade_tramitacao_destino }}<br /><br /><br />
{% if object_list %}
{% if object_list|length == 1 %}
<tr><td><h3 style="text-align: left;">Foi encontrada 1 matéria com esses parâmetros.</h3></td></tr><br><br>
{% else %}
<tr><td><h3 style="text-align: left;">Foram encontradas {{object_list|length}} matérias com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Matéria</th>
<th>Ementa</th>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td>
<td>{{materia.ementa}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<tr><td><h3 style="text-align: left;">Nenhuma matéria encontrada com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
{% endif %}
{% endblock base_content %}

48
sapl/templates/base/RelatorioHistoricoTramitacaoAdm_filter.html

@ -0,0 +1,48 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block base_content %}
{% if not show_results %}
<br>
{% crispy filter.form %}
{% else %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.base:historico_tramitacoes_adm' %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<br /><br /><br /><br />
<b>PARÂMETROS DE PESQUISA:<br /></b>
&emsp;Período: {{ data_tramitacao }} <br />
&emsp;Tipo de documento: {{ tipo }}<br />
&emsp;Status atual: {{ tramitacaoadministrativo__status }}<br />
&emsp;Local de origem: {{ tramitacaoadministrativo__unidade_tramitacao_local }}<br />
&emsp;Local de destino: {{ tramitacaoadministrativo__unidade_tramitacao_destino }}<br /><br /><br />
{% if object_list %}
{% if object_list|length == 1 %}
<tr><td><h3 style="text-align: left;">Foi encontrado 1 documento com esses parâmetros.</h3></td></tr><br><br>
{% else %}
<tr><td><h3 style="text-align: left;">Foram encontrados {{object_list|length}} documentos com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Documento</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for documento in object_list %}
<tr>
<td><a href="{% url 'sapl.protocoloadm:tramitacaoadministrativo_list' documento.pk %}">
{{documento.tipo.descricao}} - {{documento.tipo.sigla}} {{documento.numero}}/{{documento.ano}}
</a></td>
<td>{{documento.ementa}}<br>{{documento.observacao}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<tr><td><h3 style="text-align: left;">Nenhum documento encontrado com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
{% endif %}
{% endblock base_content %}

51
sapl/templates/base/RelatorioHistoricoTramitacao_filter.html

@ -4,10 +4,9 @@
{% block base_content %}
{% if not show_results %}
<br>
{% crispy filter.form %}
{% endif %}
{% if show_results %}
{% else %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.base:historico_tramitacoes' %}" class="btn btn-outline-primary">{% trans 'Fazer nova pesquisa' %}</a>
</div>
@ -16,24 +15,34 @@
&emsp;Período: {{ data_tramitacao }} <br />
&emsp;Tipo de matéria: {{ tipo }}<br />
&emsp;Status atual: {{ tramitacao__status }}<br />
&emsp;Local atual: {{ tramitacao__unidade_tramitacao_local }}<br /><br /><br />
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Matéria</th>
<th>Ementa</th>
</tr>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td>
<td>{{materia.ementa}}<br>{{materia.observacao}}</td>
&emsp;Local de origem: {{ tramitacao__unidade_tramitacao_local }}<br />
&emsp;Local de destino: {{ tramitacao__unidade_tramitacao_destino }}<br /><br /><br />
{% if object_list %}
{% if object_list|length == 1 %}
<tr><td><h3 style="text-align: left;">Foi encontrada 1 matéria com esses parâmetros.</h3></td></tr><br><br>
{% else %}
<tr><td><h3 style="text-align: left;">Foram encontradas {{object_list|length}} matérias com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
<table class="table table-bordered table-hover">
<thead class="thead-default" >
<tr class="active">
<th>Matéria</th>
<th>Ementa</th>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for materia in object_list %}
<tr>
<td><a href="{% url 'sapl.materia:tramitacao_list' materia.pk %}">
{{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}}
</a></td>
<td>{{materia.ementa}}<br>{{materia.observacao}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<tr><td><h3 style="text-align: left;">Nenhuma matéria encontrada com esses parâmetros.</h3></td></tr><br><br>
{% endif %}
{% endif %}
{% endblock base_content %}

3
sapl/templates/base/layouts.yaml

@ -22,6 +22,9 @@ AppConfig:
- protocolo_manual receber_recibo_proposicao
- proposicao_incorporacao_obrigatoria escolher_numero_materia_proposicao
{% trans 'Tramitações' %}:
- tramitacao_materia tramitacao_documento
{% trans 'Textos Articulados' %}:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma

8
sapl/templates/base/relatorios_list.html

@ -33,11 +33,11 @@
<td> Atas de Sessão Plenária. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:historico_tramitacoes' %}">Histórico de tramitações</a></td>
<td><a href="{% url 'sapl.base:historico_tramitacoes' %}">Histórico de tramitações de Matérias</a></td>
<td> Histórico de tramitações por período e local informados. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:data_fim_prazo_tramitacoes' %}">Tramitações por fim de prazo</a></td>
<td><a href="{% url 'sapl.base:data_fim_prazo_tramitacoes' %}">Tramitações de Matérias por fim de prazo</a></td>
<td> Tramitações com fim de prazo no intervalo informado. </td>
</tr>
<tr>
@ -56,6 +56,10 @@
<td><a href="{% url 'sapl.base:normas_por_vigencia' %}">Normas por vigência</a></td>
<td> Normas vigentes ou não vigentes. </td>
</tr>
<tr>
<td><a href="{% url 'sapl.base:historico_tramitacoes_adm' %}">Histórico de tramitações de Documentos</a></td>
<td> Histórico de tramitações de Documentos por período e local informados. </td>
</tr>
{% if estatisticas_acesso_normas %}
<tr>
<td><a href="{% url 'sapl.base:estatisticas_acesso' %}">Estatísticas de acesso de Normas</a></td>

68
sapl/templates/comissoes/pauta.html

@ -0,0 +1,68 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block title %}
<h1 class="page-header">
{% if opcao %}
Adicionar Matérias à Pauta <small>(Reunião: {{object}})</small>
{% else %}
Remover Matérias da Pauta <small>(Reunião: {{object}})</small>
{% endif %}
</h1>
{% endblock %}
{% block detail_content %}
{% if materias %}
{% if num_materias == 1 %}
<b>Há {{num_materias}} matéria disponível.</b> <br><br>
{% else %}
<b>Há {{num_materias}} matérias disponíveis.</b> <br><br>
{% endif %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<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>Matéria</th></tr>
</thead>
<tbody onload="checks(materias_checked)">
{% for materia in materias %}
<tr>
<td>
<input type="checkbox" name="materia_id" value="{{materia.id}}" {% if check %} checked {% endif %}/>
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} - {{materia.tipo.descricao}}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
{% if opcao %}
<input type="submit" value="Salvar" class="btn btn-primary"S>
{% else %}
<input type="submit" value="Remover" class="btn btn-danger"S>
{% endif %}
</form>
{% else %}
<b>Não há matéria disponível.</b> <br><br>
{% endif %}
{% endblock %}
{% 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 %}

65
sapl/templates/comissoes/reuniao_detail.html

@ -0,0 +1,65 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block detail_content %}
{{ block.super }}
<h2 class="legend">Pauta</h2>
{% if mats %}
<p>Total de Registros: <b>{{num_mats}}</b></p>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Matéria</th>
</tr>
</thead>
<tbody>
{% for mat in mats %}
<tr>
<td>
<a href="{% url 'sapl.materia:materialegislativa_detail' mat.pk %}">{{mat}}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if perms.comissoes.add_reuniao %}
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.comissoes:pauta_add' reuniao_pk %}" class="btn btn-outline-primary">{% trans 'Adicionar Matéria' %}</a>
<a href="{% url 'sapl.comissoes:pauta_remove' reuniao_pk %}" class="btn btn-outline-primary btn-outline-danger">{% trans 'Remover Matéria' %}</a>
</div>
{% endif %}
{% else %}
{% if perms.comissoes.add_reuniao %}
<a href="{% url 'sapl.comissoes:pauta_add' reuniao_pk %}" class="btn btn-outline-primary">{% trans 'Adicionar Matéria' %}</a>
{% endif %}
{% endif %}
<br /><br />
<h2 class="legend">Documentos Acessórios</h2>
{% if docs %}
<p>Total de registros: <b>{{num_docs}}</b></p>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Documento Acessório</th>
</tr>
</thead>
<tbody>
{% for doc in docs %}
<tr>
<td>
<a href="{% url 'sapl.comissoes:documentoacessorio_detail' doc.pk %}">{{ doc.nome }}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if perms.comissoes.add_reuniao %}
<a href="{% url 'sapl.comissoes:documentoacessorio_create' reuniao_pk %}" class="btn btn-outline-primary float-right">{% trans 'Adicionar Documento' %}</a>
{% endif %}
{% else %}
{% if perms.comissoes.add_reuniao %}
<a href="{% url 'sapl.comissoes:documentoacessorio_create' reuniao_pk %}" class="btn btn-outline-primary">{% trans 'Adicionar Documento' %}</a>
{% endif %}
{% endif %}
<br /><br />
{% endblock detail_content %}

4
sapl/templates/compilacao/subnav.html

@ -19,7 +19,7 @@
<li class="nav-item"><a class="nav-link" href="{% url 'sapl.compilacao:ta_text_notificacoes' object.pk %}">{% trans 'Notificações' %}</a></li>
{% endif %}
{% block extra_sections_nav %}
<li class="nav-item"><a class="nav-link" href="{% url 'sapl.compilacao:ta_text' object.pk %}">{% trans 'Texto' %}</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'sapl.compilacao:ta_text' object.pk %}">{% trans 'Texto Compilado' %}</a></li>
{% endblock %}
{% endif %}
</ul>
</ul>

36
sapl/templates/materia/materia_detail.html

@ -0,0 +1,36 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block detail_content %}
{{ block.super }}
{% if user.is_superuser %}
<div class="row">
{% if materia.user %}
<div class="col-sm-6">
<div id="div_id_user" class="form-group">
<p class="control-label">Usuário</p>
<div class="controls">
<div class="form-control-static">
<div class="dont-break-out">
<a href="{% url 'sapl.base:user_edit' materia.user.pk %}">{{materia.user}}</a>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% if materia.ip %}
<div class="col-sm-6">
<div id="div_ip_user" class="form-group">
<p class="control-label">IP</p>
<div class="controls">
<div class="form-control-static">
<div class="dont-break-out">{{materia.ip}}</div>
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endif %}
{% endblock detail_content %}

4
sapl/templates/materia/tramitacao_detail.html

@ -1,4 +1,4 @@
{% extends "crud/detail.html" %}
{% extends "crud/detail_detail.html" %}
{% load i18n %}
{% block detail_content %}
@ -12,7 +12,7 @@
<div class="controls">
<div class="form-control-static">
<div class="dont-break-out">
<a href="{% url 'sapl.base:user_edit' user.pk %}">{{tramitacao.user}}</a>
<a href="{% url 'sapl.base:user_edit' tramitacao.user.pk %}">{{tramitacao.user}}</a>
</div>
</div>
</div>

9
sapl/templates/navbar.yaml

@ -29,8 +29,13 @@
url: sapl.materia:receber-proposicao
- title: {% trans 'Documentos Administrativos' %}
{% if 'documentos_administrativos'|get_config_attr == 'R' %}check_permission: protocoloadm.list_documentoadministrativo{%endif%}
url: sapl.protocoloadm:pesq_doc_adm
{% if 'documentos_administrativos'|get_config_attr == 'R' %}check_permission: protocoloadm.list_documentoadministrativo {% endif %}
children:
- title: {% trans 'Pesquisar Documentos Administrativos' %}
url: sapl.protocoloadm:pesq_doc_adm
- title: {% trans 'Tramitação em Lote' %}
url: sapl.protocoloadm:primeira_tramitacao_em_lote_docadm
check_permission: sapl.documento:add_tramitacao
- title: {% trans 'Atividade Legislativa' %}
children:

2
sapl/templates/norma/subnav.yaml

@ -15,6 +15,6 @@
# Em nada mais a integração interfere em NormaJuridica
{% if 'texto_articulado_norma'|get_config_attr %}
- title: {% trans 'Texto' %}
- title: {% trans 'Texto Compilado' %}
url: norma_ta
{% endif %}

39
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -81,3 +81,42 @@
{% block table_content %}
{% endblock table_content %}
{% block extra_js %}
<style>
.select-error {
border-color: red;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
}
</style>
<script type="text/javascript">
validation = () => {
if (document.getElementById("relatorio").checked && !$("#id_ano").val()){
$("#submit-id-pesquisar").attr("disabled", true);
$("#id_ano").addClass("select-error");
$("#div_id_ano").append('<spam id="error-ano" style="font-size:8pt;color:red">Selecione uma data.</spam>');
}
else{
error = document.getElementById("error-ano")
if (error){
$("#submit-id-pesquisar").attr("disabled", false);
$("#id_ano").removeClass("select-error");
document.getElementById("error-ano").remove();
}
}
}
document.getElementById("relatorio").onchange = validation;
document.getElementById("id_ano").onchange = validation;
validation();
</script>
{% endblock %}

5
sapl/templates/protocoloadm/em_lote/subnav_em_lote.yaml

@ -0,0 +1,5 @@
{% load i18n common_tags %}
- title: {% trans 'Primeira Tramitação' %}
url: primeira_tramitacao_em_lote_docadm
- title: {% trans 'Tramitação em Lote' %}
url: tramitacao_em_lote_docadm

46
sapl/templates/protocoloadm/em_lote/tramitacaoadm.html

@ -0,0 +1,46 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block detail_content %}
{% if not show_results %}
{% crispy filter.form %}
{% else %}
{% if object_list|length > 0 %}
{% if object_list|length == 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 {{object_list|length}} documentos.</h3>
{% endif %}
{% crispy 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('documentos');
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"}}
if (primeira_tramitacao == false){
$('#id_unidade_tramitacao_local').prop('disabled', true);
}
// Reabilita o campo, no momento do Submit, para que seu dado seja enviado
$('input[type=submit]').click(function() {
$('#id_unidade_tramitacao_local').attr('disabled', false);
$('#id_unidade_tramitacao_local').parents('form').submit();
});
});
</script>
{% endblock %}

2
sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html

@ -26,7 +26,7 @@
<div class="controls">
<div class="form-control-static">
<div class="dont-break-out">
<a href="{% url 'sapl.base:user_edit' user.pk %}">{{tramitacaoadministrativo.user}}</a>
<a href="{% url 'sapl.base:user_edit' tramitacaoadministrativo.user.pk %}">{{tramitacaoadministrativo.user}}</a>
</div>
</div>
</div>

85
sapl/templates/relatorios/relatorio_doc_administrativos.html

@ -0,0 +1,85 @@
{% load i18n %}
{% load common_tags %}
{% load static %}
<head>
<style>
@page{
margin-top: 4.5cm;
size: A4 portrait;
@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>
<h2>Documentos Administrativos</h2>
{% if documentoadministrativo_list|length %}
<h3>Número de documentos: {{numero_res}}</h3>
{% for d in documentoadministrativo_list %}
<div style="border-top: 1px solid black;margin-bottom:0.3cm">
{% if request.user.is_anonymous and not d.restrito or not request.user.is_anonymous%}
<strong><a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não informado"}}
</br>
<strong>Assunto:</strong>&nbsp;<a>{{ d.assunto|safe}}</a>
</br>
{% if d.protocolo %}
<strong>Protocolo:</strong>&nbsp;<a href="{% url 'sapl.protocoloadm:protocolo_mostrar' d.protocolo.id %}">{{ d.protocolo}}</a></br>
{% endif %}
{% define d.tramitacaoadministrativo_set.last as tram %}
{% if tram.unidade_tramitacao_destino %}
<strong>Localização Atual:</strong> &nbsp;{{tram.unidade_tramitacao_destino}}
</br>
<strong>Status:</strong> {{tram.status}}
</br>
{% endif %}
{% define d.documentoacessorioadministrativo_set.all as acess %}
{% if d.documentoacessorioadministrativo_set.all.exists %}
<strong>Documentos Acessórios:</strong>
<a href="{% url 'sapl.protocoloadm:documentoacessorioadministrativo_list' d.id %}">
{{ d.documentoacessorioadministrativo_set.all.count }}
</a>
</br>
{% endif %}
{% if d.tramitacao and mail_service_configured %}
<a href="{% url 'sapl.protocoloadm:acompanhar_documento' d.id %}">Acompanhar Documento</a>
{% endif %}
{% endif %}
</div>
{% endfor %}
{% else %}
<h3>Nenhum documento encontrado com essas especificações</h3>
{% endif %}
</body>

25
sapl/templates/search/search.html

@ -7,14 +7,21 @@
</br>
<form method="get" action=".">
<div class="row">
<div class="col-md-8">
<div class="col-md-12">
{{ form.q|as_crispy_field }}
</div>
</div>
<div class="row">
<div class="row">
<div class="col-md-8">
<h3> Em quais tipos de documento deseja pesquisar?</h3>
<br/>
<div class="checkbox" id="check_all">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
<br/>
{{ form.models }}
</div>
</div>
@ -103,3 +110,17 @@
</form>
{% endblock %}
{% block extra_js %}
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('models');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
</script>
{% endblock %}

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

@ -3,8 +3,12 @@
{% if expedientes %}
<strong>Expedientes: </strong>
{% for e in expedientes %}
<b>{{e.tipo}}</b>:
{{e.conteudo|striptags|safe}}
<b>{{e.tipo}}</b>:
{% if e.conteudo %}
{{e.conteudo|striptags|safe}}
{% else %}
Sem registro
{% endif %}
{% endfor %}
{% endif %}
</p>

2
sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html

@ -5,4 +5,4 @@
<div class="col-md-6">Video: <a href={{multimidia_video|slice:"6:"}}>{{multimidia_video|slice:"6:"}}</a></div>
</div>
</fieldset>
<br /><br /><br />
<br /><br /><br />

5
sapl/templates/sessao/blocos_resumo/expedientes.html

@ -1,3 +1,4 @@
{% if expedientes %}
<fieldset>
<legend>Expedientes</legend>
<table class="table">
@ -14,4 +15,6 @@
{% endfor %}
</thead>
</table>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/blocos_resumo/identificacao_basica.html

@ -1,3 +1,4 @@
{% if basica %}
<fieldset>
<legend>Identificação Básica</legend>
<div class="row">
@ -5,4 +6,6 @@
<div class="col-md-4">{{b}}</div>
{% endfor %}
</div>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

63
sapl/templates/sessao/blocos_resumo/lista_presenca.html

@ -1,35 +1,42 @@
{% load common_tags %}
{% if presenca_sessao or justificativa_ausencia %}
<fieldset>
{% if presenca_sessao %}
<legend>Lista de Presença na Sessão</legend>
<div class="row">
{% for p in presenca_sessao %}
<div class="col-md-12">{{p.nome_parlamentar}} / {% if p|filiacao_data_filter:object.data_inicio %} {{ p|filiacao_data_filter:object.data_inicio }} {% else %} Sem partido {% endif %}</div>
{% endfor %}
</div>
<div class="row">
{% for p in presenca_sessao %}
<div class="col-md-12">{{p.nome_parlamentar}} / {% if p|filiacao_data_filter:object.data_inicio %} {{ p|filiacao_data_filter:object.data_inicio }} {% else %} Sem partido {% endif %}</div>
{% endfor %}
</div>
</br></br></br>
<div class="row">
{% endif %}
{% if justificativa_ausencia %}
<div class="row">
<legend>Justificativas de Ausência na Sessão</legend>
<table class="table">
<thead>
<tr>
<th>Parlamentar</th>
<th>Justificativa</th>
<th>Ausente em</th>
</tr>
</thead>
<tbody>
{% for j in justificativa_ausencia %}
<tr>
<td> {{ j.parlamentar }} </td>
<td> {{ j.tipo_ausencia }} </td>
{% if j.ausencia == 1 %}
<td> Matéria </td>
{% else %}
<td> Sessão </td>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
<table class="table">
<thead>
<tr>
<th>Parlamentar</th>
<th>Justificativa</th>
<th>Ausente em</th>
</tr>
</thead>
<tbody>
{% for j in justificativa_ausencia %}
<tr>
<td> {{ j.parlamentar }} </td>
<td> {{ j.tipo_ausencia }} </td>
{% if j.ausencia == 1 %}
<td> Matéria </td>
{% else %}
<td> Sessão </td>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/blocos_resumo/lista_presenca_ordem_dia.html

@ -1,5 +1,6 @@
{% load common_tags %}
{% if presenca_ordem %}
<fieldset>
<legend>Lista de Presença na Ordem do Dia</legend>
<div class="row">
@ -7,4 +8,6 @@
<div class="col-md-12">{{p.nome_parlamentar}} / {% if p|filiacao_data_filter:object.data_inicio %} {{ p|filiacao_data_filter:object.data_inicio }} {% else %} Sem partido {% endif %} </div>
{% endfor %}
</div>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

6
sapl/templates/sessao/blocos_resumo/materias_expediente.html

@ -1,5 +1,5 @@
{% load common_tags %}
{% if materia_expediente %}
<fieldset>
<legend>Matérias do Expediente</legend>
<table class="table table-striped table-hover">
@ -44,4 +44,6 @@
{% endfor %}
</tbody>
</table>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/blocos_resumo/materias_ordem_dia.html

@ -1,5 +1,6 @@
{% load common_tags %}
{% if materias_ordem %}
<fieldset>
<legend>Matérias da Ordem do Dia</legend>
<table class="table table-striped table-hover">
@ -41,4 +42,6 @@
{% endfor %}
</tbody>
</table>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/blocos_resumo/mesa_diretora.html

@ -1,5 +1,6 @@
{% load common_tags %}
{% if mesa %}
<fieldset>
<legend>Mesa Diretora</legend>
<div class="row">
@ -9,4 +10,6 @@
</div>
{% endfor %}
</div>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/blocos_resumo/ocorrencias_da_sessao.html

@ -1,6 +1,9 @@
{% if object.ocorrenciasessao.conteudo %}
<fieldset>
<legend>Ocorrências da Sessão</legend>
<div style="border:0.5px solid #BAB4B1; border-radius: 10px; background-color: rgba(225, 225, 225, .8);">
<p>{{object.ocorrenciasessao.conteudo|safe}}</p>
</div>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

3
sapl/templates/sessao/blocos_resumo/oradores_expediente.html

@ -1,3 +1,4 @@
{% if oradores %}
<fieldset>
<legend>Oradores do Expediente</legend>
<div class="row">
@ -14,3 +15,5 @@
{% endfor %}
</div>
</fieldset>
<br /><br /><br />
{% endif %}

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

@ -1,5 +1,6 @@
{% load common_tags %}
{% if oradores_explicacoes %}
<fieldset>
<legend>Oradores das Explicações Pessoais</legend>
<div class="row">
@ -13,4 +14,6 @@
</br>
{% endfor %}
</div>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/blocos_resumo/oradores_ordemdia.html

@ -1,3 +1,4 @@
{% if oradores_ordemdia %}
<fieldset>
<legend>Oradores da Ordem do Dia</legend>
<div class="row">
@ -12,4 +13,6 @@
<div class="col-md-4">{{ orador.observacao }}</div>
{% endfor %}
</div>
</fieldset>
</fieldset>
<br /><br /><br />
{% endif %}

53
sapl/templates/sessao/blocos_resumo/votos_nominais_materias_expediente.html

@ -1,28 +1,31 @@
{% if votos_nominais_materia_expediente %}
<fieldset>
<legend>Votações Nominais - Matérias do Expediente</legend>
</br>
<table class="table table-striped table-hover">
<thead>
<legend>Votações Nominais - Matérias do Expediente</legend>
</br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Matéria</th>
<th>Votos</th>
</tr>
</thead>
<tbody>
{% for m in votos_nominais_materia_expediente %}
<tr>
<th>Matéria</th>
<th>Votos</th>
<td>{{ m.titulo }}</td>
{% if m.votos %}
<td>
{% for v in m.votos %}
<li><b>{{v.parlamentar}}</b> - {{v.voto}}</li>
{% endfor %}
</td>
{% else %}
<td><b>Matéria não votada</b></td>
{% endif %}
</tr>
</thead>
<tbody>
{% for m in votos_nominais_materia_expediente %}
<tr>
<td>{{ m.titulo }}</td>
{% if m.votos %}
<td>
{% for v in m.votos %}
<li><b>{{v.parlamentar}}</b> - {{v.voto}}</li>
{% endfor %}
</td>
{% else %}
<td><b>Matéria não votada</b></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
{% endfor %}
</tbody>
</table>
</fieldset>
<br /><br /><br />
{% endif %}

53
sapl/templates/sessao/blocos_resumo/votos_nominais_materias_ordem_dia.html

@ -1,28 +1,31 @@
{% if votos_nominais_materia_ordem_dia %}
<fieldset>
<legend>Votações Nominais - Matérias da Ordem do Dia</legend>
</br>
<table class="table table-striped table-hover">
<thead>
<legend>Votações Nominais - Matérias da Ordem do Dia</legend>
</br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Matéria</th>
<th>Votos</th>
</tr>
</thead>
<tbody>
{% for m in votos_nominais_materia_ordem_dia %}
<tr>
<th>Matéria</th>
<th>Votos</th>
<td>{{ m.titulo }}</td>
{% if m.votos %}
<td>
{% for v in m.votos %}
<li><b>{{v.parlamentar}}</b> - {{v.voto}}</li>
{% endfor %}
</td>
{% else %}
<td><b>Matéria não votada</b></td>
{% endif %}
</tr>
</thead>
<tbody>
{% for m in votos_nominais_materia_ordem_dia %}
<tr>
<td>{{ m.titulo }}</td>
{% if m.votos %}
<td>
{% for v in m.votos %}
<li><b>{{v.parlamentar}}</b> - {{v.voto}}</li>
{% endfor %}
</td>
{% else %}
<td><b>Matéria não votada</b></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
{% endfor %}
</tbody>
</table>
</fieldset>
<br /><br /><br />
{% endif %}

5
sapl/templates/sessao/pauta_sessao_filter.html

@ -1,7 +1,8 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load i18n staticfiles %}
{% load i18n %}
{% load webpack_static from webpack_loader %}
{% block sections_nav %} {% endblock %}
@ -24,7 +25,7 @@
{% for s in page_obj %}
<tr>
<td><a href="{% url 'sapl.sessao:pauta_sessao_detail' s.id %}"><strong>{{s}}</strong></br></a></td><td>
<a href="{% url 'sapl.relatorios:relatorio_pauta_sessao' s.pk %}"><img height="30" width="30" src="{% static 'img/pdflogo.png' %}"></a>
<a href="{% url 'sapl.relatorios:relatorio_pauta_sessao' s.pk %}"><img height="30" width="30" src="{% webpack_static 'img/pdflogo.png' %}"></a>
</td>
</tr>
{% endfor %}

14
sapl/templates/sessao/resumo.html

@ -21,45 +21,31 @@
</div>
{% include 'sessao/blocos_resumo/'|add:primeiro_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:segundo_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:terceiro_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:quarto_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:quinto_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:sexto_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:setimo_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:oitavo_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:nono_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:decimo_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:decimo_primeiro_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:decimo_segundo_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:decimo_terceiro_ordenacao %}
<br /><br /><br />
{% include 'sessao/blocos_resumo/'|add:decimo_quarto_ordenacao %}
<br /><br /><br />
{% endblock detail_content %}

166
sapl/templates/sessao/votacao/votacao_bloco.html

@ -0,0 +1,166 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block base_content %}
{% if sessao_iniciada %}
<form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}">
{% csrf_token %}
<br><br>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3>{% trans "Tipo de Votação" %}</h3></td>
</tr>
</thead>
<tr>
<td class="col-md-12">
<fieldset id="tipo_votacao" name="tipo">
<input type="radio" name="tipo_votacao" id="tipo_votacao_1" value="1" onchange="alteraTipoVotacao()" checked="checked"> <label for="tipo">Simbólica</label>
</br>
<input type="radio" name="tipo_votacao" id="tipo_votacao_2" value="2" onchange="alteraTipoVotacao()" > <label for="tipo">Nominal</label>
</br>
</fieldset>
</td>
</tr>
</table>
<br>
<h3 id='frase_selecione'>{% if expediente %} Selecione o(s) expediente(s) desejado(s). {% else %} Selecione a(s) ordem(s) do dia desejada(s). {% endif %}</h3>
<table id='tab_mats' class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3> {% if expediente %} {% trans "Expediente" %} {% else %} {% trans "Ordem do Dia" %} {% endif %} </h3></td>
</tr>
</thead>
<div class="checkbox" id="check_all">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
{% for o in object_list %}
{% if o.tipo_votacao == 1 or o.tipo_votacao == 2 %}
<tr class="{% if o.tipo_votacao == 1 %}Simbolica{% else %}Nominal{% endif %}" {% if o.tipo_votacao == 2 %} style="display:none;" {% endif %}>
<td>
<input type="checkbox" name="marcadas_{{o.tipo_votacao}}" id="{{o.id}}" value="{{o.id}}" {% if check %} checked {% endif %}>
<strong><a href="{% url 'sapl.materia:materialegislativa_detail' o.materia.id %}">{{o.materia.tipo.sigla}} {{o.materia.numero}}/{{o.materia.ano}} - {{o.materia.tipo}}</strong></a></br>
{% if o.materia.numeracao_set.last %}
<strong>Processo:</strong> &nbsp; {{o.materia.numeracao_set.last}}</br>
{% endif %}
<strong>Autor:</strong>
{% for a in o.materia.autoria_set.all %}
{% if not forloop.first %}
, &nbsp;&nbsp; {{a.autor|default_if_none:""}}
{% else %}
&nbsp;{{a.autor|default_if_none:""}}
{% endif %}
{% endfor %}
</br>
{% if o.materia.numero_protocolo %}
<strong>Protocolo:</strong> &nbsp; {{o.materia.numero_protocolo}}</br>
{% endif %}
{% if o.materia.tramitacao_set.last %}
{% if o.materia.tramitacao_set.last.turno %}
<strong>Turno:</strong>&nbsp;
{% for t in turno_choices %}
{% if t.0 == o.materia.tramitacao_set.last.turno %}
{{ t.1 }}
{% endif %}
{% endfor %}</br>
{% endif %}
{% endif %}
<strong>Ementa:</strong>&nbsp;{{ o.materia.ementa|safe }}</br>
<p></p>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
<table class="table table-striped table-bordered" style="display:none" id="nenhuma_mat">
<tr>
<td>
<h3>{% if expediente %} Nenhuma matéria do expediente aberta. {% else %} Nenhuma matéria da ordem do dia aberta. {% endif %} </h3>
</td>
</tr>
</table>
{% if expediente %}
<a href="{% url 'sapl.sessao:expedientemateria_list' pk %}" class="btn btn-warning mb-3" id="but_cancel">Voltar</a>
<input type="hidden" id="origem" name="origem" value="expediente">
{% else %}
<a href="{% url 'sapl.sessao:ordemdia_list' pk %}" class="btn btn-warning mb-3" id="but_cancel">Voltar</a>
<input type="hidden" id="origem" name="origem" value="ordem">
{% endif %}
<input type="submit" value="Registrar votação" class="btn btn-primary mb-3 float-right" id="but_reg">
</form>
{% endif %}
{% endblock base_content %}
{% block extra_js %}
<script>
$(document).ready(function(){
checa_tipo_votacao();
$('#tipo_votacao_1').prop('checked', true)
});
$(window).on('beforeunload', function () {
$("input[type=submit], input[type=button]").prop("disabled", "disabled");
});
</script>
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('marcadas_1');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
checkboxes = document.getElementsByName('marcadas_2');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
function alteraTipoVotacao() {
$(".Simbolica").toggle();
$(".Nominal").toggle();
checa_tipo_votacao();
}
function checa_tipo_votacao(){
tipo_votacao = document.querySelector('input[name="tipo_votacao"]:checked').value;
numero_marcadas = document.getElementsByName('marcadas_'+tipo_votacao).length;
if(numero_marcadas == 0){
document.getElementById('frase_selecione').style.display = 'none';
document.getElementById('tab_mats').style.display = 'none';
document.getElementById('check_all').style.display = 'none';
document.getElementById('but_reg').style.display = 'none';
document.getElementById('nenhuma_mat').style.display = '';
}
else{
document.getElementById('frase_selecione').style.display = '';
document.getElementById('tab_mats').style.display = '';
document.getElementById('check_all').style.display = '';
document.getElementById('but_reg').style.display = '';
document.getElementById('nenhuma_mat').style.display = 'none';
}
if(tipo_votacao == "1"){
$('#form').attr("action", "{% url 'sapl.sessao:votacaoblocosimb' pk %}")
}
else{
$('#form').attr("action", "{% url 'sapl.sessao:votacaobloconom' pk %}")
}
}
</script>
{% endblock extra_js%}

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

@ -1,161 +0,0 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block base_content %}
{% if sessao_iniciada %}
<form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}">
{% csrf_token %}
<br><br>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3>{% trans "Tipo de Votação" %}</h3></td>
</tr>
</thead>
<tr>
<td class="col-md-12">
<fieldset id="tipo_votacao" name="tipo">
<input type="radio" name="tipo_votacao" id="tipo_votacao_1" value="1" onchange="alteraTipoVotacao()" checked="checked"> <label for="tipo">Simbólica</label>
</br>
<input type="radio" name="tipo_votacao" id="tipo_votacao_2" value="2" onchange="alteraTipoVotacao()" > <label for="tipo">Nominal</label>
</br>
</fieldset>
</td>
</tr>
</table>
<br>
<h3 id='frase_selecione'>Selecione o(s) expediente(s) desejado(s).</h3>
<table id='tab_ordens' class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3>{% trans "Expediente" %}</h3></td>
</tr>
</thead>
<div class="checkbox" id="check_all">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
{% for o in expedientes %}
{% if o.tipo_votacao == 1 or o.tipo_votacao == 2 %}
<tr class="{% if o.tipo_votacao == 1 %}Simbolica{% else %}Nominal{% endif %}" {% if o.tipo_votacao == 2 %} style="display:none;" {% endif %}>
<td>
<input type="checkbox" name="marcadas_{{o.tipo_votacao}}" id="{{o.id}}" value="{{o.id}}" {% if check %} checked {% endif %}>
<strong><a href="{% url 'sapl.materia:materialegislativa_detail' o.id %}">{{o.materia.tipo.sigla}} {{o.materia.numero}}/{{o.materia.ano}} - {{o.materia.tipo}}</strong></a></br>
{% if o.materia.numeracao_set.last %}
<strong>Processo:</strong> &nbsp; {{o.materia.numeracao_set.last}}</br>
{% endif %}
<strong>Autor:</strong>
{% for a in o.materia.autoria_set.all %}
{% if not forloop.first %}
, &nbsp;&nbsp; {{a.autor|default_if_none:""}}
{% else %}
&nbsp;{{a.autor|default_if_none:""}}
{% endif %}
{% endfor %}
</br>
{% if o.materia.numero_protocolo %}
<strong>Protocolo:</strong> &nbsp; {{o.materia.numero_protocolo}}</br>
{% endif %}
{% if o.materia.tramitacao_set.last %}
{% if o.materia.tramitacao_set.last.turno %}
<strong>Turno:</strong>&nbsp;
{% for t in turno_choices %}
{% if t.0 == o.materia.tramitacao_set.last.turno %}
{{ t.1 }}
{% endif %}
{% endfor %}</br>
{% endif %}
{% endif %}
<strong>Ementa:</strong>&nbsp;{{ o.ementa|safe }}</br>
<p></p>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
<table class="table table-striped table-bordered" style="display:none" id="nenhum_exp">
<tr>
<td>
<h3>Nenhuma matéria do expediente aberta.</h3>
</td>
</tr>
</table>
<a href="{% url 'sapl.sessao:expedientemateria_list' pk %}" class="btn btn-warning mb-3" id="but_cancel">Voltar</a>
<input type="submit" value="Registrar votação" class="btn btn-primary mb-3 float-right" id="but_reg">
<input type="hidden" id="origem" name="origem" value="expediente">
</form>
{% endif %}
{% endblock base_content %}
{% block extra_js %}
<script>
$(document).ready(function(){
checa_tipo_votacao();
$('#tipo_votacao_1').prop('checked', true)
});
$(window).on('beforeunload', function () {
$("input[type=submit], input[type=button]").prop("disabled", "disabled");
});
</script>
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('marcadas_1');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
checkboxes = document.getElementsByName('marcadas_2');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
function alteraTipoVotacao() {
$(".Simbolica").toggle();
$(".Nominal").toggle();
checa_tipo_votacao();
}
function checa_tipo_votacao(){
tipo_votacao = document.querySelector('input[name="tipo_votacao"]:checked').value;
numero_ordens = document.getElementsByName('marcadas_'+tipo_votacao).length;
if(numero_ordens == 0){
document.getElementById('frase_selecione').style.display = 'none';
document.getElementById('tab_ordens').style.display = 'none';
document.getElementById('check_all').style.display = 'none';
document.getElementById('but_reg').style.display = 'none';
document.getElementById('nenhum_exp').style.display = '';
}
else{
document.getElementById('frase_selecione').style.display = '';
document.getElementById('tab_ordens').style.display = '';
document.getElementById('check_all').style.display = '';
document.getElementById('but_reg').style.display = '';
document.getElementById('nenhum_exp').style.display = 'none';
}
if(tipo_votacao == "1"){
$('#form').attr("action", "{% url 'sapl.sessao:votacaoblocosimb' pk %}")
}
else{
$('#form').attr("action", "{% url 'sapl.sessao:votacaobloconom' pk %}")
}
}
</script>
{% endblock extra_js%}

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

@ -1,162 +0,0 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block base_content %}
{% if sessao_iniciada %}
<form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:votacaoblocosimb' pk %}">
{% csrf_token %}
<br><br>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3>{% trans "Tipo de Votação" %}</h3></td>
</tr>
</thead>
<tr>
<td class="col-md-12">
<fieldset id="tipo_votacao" name="tipo">
<input type="radio" name="tipo_votacao" id="tipo_votacao_1" value="1" onchange="alteraTipoVotacao()" checked="checked"> <label for="tipo">Simbólica</label>
</br>
<input type="radio" name="tipo_votacao" id="tipo_votacao_2" value="2" onchange="alteraTipoVotacao()" > <label for="tipo">Nominal</label>
</br>
</fieldset>
</td>
</tr>
</table>
<br>
<h3 id='frase_selecione'>Selecione a(s) ordem(s) do dia desejada(s).</h3>
<table id='tab_ordens' class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3>{% trans "Ordem do dia" %}</h3></td>
</tr>
</thead>
<div class="checkbox" id="check_all">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos
</label>
</div>
{% for o in ordem_dia %}
{% if o.tipo_votacao == 1 or o.tipo_votacao == 2 %}
<tr class="{% if o.tipo_votacao == 1 %}Simbolica{% else %}Nominal{% endif %}" {% if o.tipo_votacao == 2 %} style="display:none;" {% endif %}>
<td>
<input type="checkbox" name="marcadas_{{o.tipo_votacao}}" id="{{o.id}}" value="{{o.id}}" {% if check %} checked {% endif %}>
<strong><a href="{% url 'sapl.materia:materialegislativa_detail' o.id %}">{{o.materia.tipo.sigla}} {{o.materia.numero}}/{{o.materia.ano}} - {{o.materia.tipo}}</strong></a></br>
{% if o.materia.numeracao_set.last %}
<strong>Processo:</strong> &nbsp; {{o.materia.numeracao_set.last}}</br>
{% endif %}
<strong>Autor:</strong>
{% for a in o.materia.autoria_set.all %}
{% if not forloop.first %}
, &nbsp;&nbsp; {{a.autor|default_if_none:""}}
{% else %}
&nbsp;{{a.autor|default_if_none:""}}
{% endif %}
{% endfor %}
</br>
{% if o.materia.numero_protocolo %}
<strong>Protocolo:</strong> &nbsp; {{o.materia.numero_protocolo}}</br>
{% endif %}
{% if o.materia.tramitacao_set.last %}
{% if o.materia.tramitacao_set.last.turno %}
<strong>Turno:</strong>&nbsp;
{% for t in turno_choices %}
{% if t.0 == o.materia.tramitacao_set.last.turno %}
{{ t.1 }}
{% endif %}
{% endfor %}</br>
{% endif %}
{% endif %}
<strong>Ementa:</strong>&nbsp;{{ o.ementa|safe }}</br>
<p></p>
</td>
</tr>
{% endif %}
{% endfor %}
</table>
<table class="table table-striped table-bordered" style="display:none" id="nenhuma_ordem">
<tr>
<td>
<h3>Nenhuma ordem do dia aberta.</h3>
</td>
</tr>
</table>
<a href="{% url 'sapl.sessao:ordemdia_list' pk %}" class="btn btn-warning mb-3" id="but_cancel">Voltar</a>
<input type="submit" value="Registrar votação" class="btn btn-primary mb-3 float-right" id="but_reg">
<input type="hidden" id="origem" name="origem" value="ordem">
</form>
{% endif %}
{% endblock base_content %}
{% block extra_js %}
<script>
$(document).ready(function(){
checa_tipo_votacao();
$('#tipo_votacao_1').prop('checked', true)
});
$(window).on('beforeunload', function () {
$("input[type=submit], input[type=button]").prop("disabled", "disabled");
});
</script>
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('marcadas_1');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
checkboxes = document.getElementsByName('marcadas_2');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
function alteraTipoVotacao() {
$(".Simbolica").toggle();
$(".Nominal").toggle();
checa_tipo_votacao();
}
function checa_tipo_votacao(){
tipo_votacao = document.querySelector('input[name="tipo_votacao"]:checked').value;
numero_ordens = document.getElementsByName('marcadas_'+tipo_votacao).length;
if(numero_ordens == 0){
document.getElementById('frase_selecione').style.display = 'none';
document.getElementById('tab_ordens').style.display = 'none';
document.getElementById('check_all').style.display = 'none';
document.getElementById('but_reg').style.display = 'none';
document.getElementById('nenhuma_ordem').style.display = '';
}
else{
document.getElementById('frase_selecione').style.display = '';
document.getElementById('tab_ordens').style.display = '';
document.getElementById('check_all').style.display = '';
document.getElementById('but_reg').style.display = '';
document.getElementById('nenhuma_ordem').style.display = 'none';
}
if(tipo_votacao == "1"){
$('#form').attr("action", "{% url 'sapl.sessao:votacaoblocosimb' pk %}")
}
else{
$('#form').attr("action", "{% url 'sapl.sessao:votacaobloconom' pk %}")
}
}
</script>
{% endblock extra_js%}

21
sapl/utils.py

@ -965,16 +965,21 @@ def lista_anexados(principal, isMateriaLegislativa=True):
else: #DocAdm
from sapl.protocoloadm.models import Anexado
anexados_iterator = Anexado.objects.filter(documento_principal=principal)
while anexados_iterator:
anexados_tmp = []
for anx in anexados_iterator:
if isMateriaLegislativa:
anexadas_temp = list(anexados_iterator)
while anexadas_temp:
anx = anexadas_temp.pop()
if isMateriaLegislativa:
if anx.materia_anexada not in anexados_total:
anexados_total.append(anx.materia_anexada)
anexados_anexado = Anexada.objects.filter(materia_principal=anx.materia_anexada)
else:
anexadas_temp.extend(anexados_anexado)
else:
if anx.documento_anexado not in anexados_total:
anexados_total.append(anx.documento_anexado)
anexados_anexado = Anexado.objects.filter(documento_principal=anx.documento_anexado)
anexados_tmp.extend(anexados_anexado)
anexados_iterator = anexados_tmp
anexadas_temp.extend(anexados_anexado)
if principal in anexados_total:
anexados_total.remove(principal)
return anexados_total

2
sapl/webpack-stats.json

@ -1 +1 @@
{"status":"done","publicPath":"/static/sapl/frontend/","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.3c9fe6b4.css","publicPath":"/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css"},{"name":"js/chunk-vendors.0003dc37.js","publicPath":"/static/sapl/frontend/js/chunk-vendors.0003dc37.js","path":"../sapl/sapl/static/sapl/frontend/js/chunk-vendors.0003dc37.js"},{"name":"css/chunk-vendors.3c9fe6b4.css.map","publicPath":"/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css.map","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css.map"}],"compilacao":[{"name":"css/compilacao.1f5fb8cf.css","publicPath":"/static/sapl/frontend/css/compilacao.1f5fb8cf.css","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css"},{"name":"js/compilacao.411d8643.js","publicPath":"/static/sapl/frontend/js/compilacao.411d8643.js","path":"../sapl/sapl/static/sapl/frontend/js/compilacao.411d8643.js"},{"name":"css/compilacao.1f5fb8cf.css.map","publicPath":"/static/sapl/frontend/css/compilacao.1f5fb8cf.css.map","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css.map"}],"global":[{"name":"css/global.83a4a89d.css","publicPath":"/static/sapl/frontend/css/global.83a4a89d.css","path":"../sapl/sapl/static/sapl/frontend/css/global.83a4a89d.css"},{"name":"js/global.a87c35c2.js","publicPath":"/static/sapl/frontend/js/global.a87c35c2.js","path":"../sapl/sapl/static/sapl/frontend/js/global.a87c35c2.js"},{"name":"css/global.83a4a89d.css.map","publicPath":"/static/sapl/frontend/css/global.83a4a89d.css.map","path":"../sapl/sapl/static/sapl/frontend/css/global.83a4a89d.css.map"}],"painel":[{"name":"css/painel.baa845ab.css","publicPath":"/static/sapl/frontend/css/painel.baa845ab.css","path":"../sapl/sapl/static/sapl/frontend/css/painel.baa845ab.css"},{"name":"js/painel.de2ce2cd.js","publicPath":"/static/sapl/frontend/js/painel.de2ce2cd.js","path":"../sapl/sapl/static/sapl/frontend/js/painel.de2ce2cd.js"},{"name":"css/painel.baa845ab.css.map","publicPath":"/static/sapl/frontend/css/painel.baa845ab.css.map","path":"../sapl/sapl/static/sapl/frontend/css/painel.baa845ab.css.map"}]}}
{"status":"done","publicPath":"/static/sapl/frontend/","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.3c9fe6b4.css","publicPath":"/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css"},{"name":"js/chunk-vendors.0003dc37.js","publicPath":"/static/sapl/frontend/js/chunk-vendors.0003dc37.js","path":"../sapl/sapl/static/sapl/frontend/js/chunk-vendors.0003dc37.js"},{"name":"css/chunk-vendors.3c9fe6b4.css.map","publicPath":"/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css.map","path":"../sapl/sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css.map"}],"compilacao":[{"name":"css/compilacao.1f5fb8cf.css","publicPath":"/static/sapl/frontend/css/compilacao.1f5fb8cf.css","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css"},{"name":"js/compilacao.7625546b.js","publicPath":"/static/sapl/frontend/js/compilacao.7625546b.js","path":"../sapl/sapl/static/sapl/frontend/js/compilacao.7625546b.js"},{"name":"css/compilacao.1f5fb8cf.css.map","publicPath":"/static/sapl/frontend/css/compilacao.1f5fb8cf.css.map","path":"../sapl/sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css.map"}],"global":[{"name":"css/global.d160bbe2.css","publicPath":"/static/sapl/frontend/css/global.d160bbe2.css","path":"../sapl/sapl/static/sapl/frontend/css/global.d160bbe2.css"},{"name":"js/global.522fd995.js","publicPath":"/static/sapl/frontend/js/global.522fd995.js","path":"../sapl/sapl/static/sapl/frontend/js/global.522fd995.js"},{"name":"css/global.d160bbe2.css.map","publicPath":"/static/sapl/frontend/css/global.d160bbe2.css.map","path":"../sapl/sapl/static/sapl/frontend/css/global.d160bbe2.css.map"}],"painel":[{"name":"css/painel.baa845ab.css","publicPath":"/static/sapl/frontend/css/painel.baa845ab.css","path":"../sapl/sapl/static/sapl/frontend/css/painel.baa845ab.css"},{"name":"js/painel.de2ce2cd.js","publicPath":"/static/sapl/frontend/js/painel.de2ce2cd.js","path":"../sapl/sapl/static/sapl/frontend/js/painel.de2ce2cd.js"},{"name":"css/painel.baa845ab.css.map","publicPath":"/static/sapl/frontend/css/painel.baa845ab.css.map","path":"../sapl/sapl/static/sapl/frontend/css/painel.baa845ab.css.map"}]}}

4
setup.py

@ -12,7 +12,7 @@ install_requires = [
'django>=1.11.19,<2.0',
'django-haystack==2.8.1',
'django-filter==2.0.0',
'djangorestframework==3.9.0',
'djangorestframework==3.9.1',
'dj-database-url==0.5.0',
'django-braces==1.9.0',
'django-crispy-forms==1.7.2',
@ -43,7 +43,7 @@ install_requires = [
]
setup(
name='interlegis-sapl',
version='3.1.156',
version='3.1.157-RC5',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',

Loading…
Cancel
Save