Browse Source

Merge branch 'master' into 2924-ordernar-cronometro-arrastando

pull/2930/head
Cesar Augusto de Carvalho 6 years ago
committed by GitHub
parent
commit
daa86b2e70
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      sapl/api/views.py
  2. 50
      sapl/base/forms.py
  3. 15
      sapl/base/search_indexes.py
  4. 5
      sapl/base/urls.py
  5. 101
      sapl/base/views.py
  6. 32
      sapl/comissoes/forms.py
  7. 9
      sapl/compilacao/views.py
  8. 28
      sapl/materia/forms.py
  9. 19
      sapl/materia/migrations/0055_auto_20190816_0943.py
  10. 14
      sapl/materia/models.py
  11. 6
      sapl/materia/views.py
  12. 5
      sapl/painel/urls.py
  13. 32
      sapl/painel/views.py
  14. 87
      sapl/parlamentares/forms.py
  15. 32
      sapl/parlamentares/migrations/0033_afastamentoparlamentar.py
  16. 21
      sapl/parlamentares/migrations/0034_auto_20190801_1408.py
  17. 16
      sapl/parlamentares/migrations/0035_merge_20190802_0954.py
  18. 38
      sapl/parlamentares/models.py
  19. 151
      sapl/parlamentares/tests/test_parlamentares.py
  20. 3
      sapl/parlamentares/urls.py
  21. 41
      sapl/parlamentares/views.py
  22. 83
      sapl/protocoloadm/views.py
  23. 14
      sapl/relatorios/templates/pdf_pauta_sessao_gerar.py
  24. 33
      sapl/relatorios/views.py
  25. 1
      sapl/rules/map_rules.py
  26. 22
      sapl/sessao/forms.py
  27. 24
      sapl/sessao/migrations/0045_auto_20190809_1319.py
  28. 24
      sapl/sessao/migrations/0046_auto_20190809_1319.py
  29. 8
      sapl/sessao/models.py
  30. 18
      sapl/sessao/tests/test_sessao_view.py
  31. 117
      sapl/sessao/views.py
  32. 8
      sapl/static/sapl/frontend/css/chunk-45646c50.b20a1ea4.css
  33. BIN
      sapl/static/sapl/frontend/css/chunk-45646c50.b20a1ea4.css.gz
  34. 8
      sapl/static/sapl/frontend/css/chunk-45646c50.d0eb5406.css
  35. BIN
      sapl/static/sapl/frontend/css/chunk-45646c50.d0eb5406.css.gz
  36. 104
      sapl/static/sapl/frontend/css/chunk-vendors.28796d79.css
  37. BIN
      sapl/static/sapl/frontend/css/chunk-vendors.28796d79.css.gz
  38. 101
      sapl/static/sapl/frontend/css/chunk-vendors.2ce8185b.css
  39. BIN
      sapl/static/sapl/frontend/css/chunk-vendors.2ce8185b.css.gz
  40. 1
      sapl/static/sapl/frontend/css/global.cb631d5e.css
  41. BIN
      sapl/static/sapl/frontend/css/global.cb631d5e.css.gz
  42. 1
      sapl/static/sapl/frontend/css/global.d160bbe2.css
  43. BIN
      sapl/static/sapl/frontend/css/global.d160bbe2.css.gz
  44. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.3165b14b.eot
  45. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.3165b14b.eot.gz
  46. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.457cb96b.woff
  47. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.4b115e11.woff2
  48. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.b90365bc.woff
  49. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf.gz
  50. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot.gz
  51. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.f2e186cf.ttf
  52. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.f2e186cf.ttf.gz
  53. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.f861a57c.woff2
  54. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.2cd8d991.ttf
  55. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.2cd8d991.ttf.gz
  56. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot.gz
  57. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.65779ebc.woff2
  58. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.7ab2cb05.woff
  59. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.a03df7ab.eot
  60. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.a03df7ab.eot.gz
  61. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.bd52a727.woff2
  62. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf.gz
  63. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.2cd2be17.woff2
  64. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.46280631.woff2
  65. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.5ee32f5c.ttf
  66. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.5ee32f5c.ttf.gz
  67. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.61969d43.woff
  68. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.657a4694.woff
  69. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.a547e21e.eot
  70. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.a547e21e.eot.gz
  71. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot.gz
  72. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf.gz
  73. BIN
      sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg.gz
  74. 1407
      sapl/static/sapl/frontend/img/fa-brands-400.f249e44d.svg
  75. BIN
      sapl/static/sapl/frontend/img/fa-brands-400.f249e44d.svg.gz
  76. 22
      sapl/static/sapl/frontend/img/fa-regular-400.2fad4ee0.svg
  77. BIN
      sapl/static/sapl/frontend/img/fa-regular-400.2fad4ee0.svg.gz
  78. BIN
      sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg.gz
  79. BIN
      sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg.gz
  80. 741
      sapl/static/sapl/frontend/img/fa-solid-900.fdc155d5.svg
  81. BIN
      sapl/static/sapl/frontend/img/fa-solid-900.fdc155d5.svg.gz
  82. 0
      sapl/static/sapl/frontend/js/chunk-2d0c4a82.43dad737.js
  83. 0
      sapl/static/sapl/frontend/js/chunk-2d0c4a82.43dad737.js.gz
  84. 0
      sapl/static/sapl/frontend/js/chunk-2d0e8be2.2b08ebc9.js
  85. 0
      sapl/static/sapl/frontend/js/chunk-2d0e8be2.2b08ebc9.js.gz
  86. 0
      sapl/static/sapl/frontend/js/chunk-3e2c11a1.2ff29933.js
  87. 0
      sapl/static/sapl/frontend/js/chunk-3e2c11a1.2ff29933.js.gz
  88. 0
      sapl/static/sapl/frontend/js/chunk-45646c50.4e66dd13.js
  89. 0
      sapl/static/sapl/frontend/js/chunk-45646c50.4e66dd13.js.gz
  90. 0
      sapl/static/sapl/frontend/js/chunk-4cf2dae1.13047e21.js
  91. 0
      sapl/static/sapl/frontend/js/chunk-4cf2dae1.13047e21.js.gz
  92. 314
      sapl/static/sapl/frontend/js/chunk-vendors.0af160fc.js
  93. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.0af160fc.js.gz
  94. 304
      sapl/static/sapl/frontend/js/chunk-vendors.eaff380d.js
  95. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.eaff380d.js.gz
  96. 1
      sapl/static/sapl/frontend/js/compilacao.97a57151.js
  97. BIN
      sapl/static/sapl/frontend/js/compilacao.97a57151.js.gz
  98. 1
      sapl/static/sapl/frontend/js/compilacao.bb73875d.js
  99. BIN
      sapl/static/sapl/frontend/js/compilacao.bb73875d.js.gz
  100. 2
      sapl/static/sapl/frontend/js/global.40c7bff1.js

19
sapl/api/views.py

@ -15,6 +15,7 @@ from django_filters.rest_framework.filterset import FilterSet
from django_filters.utils import resolve_field from django_filters.utils import resolve_field
from rest_framework import serializers as rest_serializers from rest_framework import serializers as rest_serializers
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import SerializerMethodField
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
@ -24,12 +25,14 @@ from sapl.api.serializers import ChoiceSerializer
from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO
from sapl.materia.models import Proposicao, TipoMateriaLegislativa,\ from sapl.materia.models import Proposicao, TipoMateriaLegislativa,\
MateriaLegislativa, Tramitacao MateriaLegislativa, Tramitacao
from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import DocumentoAdministrativo,\ from sapl.protocoloadm.models import DocumentoAdministrativo,\
DocumentoAcessorioAdministrativo, TramitacaoAdministrativo, Anexado DocumentoAcessorioAdministrativo, TramitacaoAdministrativo, Anexado
from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao
from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria
class BusinessRulesNotImplementedMixin: class BusinessRulesNotImplementedMixin:
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
raise Exception(_("POST Create não implementado")) raise Exception(_("POST Create não implementado"))
@ -92,10 +95,15 @@ class SaplApiViewSetConstrutor():
# Define uma classe padrão para serializer caso não tenha sido # Define uma classe padrão para serializer caso não tenha sido
# criada a classe sapl.api.serializers.{model}Serializer # criada a classe sapl.api.serializers.{model}Serializer
class SaplSerializer(rest_serializers.ModelSerializer): class SaplSerializer(rest_serializers.ModelSerializer):
__str__ = SerializerMethodField()
class Meta: class Meta:
model = _model model = _model
fields = '__all__' fields = '__all__'
def get___str__(self, obj):
return str(obj)
# Define uma classe padrão para filtro caso não tenha sido # Define uma classe padrão para filtro caso não tenha sido
# criada a classe sapl.api.forms.{model}FilterSet # criada a classe sapl.api.forms.{model}FilterSet
class SaplFilterSet(SaplFilterSetMixin): class SaplFilterSet(SaplFilterSetMixin):
@ -200,6 +208,8 @@ SaplApiViewSetConstrutor.build_class()
# rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor # rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor
# decorator para recuperar e transformar o default # decorator para recuperar e transformar o default
class customize(object): class customize(object):
def __init__(self, model): def __init__(self, model):
self.model = model self.model = model
@ -521,3 +531,12 @@ class _SessaoPlenariaViewSet:
serializer = self.get_serializer(page, many=True) serializer = self.get_serializer(page, many=True)
return Response(serializer.data) return Response(serializer.data)
@customize(NormaJuridica)
class _NormaJuridicaViewset:
@action(detail=False, methods=['GET'])
def destaques(self, request, *args, **kwargs):
self.queryset = self.get_queryset().filter(norma_de_destaque=True)
return self.list(request, *args, **kwargs)

50
sapl/base/forms.py

@ -605,7 +605,7 @@ class AutorForm(ModelForm):
self.logger.error( self.logger.error(
'Já existe um Autor para este usuário ({}).'.format(cd['username'])) 'Já existe um Autor para este usuário ({}).'.format(cd['username']))
raise ValidationError( raise ValidationError(
_('Já existe um Autor para este usuário.')) _('Já existe um usuário vinculado a esse autor'))
""" """
'if' não é necessário por ser campo obrigatório e o framework 'if' não é necessário por ser campo obrigatório e o framework
@ -1162,7 +1162,7 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
@property @property
def qs(self): def qs(self):
parent = super(RelatorioMateriasPorAutorFilterSet, self).qs parent = super().qs
return parent.distinct().filter(autoria__primeiro_autor=True)\ return parent.distinct().filter(autoria__primeiro_autor=True)\
.order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero') .order_by('autoria__autor', '-autoria__primeiro_autor', 'tipo', '-ano', '-numero')
@ -1171,8 +1171,7 @@ class RelatorioMateriasPorAutorFilterSet(django_filters.FilterSet):
fields = ['tipo', 'data_apresentacao'] fields = ['tipo', 'data_apresentacao']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(RelatorioMateriasPorAutorFilterSet, self).__init__( super().__init__(*args, **kwargs)
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria' self.filters['tipo'].label = 'Tipo de Matéria'
@ -1611,3 +1610,46 @@ class RelatorioHistoricoTramitacaoAdmFilterSet(django_filters.FilterSet):
form_actions(label='Pesquisar')) form_actions(label='Pesquisar'))
) )
class RelatorioNormasPorAutorFilterSet(django_filters.FilterSet):
autorianorma__autor = django_filters.CharFilter(widget=forms.HiddenInput())
@property
def qs(self):
parent = super().qs
return parent.distinct().filter(autorianorma__primeiro_autor=True)\
.order_by('autorianorma__autor', '-autorianorma__primeiro_autor', 'tipo', '-ano', '-numero')
class Meta(FilterOverridesMetaMixin):
model = NormaJuridica
fields = ['tipo', 'data']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Norma'
row1 = to_row(
[('tipo', 12)])
row2 = to_row(
[('data', 12)])
row3 = to_row(
[('autorianorma__autor', 0),
(Button('pesquisar',
'Pesquisar Autor',
css_class='btn btn-primary btn-sm'), 2),
(Button('limpar',
'Limpar Autor',
css_class='btn btn-primary btn-sm'), 10)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisar'),
row1, row2,
HTML(autor_label),
HTML(autor_modal),
row3,
form_actions(label='Pesquisar'))
)

15
sapl/base/search_indexes.py

@ -1,23 +1,21 @@
import os.path
import logging import logging
import os.path
from celery_haystack.indexes import CelerySearchIndex
from django.db.models import F, Q, Value from django.db.models import F, Q, Value
from django.db.models.fields import TextField from django.db.models.fields import TextField
from django.db.models.functions import Concat from django.db.models.functions import Concat
from django.template import loader from django.template import loader
from haystack import connections from haystack import connections
from haystack.constants import Indexable from haystack.constants import Indexable
from haystack.fields import CharField from haystack.fields import CharField, DateTimeField, IntegerField
from haystack.utils import get_model_ct_tuple from haystack.utils import get_model_ct_tuple
from celery_haystack.indexes import CelerySearchIndex
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PUBLIC, Dispositivo) STATUS_TA_PUBLIC, Dispositivo)
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa
from sapl.norma.models import NormaJuridica from sapl.norma.models import NormaJuridica
from sapl.settings import SOLR_URL from sapl.settings import SOLR_URL
from sapl.utils import RemoveTag
class TextExtractField(CharField): class TextExtractField(CharField):
@ -120,6 +118,7 @@ class TextExtractField(CharField):
class DocumentoAcessorioIndex(CelerySearchIndex, Indexable): class DocumentoAcessorioIndex(CelerySearchIndex, Indexable):
model = DocumentoAcessorio model = DocumentoAcessorio
data = DateTimeField(model_attr='data', null=True)
text = TextExtractField( text = TextExtractField(
document=True, use_template=True, document=True, use_template=True,
model_attr=( model_attr=(
@ -145,6 +144,9 @@ class DocumentoAcessorioIndex(CelerySearchIndex, Indexable):
class NormaJuridicaIndex(DocumentoAcessorioIndex): class NormaJuridicaIndex(DocumentoAcessorioIndex):
model = NormaJuridica model = NormaJuridica
data = DateTimeField(model_attr='data', null=True)
tipo = CharField(model_attr='tipo__sigla')
ano = IntegerField(model_attr='ano')
text = TextExtractField( text = TextExtractField(
document=True, use_template=True, document=True, use_template=True,
model_attr=( model_attr=(
@ -159,6 +161,9 @@ class NormaJuridicaIndex(DocumentoAcessorioIndex):
class MateriaLegislativaIndex(DocumentoAcessorioIndex): class MateriaLegislativaIndex(DocumentoAcessorioIndex):
model = MateriaLegislativa model = MateriaLegislativa
tipo = CharField(model_attr='tipo__sigla')
ano = IntegerField(model_attr='ano')
data = DateTimeField(model_attr='data_apresentacao')
text = TextExtractField( text = TextExtractField(
document=True, use_template=True, document=True, use_template=True,
model_attr=( model_attr=(

5
sapl/base/urls.py

@ -38,7 +38,8 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
ListarAutoresDuplicadosView, ListarBancadaComissaoAutorExternoView, ListarAutoresDuplicadosView, ListarBancadaComissaoAutorExternoView,
ListarLegislaturaInfindavelView, ListarAnexadasCiclicasView, ListarLegislaturaInfindavelView, ListarAnexadasCiclicasView,
ListarAnexadosCiclicosView, pesquisa_textual, ListarAnexadosCiclicosView, pesquisa_textual,
RelatorioHistoricoTramitacaoAdmView, RelatorioDocumentosAcessoriosView) RelatorioHistoricoTramitacaoAdmView, RelatorioDocumentosAcessoriosView,
RelatorioNormasPorAutorView)
app_name = AppConfig.name app_name = AppConfig.name
@ -156,6 +157,8 @@ urlpatterns = [
url(r'^sistema/relatorios/documentos_acessorios$', url(r'^sistema/relatorios/documentos_acessorios$',
RelatorioDocumentosAcessoriosView.as_view(), RelatorioDocumentosAcessoriosView.as_view(),
name='relatorio_documentos_acessorios'), name='relatorio_documentos_acessorios'),
url(r'^sistema/relatorios/normas-por-autor$',
RelatorioNormasPorAutorView.as_view(), name='normas_por_autor'),
url(r'^email/validate/(?P<uidb64>[0-9A-Za-z_\-]+)/' url(r'^email/validate/(?P<uidb64>[0-9A-Za-z_\-]+)/'
'(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$', '(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$',

101
sapl/base/views.py

@ -41,13 +41,13 @@ from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao, Anexada, from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao, Anexada,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao, TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao,
DocumentoAcessorio, TipoDocumento) DocumentoAcessorio, TipoDocumento)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas) from sapl.norma.models import (NormaJuridica, TipoNormaJuridica, NormaEstatisticas)
from sapl.parlamentares.models import (Parlamentar, Legislatura, Mandato, from sapl.parlamentares.models import (Parlamentar, Legislatura, Mandato, Filiacao,
Filiacao, SessaoLegislativa, Bancada) SessaoLegislativa, Bancada, AfastamentoParlamentar)
from sapl.protocoloadm.models import (Protocolo, TipoDocumentoAdministrativo, from sapl.protocoloadm.models import (Protocolo, TipoDocumentoAdministrativo,
StatusTramitacaoAdministrativo, StatusTramitacaoAdministrativo,
DocumentoAdministrativo, Anexado) DocumentoAdministrativo, Anexado)
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, OrdemDia,
SessaoPlenariaPresenca, TipoSessaoPlenaria) SessaoPlenariaPresenca, TipoSessaoPlenaria)
from sapl.utils import (parlamentares_ativos, gerar_hash_arquivo, SEPARADOR_HASH_PROPOSICAO, from sapl.utils import (parlamentares_ativos, gerar_hash_arquivo, SEPARADOR_HASH_PROPOSICAO,
show_results_filter_set, mail_service_configured, show_results_filter_set, mail_service_configured,
@ -66,7 +66,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm,
RelatorioNormasVigenciaFilterSet, RelatorioNormasVigenciaFilterSet,
EstatisticasAcessoNormasForm, UsuarioFilterSet, EstatisticasAcessoNormasForm, UsuarioFilterSet,
RelatorioHistoricoTramitacaoAdmFilterSet, RelatorioHistoricoTramitacaoAdmFilterSet,
RelatorioDocumentosAcessoriosFilterSet) RelatorioDocumentosAcessoriosFilterSet,
RelatorioNormasPorAutorFilterSet)
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
@ -494,16 +495,35 @@ class RelatorioPresencaSessaoView(FilterView):
for i, p in enumerate(parlamentares_qs): for i, p in enumerate(parlamentares_qs):
m = p.mandato_set.filter(Q(data_inicio_mandato__lte=_range[0], data_fim_mandato__gte=_range[1]) | m = p.mandato_set.filter(Q(data_inicio_mandato__lte=_range[0], data_fim_mandato__gte=_range[1]) |
Q(data_inicio_mandato__lte=_range[0], data_fim_mandato__isnull=True) | Q(data_inicio_mandato__lte=_range[0], data_fim_mandato__isnull=True) |
Q(data_inicio_mandato__gte=_range[0], data_fim_mandato__lte=_range[1]) |
# mandato suplente
Q(data_inicio_mandato__gte=_range[0], data_fim_mandato__lte=_range[1])) Q(data_inicio_mandato__gte=_range[0], data_fim_mandato__lte=_range[1]))
afastamentos = AfastamentoParlamentar.objects.filter(Q(parlamentar=p) & (Q(data_inicio__range=_range) |
Q(data_inicio__gte=_range[0], data_fim__isnull=True)))
afast_parl_sessao = 0
afast_parl_ordem = 0
for afastamento in afastamentos:
if afastamento.data_fim:
afast_parl_sessao += SessaoPlenaria.objects.filter(data_inicio__range=[afastamento.data_inicio,
afastamento.data_fim]).count()
afast_parl_ordem += OrdemDia.objects.filter(sessao_plenaria__data_inicio__range=[afastamento.data_inicio,
afastamento.data_fim]).order_by('sessao_plenaria__id').\
distinct('sessao_plenaria__id').count()
else:
afast_parl_sessao += SessaoPlenaria.objects.filter(data_inicio__gte=afastamento.data_inicio).count()
afast_parl_ordem += OrdemDia.objects.filter(sessao_plenaria__data_inicio__gte=afastamento.data_inicio).\
order_by('sessao_plenaria__id').\
distinct('sessao_plenaria__id').count()
m = m.last() m = m.last()
parlamentares_presencas.append({ parlamentares_presencas.append({
'parlamentar': p, 'parlamentar': p,
'titular': m.titular if m else False, 'titular': m.titular if m else False,
'sessao_porc': 0, 'sessao_porc': 0,
'ordemdia_porc': 0 'ordemdia_porc': 0,
'sessao_afast': afast_parl_sessao,
'ordem_afast': afast_parl_ordem
}) })
try: try:
self.logger.debug( self.logger.debug(
@ -529,13 +549,15 @@ class RelatorioPresencaSessaoView(FilterView):
}) })
if total_sessao != 0: if total_sessao != 0:
porc = round(
sessao_count * 100 / (total_sessao-afast_parl_sessao), 2)
parlamentares_presencas[i].update( parlamentares_presencas[i].update(
{'sessao_porc': round( {'sessao_porc': porc if porc <=100 else 100})
sessao_count * 100 / total_sessao, 2)})
if total_ordemdia != 0: if total_ordemdia != 0:
porc = round(
ordemdia_count * 100 / (total_ordemdia-afast_parl_ordem), 2)
parlamentares_presencas[i].update( parlamentares_presencas[i].update(
{'ordemdia_porc': round( {'ordemdia_porc': porc if porc <=100.0 else 100.0})
ordemdia_count * 100 / total_ordemdia, 2)})
context['date_range'] = _range context['date_range'] = _range
context['total_ordemdia'] = total_ordemdia context['total_ordemdia'] = total_ordemdia
@ -872,15 +894,12 @@ class RelatorioMateriasPorAutorView(FilterView):
template_name = 'base/RelatorioMateriasPorAutor_filter.html' template_name = 'base/RelatorioMateriasPorAutor_filter.html'
def get_filterset_kwargs(self, filterset_class): def get_filterset_kwargs(self, filterset_class):
super(RelatorioMateriasPorAutorView, super().get_filterset_kwargs(filterset_class)
self).get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None} kwargs = {'data': self.request.GET or None}
return kwargs return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RelatorioMateriasPorAutorView, context = super().get_context_data(**kwargs)
self).get_context_data(**kwargs)
context['title'] = _('Matérias por Autor') context['title'] = _('Matérias por Autor')
if not self.filterset.form.is_valid(): if not self.filterset.form.is_valid():
@ -2113,3 +2132,51 @@ class RelatorioHistoricoTramitacaoAdmView(FilterView):
context['tramitacaoadministrativo__unidade_tramitacao_destino'] = '' context['tramitacaoadministrativo__unidade_tramitacao_destino'] = ''
return context return context
class RelatorioNormasPorAutorView(FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasPorAutorFilterSet
template_name = 'base/RelatorioNormasPorAutor_filter.html'
def get_filterset_kwargs(self, filterset_class):
super().get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = _('Normas por Autor')
if not self.filterset.form.is_valid():
return context
qtdes = {}
for tipo in TipoNormaJuridica.objects.all():
qs = kwargs['object_list']
qtde = len(qs.filter(tipo_id=tipo.id))
if qtde > 0:
qtdes[tipo] = qtde
context['qtdes'] = qtdes
qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
if self.request.GET['tipo']:
tipo = int(self.request.GET['tipo'])
context['tipo'] = (
str(TipoNormaJuridica.objects.get(id=tipo)))
else:
context['tipo'] = ''
if self.request.GET['autorianorma__autor']:
autor = int(self.request.GET['autorianorma__autor'])
context['autor'] = (str(Autor.objects.get(id=autor)))
else:
context['autor'] = ''
context['periodo'] = (
self.request.GET['data_0'] +
' - ' + self.request.GET['data_1'])
return context

32
sapl/comissoes/forms.py

@ -40,17 +40,31 @@ class ComposicaoForm(forms.ModelForm):
periodo = cleaned_data['periodo'] periodo = cleaned_data['periodo']
comissao_pk = self.initial['comissao'].id comissao_pk = self.initial['comissao'].id
cleaned_data['comissao'] = self.initial['comissao'] cleaned_data['comissao'] = self.initial['comissao']
intersecao_periodo = Composicao.objects.filter(
Q(periodo__data_inicio__lte=periodo.data_fim, if periodo.data_fim:
periodo__data_fim__gte=periodo.data_fim) | intersecao_periodo = Composicao.objects.filter(
Q(periodo__data_inicio__gte=periodo.data_inicio, Q(periodo__data_inicio__lte=periodo.data_fim,
periodo__data_fim__lte=periodo.data_inicio), periodo__data_fim__gte=periodo.data_fim) |
comissao_id=comissao_pk) Q(periodo__data_inicio__gte=periodo.data_inicio,
periodo__data_fim__lte=periodo.data_inicio),
comissao_id=comissao_pk)
else:
intersecao_periodo = Composicao.objects.filter(
Q(periodo__data_inicio__gte=periodo.data_inicio,
periodo__data_fim__lte=periodo.data_inicio),
comissao_id=comissao_pk)
if intersecao_periodo: if intersecao_periodo:
self.logger.error('O período informado ({} a {})' if periodo.data_fim:
'choca com períodos já ' self.logger.error('O período informado ({} a {})'
'cadastrados para esta comissão'.format(periodo.data_inicio, periodo.data_fim)) 'choca com períodos já '
'cadastrados para esta comissão'
.format(periodo.data_inicio, periodo.data_fim))
else:
self.logger.error('O período informado ({} - )'
'choca com períodos já '
'cadastrados para esta comissão'
.format(periodo.data_inicio))
raise ValidationError('O período informado ' raise ValidationError('O período informado '
'choca com períodos já ' 'choca com períodos já '
'cadastrados para esta comissão') 'cadastrados para esta comissão')

9
sapl/compilacao/views.py

@ -195,8 +195,13 @@ class IntegracaoTaView(TemplateView):
return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit', return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit',
kwargs={'ta_id': ta.pk})) kwargs={'ta_id': ta.pk}))
else: else:
return redirect(to=reverse_lazy('sapl.compilacao:ta_text', return redirect(
kwargs={'ta_id': ta.pk})) to='%s?%s' % (
reverse_lazy('sapl.compilacao:ta_text',
kwargs={'ta_id': ta.pk}),
request.META['QUERY_STRING']
)
)
class Meta: class Meta:
abstract = True abstract = True

28
sapl/materia/forms.py

@ -996,11 +996,15 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'autoria__primeiro_autor', 'autoria__primeiro_autor',
'autoria__autor__parlamentar_set__filiacao__partido', 'autoria__autor__parlamentar_set__filiacao__partido',
'relatoria__parlamentar_id', 'relatoria__parlamentar_id',
'local_origem_externa',
'tramitacao__unidade_tramitacao_destino', 'tramitacao__unidade_tramitacao_destino',
'tramitacao__status', 'tramitacao__status',
'materiaassunto__assunto', 'materiaassunto__assunto',
'em_tramitacao', 'em_tramitacao',
'tipo_origem_externa',
'numero_origem_externa',
'ano_origem_externa',
'data_origem_externa',
'local_origem_externa',
] ]
def filter_ementa(self, queryset, name, value): def filter_ementa(self, queryset, name, value):
@ -1012,7 +1016,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
return queryset.filter(q) return queryset.filter(q)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
# self.filters['tipo'].label = 'Tipo de Matéria' # self.filters['tipo'].label = 'Tipo de Matéria'
self.filters[ self.filters[
@ -1055,11 +1059,10 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
]) ])
row6 = to_row( row6 = to_row(
[('relatoria__parlamentar_id', 6), [('relatoria__parlamentar_id', 6),
('local_origem_externa', 6)]) ('em_tramitacao', 6)])
row7 = to_row( row7 = to_row(
[('tramitacao__unidade_tramitacao_destino', 5), [('tramitacao__unidade_tramitacao_destino', 6),
('tramitacao__status', 5), ('tramitacao__status', 6),
('em_tramitacao', 2)
]) ])
row9 = to_row( row9 = to_row(
[('materiaassunto__assunto', 6), ('indexacao', 6)]) [('materiaassunto__assunto', 6), ('indexacao', 6)])
@ -1070,6 +1073,16 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
('tipo_listagem', 4) ('tipo_listagem', 4)
]) ])
row10 = to_row([
('tipo_origem_externa', 4),
('numero_origem_externa', 4),
('ano_origem_externa', 4),
])
row11 = to_row([
('data_origem_externa', 8),
('local_origem_externa', 4)
])
self.form.helper = SaplFormHelper() self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET' self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout( self.form.helper.layout = Layout(
@ -1079,6 +1092,9 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
Fieldset(_('Como listar os resultados da pesquisa'), Fieldset(_('Como listar os resultados da pesquisa'),
row8 row8
), ),
Fieldset(_('Origem externa'),
row10, row11
),
Fieldset(_('Pesquisa Avançada'), Fieldset(_('Pesquisa Avançada'),
row3, row3,
HTML(autor_label), HTML(autor_label),

19
sapl/materia/migrations/0055_auto_20190816_0943.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-16 12:43
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('materia', '0054_merge_20190802_1117'),
]
operations = [
migrations.AlterModelOptions(
name='materialegislativa',
options={'ordering': ['-id'], 'permissions': (('can_access_impressos', 'Can access impressos'),), 'verbose_name': 'Matéria Legislativa', 'verbose_name_plural': 'Matérias Legislativas'},
),
]

14
sapl/materia/models.py

@ -299,7 +299,7 @@ class MateriaLegislativa(models.Model):
verbose_name = _('Matéria Legislativa') verbose_name = _('Matéria Legislativa')
verbose_name_plural = _('Matérias Legislativas') verbose_name_plural = _('Matérias Legislativas')
unique_together = (("tipo", "numero", "ano"),) unique_together = (("tipo", "numero", "ano"),)
ordering = ['-id']
permissions = (("can_access_impressos", "Can access impressos"),) permissions = (("can_access_impressos", "Can access impressos"),)
def __str__(self): def __str__(self):
@ -438,7 +438,7 @@ class PautaReuniao(models.Model):
' - Matéria: %(materia)s') % { ' - Matéria: %(materia)s') % {
'reuniao': self.reuniao, 'reuniao': self.reuniao,
'materia': self.materia 'materia': self.materia
} }
@reversion.register() @reversion.register()
@ -487,7 +487,8 @@ class AssuntoMateria(models.Model):
@reversion.register() @reversion.register()
class DespachoInicial(models.Model): class DespachoInicial(models.Model):
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE) materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
comissao = models.ForeignKey(Comissao, on_delete=models.CASCADE, verbose_name="Comissão") comissao = models.ForeignKey(
Comissao, on_delete=models.CASCADE, verbose_name="Comissão")
class Meta: class Meta:
verbose_name = _('Despacho Inicial') verbose_name = _('Despacho Inicial')
@ -559,7 +560,8 @@ class DocumentoAcessorio(models.Model):
return _('%(tipo)s - %(nome)s de %(data)s por %(autor)s') % { return _('%(tipo)s - %(nome)s de %(data)s por %(autor)s') % {
'tipo': self.tipo, 'tipo': self.tipo,
'nome': self.nome, 'nome': self.nome,
'data': self.data, 'data': formats.date_format(
self.data, "SHORT_DATE_FORMAT") if self.data else '',
'autor': self.autor} 'autor': self.autor}
def delete(self, using=None, keep_parents=False): def delete(self, using=None, keep_parents=False):
@ -715,8 +717,8 @@ class Relatoria(models.Model):
'data': self.data_designacao_relator.strftime("%d/%m/%Y")} 'data': self.data_designacao_relator.strftime("%d/%m/%Y")}
else: else:
return _('%(materia)s - %(data)s') % { return _('%(materia)s - %(data)s') % {
'materia': self.materia, 'materia': self.materia,
'data': self.data_designacao_relator.strftime("%d/%m/%Y")} 'data': self.data_designacao_relator.strftime("%d/%m/%Y")}
@reversion.register() @reversion.register()

6
sapl/materia/views.py

@ -1909,8 +1909,7 @@ class MateriaLegislativaPesquisaView(FilterView):
paginate_by = 50 paginate_by = 50
def get_filterset_kwargs(self, filterset_class): def get_filterset_kwargs(self, filterset_class):
super(MateriaLegislativaPesquisaView, super().get_filterset_kwargs(filterset_class)
self).get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None} kwargs = {'data': self.request.GET or None}
@ -1966,8 +1965,7 @@ class MateriaLegislativaPesquisaView(FilterView):
return kwargs return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(MateriaLegislativaPesquisaView, context = super().get_context_data(**kwargs)
self).get_context_data(**kwargs)
context['title'] = _('Pesquisar Matéria Legislativa') context['title'] = _('Pesquisar Matéria Legislativa')

5
sapl/painel/urls.py

@ -4,7 +4,7 @@ from .apps import AppConfig
from .views import (cronometro_painel, get_dados_painel, painel_mensagem_view, from .views import (cronometro_painel, get_dados_painel, painel_mensagem_view,
painel_parlamentar_view, painel_view, painel_votacao_view, painel_parlamentar_view, painel_view, painel_votacao_view,
switch_painel, verifica_painel, votante_view, CronometroPainelCrud, switch_painel, verifica_painel, votante_view, CronometroPainelCrud,
PainelConfigCrud,ordena_cronometro) PainelConfigCrud,ordena_cronometro, painel_parcial_view)
app_name = AppConfig.name app_name = AppConfig.name
@ -28,4 +28,7 @@ urlpatterns = [
url(r'^voto-individual/$', votante_view, url(r'^voto-individual/$', votante_view,
name='voto_individual'), name='voto_individual'),
url(r'^painel-parcial/(?P<pk>\d+)/(?P<opcoes>\d+)/$', painel_parcial_view,
name="painel_parcial"),
] ]

32
sapl/painel/views.py

@ -346,11 +346,41 @@ def votante_view(request):
@user_passes_test(check_permission) @user_passes_test(check_permission)
def painel_view(request, pk): def painel_view(request, pk):
exibicao = {
'parlamentares': True,
'oradores': True,
'cronometros': True,
'resultado': True,
'materia': True
}
context = {'head_title': str(_('Painel Plenário')),
'sessao_id': pk,
'cronometros': Cronometro.objects.filter(ativo=True).order_by('ordenacao'),
'painel_config': PainelConfig.objects.first(),
'casa': CasaLegislativa.objects.last(),
'exibicao': exibicao
}
return render(request, 'painel/index.html', context)
def bit_is_set(number, bit):
return (number & (1 << bit)) != 0
@user_passes_test(check_permission)
def painel_parcial_view(request, pk, opcoes):
opcoes = int(opcoes)
exibicao = {
'parlamentares': bit_is_set(opcoes,0),
'oradores': bit_is_set(opcoes,1),
'cronometros': bit_is_set(opcoes, 2),
'resultado': bit_is_set(opcoes, 3),
'materia': bit_is_set(opcoes, 4)
}
context = {'head_title': str(_('Painel Plenário')), context = {'head_title': str(_('Painel Plenário')),
'sessao_id': pk, 'sessao_id': pk,
'cronometros': Cronometro.objects.filter(ativo=True).order_by('ordenacao'), 'cronometros': Cronometro.objects.filter(ativo=True).order_by('ordenacao'),
'painel_config': PainelConfig.objects.first(), 'painel_config': PainelConfig.objects.first(),
'casa': CasaLegislativa.objects.last() 'casa': CasaLegislativa.objects.last(),
'exibicao': exibicao
} }
return render(request, 'painel/index.html', context) return render(request, 'painel/index.html', context)

87
sapl/parlamentares/forms.py

@ -24,7 +24,7 @@ import django_filters
from .models import (ComposicaoColigacao, Filiacao, Frente, Legislatura, from .models import (ComposicaoColigacao, Filiacao, Frente, Legislatura,
Mandato, Parlamentar, Votante, Bloco, Bancada, CargoBloco, Mandato, Parlamentar, Votante, Bloco, Bancada, CargoBloco,
CargoBlocoPartido) CargoBlocoPartido, AfastamentoParlamentar, TipoAfastamento)
class ImageThumbnailFileInput(ClearableFileInput): class ImageThumbnailFileInput(ClearableFileInput):
@ -87,6 +87,12 @@ class MandatoForm(ModelForm):
'tipo_afastamento', 'observacao', 'parlamentar'] 'tipo_afastamento', 'observacao', 'parlamentar']
widgets = {'parlamentar': forms.HiddenInput()} widgets = {'parlamentar': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['tipo_afastamento'].queryset = TipoAfastamento.objects.filter(indicador='F')
def clean(self): def clean(self):
super(MandatoForm, self).clean() super(MandatoForm, self).clean()
@ -673,6 +679,8 @@ class BancadaForm(ModelForm):
nome=bancada.nome nome=bancada.nome
) )
return bancada return bancada
class CargoBlocoForm(ModelForm): class CargoBlocoForm(ModelForm):
class Meta: class Meta:
model = CargoBloco model = CargoBloco
@ -737,3 +745,80 @@ class CargoBlocoPartidoForm(ModelForm):
if self.instance.pk and (cleaned_data['parlamentar'].id != self.instance.parlamentar.id): if self.instance.pk and (cleaned_data['parlamentar'].id != self.instance.parlamentar.id):
raise ValidationError("Não é possivel alterar o parlamentar " + str(self.instance.parlamentar)) raise ValidationError("Não é possivel alterar o parlamentar " + str(self.instance.parlamentar))
class AfastamentoParlamentarForm(ModelForm):
logger = logging.getLogger(__name__)
class Meta:
model = AfastamentoParlamentar
fields = ['data_inicio', 'data_fim', 'mandato',
'tipo_afastamento', 'observacao', 'parlamentar']
widgets = {'parlamentar': forms.HiddenInput()}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not (self.instance and self.instance.pk):
parlamentar = kwargs['initial']['parlamentar']
self.fields['mandato'].queryset = Mandato.objects.filter(parlamentar=parlamentar)
self.fields['tipo_afastamento'].queryset = TipoAfastamento.objects.filter(indicador='A')
def clean(self):
super(AfastamentoParlamentarForm, self).clean()
if not self.is_valid():
return self.cleaned_data
data = self.cleaned_data
mandato = data['mandato']
data_inicio_mandato = mandato.data_inicio_mandato
data_fim_mandato = mandato.data_fim_mandato
data_inicio_afastamento = data['data_inicio']
data_fim_afastamento = data['data_fim']
if data_inicio_afastamento < data_inicio_mandato:
self.logger.error("Data início de afastamento ({}) anterior ao inicio"
" do mandato informado ({})."
.format(data_inicio_afastamento, data_inicio_mandato))
raise ValidationError(_("Data início do afastamento anterior ao início"
" do mandato informado."))
if data_fim_mandato and data_inicio_afastamento > data_fim_mandato:
self.logger.error("Data início de afastamento ({}) posterior ao fim"
" do mandato informado ({} a {})."
.format(data_inicio_afastamento, data_fim_mandato))
raise ValidationError(_("Data início do afastamento posterior ao fim"
" do mandato informado."))
if data_fim_afastamento:
if data_fim_afastamento < data_inicio_afastamento:
self.logger.error("Data fim de afastamento ({}) anterior à data início"
" do afastamento ({})."
.format(data_fim_afastamento, data_inicio_afastamento))
raise ValidationError(_("Data fim do afastamento anterior à data início do"
" afastamento."))
if data_fim_afastamento < data_inicio_mandato:
self.logger.error("Data fim de afastamento ({}) anterior ao início"
" do mandato informado ({} a {})."
.format(data_fim_afastamento, data_inicio_mandato))
raise ValidationError(_("Data fim do afastamento anterior ao início"
" do mandato informado."))
if data_fim_mandato and data_fim_afastamento > data_fim_mandato:
self.logger.error("Data fim de afastamento ({}) posterior ao fim"
" do mandato informado ({})."
.format(data_inicio_afastamento, data_fim_mandato))
raise ValidationError(_("Data fim do afastamento posterior ao fim"
" do mandato informado."))
ultimo_afastamento = AfastamentoParlamentar.objects.last()
if ultimo_afastamento and not ultimo_afastamento.data_fim \
and ultimo_afastamento != self.instance:
self.logger.error("Existe Afastamento sem Data Fim.")
raise ValidationError(_("Existe Afastamento sem Data Fim."))
return self.cleaned_data

32
sapl/parlamentares/migrations/0033_afastamentoparlamentar.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-01 15:35
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0032_auto_20190619_1509'),
]
operations = [
migrations.CreateModel(
name='AfastamentoParlamentar',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('data_inicio', models.DateField(null=True, verbose_name='Início do Afastamento')),
('data_fim', models.DateField(blank=True, null=True, verbose_name='Fim do Afastamento')),
('observacao', models.TextField(blank=True, verbose_name='Observação')),
('mandato', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Mandato', verbose_name='Mandato')),
('parlamentar', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='parlamentares.Parlamentar')),
('tipo_afastamento', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='parlamentares.TipoAfastamento', verbose_name='Tipo de Afastamento')),
],
options={
'verbose_name': 'Afastamento',
'verbose_name_plural': 'Afastamentos',
},
),
]

21
sapl/parlamentares/migrations/0034_auto_20190801_1408.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-01 17:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0033_afastamentoparlamentar'),
]
operations = [
migrations.AlterField(
model_name='mandato',
name='tipo_afastamento',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='parlamentares.TipoAfastamento', verbose_name='Tipo de Afastamento'),
),
]

16
sapl/parlamentares/migrations/0035_merge_20190802_0954.py

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-02 12:54
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0033_auto_20190712_1132'),
('parlamentares', '0034_auto_20190801_1408'),
]
operations = [
]

38
sapl/parlamentares/models.py

@ -478,8 +478,12 @@ class TipoAfastamento(models.Model):
@reversion.register() @reversion.register()
class Mandato(models.Model): class Mandato(models.Model):
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.CASCADE) parlamentar = models.ForeignKey(Parlamentar, on_delete=models.CASCADE)
tipo_afastamento = models.ForeignKey( tipo_afastamento = models.ForeignKey(TipoAfastamento,
TipoAfastamento, blank=True, null=True, on_delete=models.PROTECT) blank=True,
null=True,
on_delete=models.PROTECT,
verbose_name=_('Tipo de Afastamento'))
legislatura = models.ForeignKey(Legislatura, on_delete=models.PROTECT, legislatura = models.ForeignKey(Legislatura, on_delete=models.PROTECT,
verbose_name=_('Legislatura')) verbose_name=_('Legislatura'))
coligacao = models.ForeignKey( coligacao = models.ForeignKey(
@ -727,7 +731,6 @@ class CargoBancada(models.Model):
def __str__(self): def __str__(self):
return self.nome_cargo return self.nome_cargo
class CargoBlocoPartido(models.Model): class CargoBlocoPartido(models.Model):
class Meta: class Meta:
verbose_name = _('Vinculo bloco parlamentar') verbose_name = _('Vinculo bloco parlamentar')
@ -748,3 +751,32 @@ class CargoBlocoPartido(models.Model):
data_inicio = models.DateField(verbose_name=_('Data Início')) data_inicio = models.DateField(verbose_name=_('Data Início'))
data_fim = models.DateField(blank=True, null=True, verbose_name=_('Data Fim')) data_fim = models.DateField(blank=True, null=True, verbose_name=_('Data Fim'))
@reversion.register()
class AfastamentoParlamentar(models.Model):
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.CASCADE)
mandato = models.ForeignKey(Mandato, on_delete=models.CASCADE,
verbose_name=_('Mandato'))
tipo_afastamento = models.ForeignKey(TipoAfastamento,
on_delete=models.PROTECT,
verbose_name=_('Tipo de Afastamento'),
blank=True,
null=True)
data_inicio = models.DateField(verbose_name=_('Início do Afastamento'),
blank=False,
null=True)
data_fim = models.DateField(verbose_name=_('Fim do Afastamento'),
blank=True,
null=True)
observacao = models.TextField(verbose_name=_('Observação'),
blank=True)
class Meta:
verbose_name = _('Afastamento')
verbose_name_plural = _('Afastamentos')
def __str__(self):
return _('%(parlamentar)s %(legislatura)s') % {
'parlamentar': self.parlamentar, 'legislatura': self.mandato.legislatura
}

151
sapl/parlamentares/tests/test_parlamentares.py

@ -5,10 +5,12 @@ from model_mommy import mommy
from datetime import datetime from datetime import datetime
from sapl.parlamentares import forms from sapl.parlamentares import forms
from sapl.parlamentares.forms import FrenteForm, LegislaturaForm, MandatoForm from sapl.parlamentares.forms import FrenteForm, LegislaturaForm, MandatoForm, AfastamentoParlamentarForm
from sapl.parlamentares.models import (Dependente, Filiacao, Legislatura, from sapl.parlamentares.models import (Dependente, Filiacao, Legislatura,
Mandato, Parlamentar, Partido, Mandato, Parlamentar, Partido,
TipoDependente) TipoDependente, TipoAfastamento,
AfastamentoParlamentar)
from sapl.utils import verifica_afastamento_parlamentar
@pytest.mark.django_db(transaction=False) @pytest.mark.django_db(transaction=False)
@ -408,3 +410,148 @@ def test_bancada_form_datas_invalidas():
'descricao': 'teste' 'descricao': 'teste'
}) })
assert not form.is_valid() assert not form.is_valid()
@pytest.mark.django_db(transaction=False)
def test_afastamentos_form_datas_invalidas():
parlamentar = mommy.make(Parlamentar)
mandato = mommy.make(Mandato,
parlamentar = parlamentar,
data_inicio_mandato='2017-01-01',
data_fim_mandato='2021-12-31')
tipo_afastamento = mommy.make(TipoAfastamento,
indicador= 'A',
pk=1)
form = AfastamentoParlamentarForm(data={
'parlamentar': parlamentar.pk,
'mandato': mandato.pk,
'data_inicio': '2016-12-12',
'data_fim': '2019-10-09',
'tipo_afastamento': tipo_afastamento.pk
}, initial={'parlamentar': parlamentar.pk})
assert not form.is_valid()
assert form.errors['__all__'] == \
["Data início do afastamento anterior ao início do mandato informado."]
form = AfastamentoParlamentarForm(data={
'parlamentar': parlamentar.pk,
'mandato': mandato.pk,
'data_inicio': '2017-02-02',
'data_fim': '2022-10-09',
'tipo_afastamento': tipo_afastamento.pk
}, initial={'parlamentar': parlamentar.pk})
assert not form.is_valid()
assert form.errors['__all__'] == \
["Data fim do afastamento posterior ao fim do mandato informado."]
form = AfastamentoParlamentarForm(data={
'parlamentar': parlamentar.pk,
'mandato': mandato.pk,
'data_inicio': '2017-02-02',
'data_fim': '2015-10-09',
'tipo_afastamento': tipo_afastamento.pk
}, initial={'parlamentar': parlamentar.pk})
assert not form.is_valid()
assert form.errors['__all__'] == \
["Data fim do afastamento anterior à data início do afastamento."]
form = AfastamentoParlamentarForm(data={
'parlamentar': parlamentar.pk,
'mandato': mandato.pk,
'data_inicio': '2017-02-02',
'tipo_afastamento': tipo_afastamento.pk
}, initial={'parlamentar': parlamentar.pk})
assert form.is_valid()
form.save()
assert AfastamentoParlamentar.objects.all().count() == 1
form = AfastamentoParlamentarForm(data={
'parlamentar': parlamentar.pk,
'mandato': mandato.pk,
'data_inicio': '2018-04-02',
'data_fim': '2018-06-09',
'tipo_afastamento': tipo_afastamento.pk
}, initial={'parlamentar': parlamentar.pk})
assert not form.is_valid()
assert form.errors['__all__'] == \
["Existe Afastamento sem Data Fim."]
afastamento = AfastamentoParlamentar.objects.first()
afastamento.data_fim = '2017-04-02'
afastamento.save()
assert AfastamentoParlamentar.objects.first().data_fim == data('2017-04-02')
form = AfastamentoParlamentarForm(data={
'parlamentar': parlamentar.pk,
'mandato': mandato.pk,
'data_inicio': '2018-04-02',
'data_fim': '2018-06-09',
'tipo_afastamento': tipo_afastamento.pk
}, initial={'parlamentar': parlamentar.pk})
assert form.is_valid()
@pytest.mark.django_db(transaction=False)
def test_afastamentos_form_campos_invalidos():
parlamentar = mommy.make(Parlamentar)
mandato = mommy.make(Mandato,
parlamentar = parlamentar,
data_inicio_mandato='2017-01-01',
data_fim_mandato='2021-12-31')
tipo_afastamento = mommy.make(TipoAfastamento,
indicador= 'A',
pk=1)
form = AfastamentoParlamentarForm(data={}, initial={'parlamentar': parlamentar.pk})
assert not form.is_valid()
assert form.errors['data_inicio'] == ["Este campo é obrigatório."]
assert form.errors['mandato'] == ["Este campo é obrigatório."]
assert form.errors['parlamentar'] == ["Este campo é obrigatório."]
@pytest.mark.django_db(transaction=False)
def test_parlamentar_esta_afastado():
parlamentar = mommy.make(Parlamentar)
mandato = mommy.make(Mandato,
parlamentar = parlamentar,
data_inicio_mandato='2017-01-01',
data_fim_mandato='2021-12-31')
afastamento = AfastamentoParlamentar.objects.create(mandato=mandato,
parlamentar=parlamentar,
data_inicio='2017-12-05',
data_fim='2017-12-12')
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-06')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-13')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-04')
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-06', '2017-12-11')
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-06', '2017-12-06')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-03', '2017-12-04')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-13', '2017-12-15')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-15', '2017-12-15')
afastamento = AfastamentoParlamentar.objects.create(mandato=mandato,
parlamentar=parlamentar,
data_inicio='2017-12-05')
assert AfastamentoParlamentar.objects.all().count() == 2
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-06')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-13')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-04')
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-06', '2017-12-11')
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-06', '2017-12-06')
assert not verifica_afastamento_parlamentar(parlamentar, '2017-12-03', '2017-12-04')
assert verifica_afastamento_parlamentar(parlamentar, '2017-12-13', '2017-12-15')

3
sapl/parlamentares/urls.py

@ -12,6 +12,7 @@ from sapl.parlamentares.views import (CargoMesaCrud, ColigacaoCrud,
RelatoriaParlamentarCrud, RelatoriaParlamentarCrud,
SessaoLegislativaCrud, SessaoLegislativaCrud,
TipoAfastamentoCrud, TipoDependenteCrud, TipoAfastamentoCrud, TipoDependenteCrud,
AfastamentoParlamentarCrud,
TipoMilitarCrud, VotanteView, TipoMilitarCrud, VotanteView,
altera_field_mesa, altera_field_mesa,
altera_field_mesa_public_view, altera_field_mesa_public_view,
@ -42,7 +43,7 @@ urlpatterns = [
ParticipacaoParlamentarCrud.get_urls() + ParticipacaoParlamentarCrud.get_urls() +
ProposicaoParlamentarCrud.get_urls() + ProposicaoParlamentarCrud.get_urls() +
RelatoriaParlamentarCrud.get_urls() + FrenteList.get_urls() + RelatoriaParlamentarCrud.get_urls() + FrenteList.get_urls() +
VotanteView.get_urls() VotanteView.get_urls() + AfastamentoParlamentarCrud.get_urls()
)), )),
url(r'^parlamentar/lista$', lista_parlamentares, name='lista_parlamentares'), url(r'^parlamentar/lista$', lista_parlamentares, name='lista_parlamentares'),

41
sapl/parlamentares/views.py

@ -38,13 +38,13 @@ from .forms import (FiliacaoForm, FrenteForm, LegislaturaForm, MandatoForm,
ParlamentarCreateForm, ParlamentarForm, VotanteForm, ParlamentarCreateForm, ParlamentarForm, VotanteForm,
ParlamentarFilterSet, VincularParlamentarForm, ParlamentarFilterSet, VincularParlamentarForm,
BlocoForm, CargoBlocoForm, CargoBlocoPartidoForm, BlocoForm, CargoBlocoForm, CargoBlocoPartidoForm,
BancadaForm) BancadaForm, AfastamentoParlamentarForm)
from .models import (Bancada, CargoBancada, CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa, from .models import (Bancada, CargoBancada, CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
Dependente, Filiacao, Frente, Legislatura, Mandato, Dependente, Filiacao, Frente, Legislatura, Mandato,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa, NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
SituacaoMilitar, TipoAfastamento, TipoDependente, Votante, SituacaoMilitar, TipoAfastamento, TipoDependente, Votante,
Bloco, CargoBlocoPartido, HistoricoPartido, CargoBloco) Bloco, CargoBlocoPartido, HistoricoPartido, CargoBloco, AfastamentoParlamentar)
CargoBancadaCrud = CrudAux.build(CargoBancada, '') CargoBancadaCrud = CrudAux.build(CargoBancada, '')
@ -1298,3 +1298,40 @@ def deleta_vinculo_parlamentar_bloco(request,pk):
'sapl.parlamentares:bloco_detail', 'sapl.parlamentares:bloco_detail',
kwargs={'pk': pk_bloco}) kwargs={'pk': pk_bloco})
) )
class AfastamentoParlamentarCrud(PermissionRequiredMixin, MasterDetailCrud):
model = AfastamentoParlamentar
parent_field = 'parlamentar'
public = [RP_DETAIL, RP_LIST]
list_field_names = ['mandato__legislatura',
'data_inicio',
'data_fim',
'tipo_afastamento']
class ListView(MasterDetailCrud.ListView):
ordering = ('-mandato__legislatura__numero', '-data_inicio')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
rows = context['rows']
coluna_coligacao = 2
coluna_votos_recebidos = 3
for row in rows:
if not row[coluna_coligacao][0]:
row[coluna_coligacao] = (' ', None)
if not row[coluna_votos_recebidos][0]:
row[coluna_votos_recebidos] = (' ', None)
return context
class CreateView(MasterDetailCrud.CreateView):
form_class = AfastamentoParlamentarForm
def get_initial(self):
parlamentar = Parlamentar.objects.get(pk=self.kwargs['pk'])
return {'parlamentar': parlamentar}
class UpdateView(MasterDetailCrud.UpdateView):
form_class = AfastamentoParlamentarForm

83
sapl/protocoloadm/views.py

@ -34,10 +34,10 @@ from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa, Unid
from sapl.materia.views import gerar_pdf_impressos from sapl.materia.views import gerar_pdf_impressos
from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
from sapl.relatorios.views import relatorio_doc_administrativos
from sapl.utils import (create_barcode, get_base_url, get_client_ip, from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, lista_anexados, get_mime_type_from_file_extension, lista_anexados,
show_results_filter_set, mail_service_configured) show_results_filter_set, mail_service_configured)
from sapl.relatorios.views import relatorio_doc_administrativos
from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm, from .forms import (AcompanhamentoDocumentoForm, AnularProtocoloAdmForm,
DocumentoAcessorioAdministrativoForm, DocumentoAcessorioAdministrativoForm,
@ -302,7 +302,7 @@ class AcompanhamentoDocumentoView(CreateView):
return self.render_to_response( return self.render_to_response(
{'form': form, {'form': form,
'documento': documento, 'documento': documento,
}) })
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
else: else:
return self.render_to_response( return self.render_to_response(
@ -373,13 +373,13 @@ class DocumentoAdministrativoCrud(Crud):
return redirect('/') return redirect('/')
return super(Crud.DetailView, self).get(args, kwargs) return super(Crud.DetailView, self).get(args, kwargs)
def get_context_data(self, **kwargs): def urlize(self, obj, fieldname):
context = super().get_context_data(**kwargs) a = '<a href="%s">%s</a>' % (
self.layout_display[0]['rows'][-1][0]['text'] = ( reverse(
'<a href="%s"></a>' % reverse(
'sapl.protocoloadm:doc_texto_integral', 'sapl.protocoloadm:doc_texto_integral',
kwargs={'pk': self.object.pk})) kwargs={'pk': obj.pk}),
return context obj.texto_integral.name.split('/')[-1])
return obj.texto_integral.field.verbose_name, a
class DeleteView(Crud.DeleteView): class DeleteView(Crud.DeleteView):
@ -551,7 +551,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
).sequencia_numeracao_protocolo ).sequencia_numeracao_protocolo
if not numeracao: if not numeracao:
self.logger.error("user=" + username + ". É preciso definir a sequencia de " self.logger.error("user=" + username + ". É preciso definir a sequencia de "
"numeração na tabelas auxiliares! " + str(e)) "numeração na tabelas auxiliares! ")
msg = _('É preciso definir a sequencia de ' + msg = _('É preciso definir a sequencia de ' +
'numeração na tabelas auxiliares!') 'numeração na tabelas auxiliares!')
messages.add_message(self.request, messages.ERROR, msg) messages.add_message(self.request, messages.ERROR, msg)
@ -936,7 +936,7 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
else: else:
length = self.object_list.count() length = self.object_list.count()
is_relatorio = url!='' and request.GET.get('relatorio',None) is_relatorio = url != '' and request.GET.get('relatorio', None)
self.paginate_by = None if is_relatorio else self.paginate_by self.paginate_by = None if is_relatorio else self.paginate_by
context = self.get_context_data(filter=self.filterset, context = self.get_context_data(filter=self.filterset,
filter_url=url, filter_url=url,
@ -946,10 +946,11 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
self.request.GET.copy()) self.request.GET.copy())
if is_relatorio: if is_relatorio:
return relatorio_doc_administrativos(request,context) return relatorio_doc_administrativos(request, context)
else: else:
return self.render_to_response(context) return self.render_to_response(context)
class AnexadoCrud(MasterDetailCrud): class AnexadoCrud(MasterDetailCrud):
model = Anexado model = Anexado
parent_field = 'documento_principal' parent_field = 'documento_principal'
@ -987,7 +988,7 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super( context = super(
DocumentoAnexadoEmLoteView, self DocumentoAnexadoEmLoteView, self
).get_context_data(**kwargs) ).get_context_data(**kwargs)
context['root_pk'] = self.kwargs['pk'] context['root_pk'] = self.kwargs['pk']
@ -997,17 +998,17 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
# Verifica se os campos foram preenchidos # Verifica se os campos foram preenchidos
if not self.request.GET.get('tipo', " "): if not self.request.GET.get('tipo', " "):
msg =_('Por favor, selecione um tipo de documento.') msg = _('Por favor, selecione um tipo de documento.')
messages.add_message(self.request, messages.ERROR, msg) messages.add_message(self.request, messages.ERROR, msg)
if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "): if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "):
msg =_('Por favor, preencha as datas.') msg = _('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg) messages.add_message(self.request, messages.ERROR, msg)
return context return context
if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "): if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "):
msg =_('Por favor, preencha as datas.') msg = _('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg) messages.add_message(self.request, messages.ERROR, msg)
return context return context
@ -1019,13 +1020,15 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
context['object_list'] = [] context['object_list'] = []
for obj in context['temp_object_list']: for obj in context['temp_object_list']:
if not obj.pk == int(context['root_pk']): if not obj.pk == int(context['root_pk']):
documento_principal = DocumentoAdministrativo.objects.get(id=context['root_pk']) documento_principal = DocumentoAdministrativo.objects.get(
id=context['root_pk'])
documento_anexado = obj documento_anexado = obj
is_anexado = Anexado.objects.filter(documento_principal=documento_principal, is_anexado = Anexado.objects.filter(documento_principal=documento_principal,
documento_anexado=documento_anexado).exists() documento_anexado=documento_anexado).exists()
if not is_anexado: if not is_anexado:
ciclico = False ciclico = False
anexados_anexado = Anexado.objects.filter(documento_principal=documento_anexado) anexados_anexado = Anexado.objects.filter(
documento_principal=documento_anexado)
while anexados_anexado and not ciclico: while anexados_anexado and not ciclico:
anexados = [] anexados = []
@ -1068,22 +1071,22 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
v_data_desanexacao = data_desanexacao v_data_desanexacao = data_desanexacao
if len(marcados) == 0: if len(marcados) == 0:
msg =_('Nenhum documento foi selecionado') msg = _('Nenhum documento foi selecionado')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
if data_anexacao > v_data_desanexacao: if data_anexacao > v_data_desanexacao:
msg=_('Data de anexação posterior à data de desanexação.') msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
if data_anexacao > v_data_desanexacao: if data_anexacao > v_data_desanexacao:
msg =_('Data de anexação posterior à data de desanexação.') msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, messages.ERROR, msg) return self.get(request, messages.ERROR, msg)
principal = DocumentoAdministrativo.objects.get(pk = kwargs['pk']) principal = DocumentoAdministrativo.objects.get(pk=kwargs['pk'])
for documento in DocumentoAdministrativo.objects.filter(id__in = marcados): for documento in DocumentoAdministrativo.objects.filter(id__in=marcados):
anexado = Anexado() anexado = Anexado()
anexado.documento_principal = principal anexado.documento_principal = principal
anexado.documento_anexado = documento anexado.documento_anexado = documento
@ -1094,7 +1097,8 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
msg = _('Documento(s) anexado(s).') msg = _('Documento(s) anexado(s).')
messages.add_message(request, messages.SUCCESS, msg) messages.add_message(request, messages.SUCCESS, msg)
success_url = reverse('sapl.protocoloadm:anexado_list', kwargs={'pk': kwargs['pk']}) success_url = reverse('sapl.protocoloadm:anexado_list', kwargs={
'pk': kwargs['pk']})
return HttpResponseRedirect(success_url) return HttpResponseRedirect(success_url)
@ -1142,7 +1146,8 @@ class TramitacaoAdmCrud(MasterDetailCrud):
'-timestamp', '-timestamp',
'-id').first() '-id').first()
#TODO: Esta checagem foi inserida na issue #2027, mas é mesmo necessária? # TODO: Esta checagem foi inserida na issue #2027, mas é mesmo
# necessária?
if ultima_tramitacao: if ultima_tramitacao:
if ultima_tramitacao.unidade_tramitacao_destino: if ultima_tramitacao.unidade_tramitacao_destino:
context['form'].fields[ context['form'].fields[
@ -1230,7 +1235,6 @@ class TramitacaoAdmCrud(MasterDetailCrud):
context['user'] = self.request.user context['user'] = self.request.user
return context return context
class DeleteView(MasterDetailCrud.DeleteView): class DeleteView(MasterDetailCrud.DeleteView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -1271,7 +1275,8 @@ class TramitacaoAdmCrud(MasterDetailCrud):
if da.tramitacaoadministrativo_set.count() == 0: if da.tramitacaoadministrativo_set.count() == 0:
da.tramitacao = False da.tramitacao = False
da.save() da.save()
TramitacaoAdministrativo.objects.filter(id__in=tramitacoes_deletar).delete() TramitacaoAdministrativo.objects.filter(
id__in=tramitacoes_deletar).delete()
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
@ -1464,7 +1469,6 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PrimeiraTramitacaoEmLoteAdmView, context = super(PrimeiraTramitacaoEmLoteAdmView,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
@ -1487,7 +1491,7 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
context['title'] = _('Primeira Tramitação em Lote') context['title'] = _('Primeira Tramitação em Lote')
# Pega somente documentos que não possuem tramitação # Pega somente documentos que não possuem tramitação
context['object_list'] = [obj for obj in context['object_list'] context['object_list'] = [obj for obj in context['object_list']
if obj.tramitacaoadministrativo_set.all().count() == 0] if obj.tramitacaoadministrativo_set.all().count() == 0]
else: else:
context['title'] = _('Tramitação em Lote') context['title'] = _('Tramitação em Lote')
context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get( context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
@ -1510,31 +1514,32 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
form = TramitacaoEmLoteAdmForm(request.POST, form = TramitacaoEmLoteAdmForm(request.POST,
initial= {'documentos': documentos_ids, initial={'documentos': documentos_ids,
'user': user, 'ip':ip}) 'user': user, 'ip': ip})
if form.is_valid(): if form.is_valid():
form.save() form.save()
msg = _('Tramitação completa.') msg = _('Tramitação completa.')
self.logger.info('user=' + user.username + '. Tramitação completa.') self.logger.info('user=' + user.username +
'. Tramitação completa.')
messages.add_message(request, messages.SUCCESS, msg) messages.add_message(request, messages.SUCCESS, msg)
return self.get_success_url() return self.get_success_url()
return self.form_invalid(form) return self.form_invalid(form)
def get_success_url(self): def get_success_url(self):
return HttpResponseRedirect(reverse('sapl.protocoloadm:primeira_tramitacao_em_lote_docadm')) return HttpResponseRedirect(reverse('sapl.protocoloadm:primeira_tramitacao_em_lote_docadm'))
def form_invalid(self, form, *args, **kwargs): def form_invalid(self, form, *args, **kwargs):
for key, erros in form.errors.items(): for key, erros in form.errors.items():
if not key=='__all__': if not key == '__all__':
[messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros] [messages.add_message(
self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
else: else:
[messages.add_message(self.request, messages.ERROR, e) for e in erros] [messages.add_message(self.request, messages.ERROR, e)
return self.get(self.request, kwargs, {'form':form}) for e in erros]
return self.get(self.request, kwargs, {'form': form})
class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView): class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
@ -1562,21 +1567,18 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
return context return context
def pega_ultima_tramitacao(self): def pega_ultima_tramitacao(self):
return TramitacaoAdministrativo.objects.values( return TramitacaoAdministrativo.objects.values(
'documento_id').annotate(data_encaminhamento=Max( 'documento_id').annotate(data_encaminhamento=Max(
'data_encaminhamento'), 'data_encaminhamento'),
id=Max('id')).values_list('id', flat=True) id=Max('id')).values_list('id', flat=True)
def filtra_tramitacao_status(self, status): def filtra_tramitacao_status(self, status):
lista = self.pega_ultima_tramitacao() lista = self.pega_ultima_tramitacao()
return TramitacaoAdministrativo.objects.filter( return TramitacaoAdministrativo.objects.filter(
id__in=lista, id__in=lista,
status=status).distinct().values_list('documento_id', flat=True) status=status).distinct().values_list('documento_id', flat=True)
def filtra_tramitacao_destino(self, destino): def filtra_tramitacao_destino(self, destino):
lista = self.pega_ultima_tramitacao() lista = self.pega_ultima_tramitacao()
return TramitacaoAdministrativo.objects.filter( return TramitacaoAdministrativo.objects.filter(
@ -1584,7 +1586,6 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView):
unidade_tramitacao_destino=destino).distinct().values_list( unidade_tramitacao_destino=destino).distinct().values_list(
'documento_id', flat=True) 'documento_id', flat=True)
def filtra_tramitacao_destino_and_status(self, status, destino): def filtra_tramitacao_destino_and_status(self, status, destino):
lista = self.pega_ultima_tramitacao() lista = self.pega_ultima_tramitacao()
return TramitacaoAdministrativo.objects.filter( return TramitacaoAdministrativo.objects.filter(

14
sapl/relatorios/templates/pdf_pauta_sessao_gerar.py

@ -112,6 +112,17 @@ def inf_basicas(inf_basicas_dic):
return tmp return tmp
def build_expedientes(expedientes):
"""
"""
tmp = ""
tmp += '\t\t<para style="P1">Expedientes</para>\n'
for e in expedientes:
tmp += '\t\t\t<para style="P2" spaceAfter="5"><b>{}:</b></para>'.format(e['tipo'])
tmp += '\t\t\t <para style="P2" spaceAfter="5"><p>{}</p></para>'.format(e['conteudo'])
return tmp
def expediente_materia(lst_expediente_materia): def expediente_materia(lst_expediente_materia):
""" """
@ -168,7 +179,7 @@ def votacao(lst_votacao):
return tmp return tmp
def principal(rodape_dic, imagem, inf_basicas_dic, lst_expediente_materia, lst_votacao): def principal(rodape_dic, imagem, inf_basicas_dic, lst_expediente_materia, lst_votacao, expedientes):
""" """
""" """
@ -190,6 +201,7 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_expediente_materia, lst_v
tmp += paraStyle() tmp += paraStyle()
tmp += '\t<story>\n' tmp += '\t<story>\n'
tmp += inf_basicas(inf_basicas_dic) tmp += inf_basicas(inf_basicas_dic)
tmp += build_expedientes(expedientes)
tmp += expediente_materia(lst_expediente_materia) tmp += expediente_materia(lst_expediente_materia)
tmp += votacao(lst_votacao) tmp += votacao(lst_votacao)
tmp += '\t</story>\n' tmp += '\t</story>\n'

33
sapl/relatorios/views.py

@ -4,11 +4,13 @@ import logging
import re import re
import tempfile import tempfile
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.html import strip_tags
from sapl.settings import MEDIA_URL from sapl.settings import MEDIA_URL
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
@ -23,16 +25,16 @@ from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
Orador, OradorExpediente, Orador, OradorExpediente,
OrdemDia, PresencaOrdemDia, SessaoPlenaria, OrdemDia, PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca, OcorrenciaSessao, SessaoPlenariaPresenca, OcorrenciaSessao,
RegistroVotacao, VotoParlamentar, OradorOrdemDia) RegistroVotacao, VotoParlamentar, OradorOrdemDia, TipoExpediente)
from sapl.settings import STATIC_ROOT from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data
from sapl.sessao.views import (get_identificação_basica, get_mesa_diretora, from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora,
get_presenca_sessao, get_expedientes, get_presenca_sessao, get_expedientes,
get_materias_expediente, get_oradores_expediente, get_materias_expediente, get_oradores_expediente,
get_presenca_ordem_do_dia, get_materias_ordem_do_dia, get_presenca_ordem_do_dia, get_materias_ordem_do_dia,
get_oradores_ordemdia, get_oradores_ordemdia,
get_oradores_explicações_pessoais, get_ocorrencias_da_sessão, get_assinaturas) get_oradores_explicacoes_pessoais, get_ocorrencias_da_sessao, get_assinaturas)
from .templates import (pdf_capa_processo_gerar, from .templates import (pdf_capa_processo_gerar,
pdf_documento_administrativo_gerar, pdf_espelho_gerar, pdf_documento_administrativo_gerar, pdf_espelho_gerar,
@ -1155,13 +1157,14 @@ def relatorio_pauta_sessao(request, pk):
sessao = SessaoPlenaria.objects.get(id=pk) sessao = SessaoPlenaria.objects.get(id=pk)
lst_expediente_materia, lst_votacao, inf_basicas_dic = get_pauta_sessao( lst_expediente_materia, lst_votacao, inf_basicas_dic, expedientes = get_pauta_sessao(
sessao, casa) sessao, casa)
pdf = pdf_pauta_sessao_gerar.principal(rodape, pdf = pdf_pauta_sessao_gerar.principal(rodape,
imagem, imagem,
inf_basicas_dic, inf_basicas_dic,
lst_expediente_materia, lst_expediente_materia,
lst_votacao) lst_votacao,
expedientes)
response.write(pdf) response.write(pdf)
@ -1262,9 +1265,20 @@ def get_pauta_sessao(sessao, casa):
lst_votacao.append(dic_votacao) lst_votacao.append(dic_votacao)
expediente = ExpedienteSessao.objects.filter(
sessao_plenaria_id=sessao.id)
expedientes = []
for e in expediente:
tipo = e.tipo
conteudo = re.sub(
'&nbsp;', ' ', strip_tags(e.conteudo.replace('<br/>', '\n')))
ex = {'tipo': tipo, 'conteudo': conteudo}
expedientes.append(ex)
return (lst_expediente_materia, return (lst_expediente_materia,
lst_votacao, lst_votacao,
inf_basicas_dic) inf_basicas_dic,
expedientes)
def make_pdf(base_url,main_template,header_template,main_css='',header_css=''): def make_pdf(base_url,main_template,header_template,main_css='',header_css=''):
html = HTML(base_url=base_url, string=main_template) html = HTML(base_url=base_url, string=main_template)
@ -1301,7 +1315,7 @@ def resumo_ata_pdf(request,pk):
sessao_plenaria = SessaoPlenaria.objects.get(pk=pk) sessao_plenaria = SessaoPlenaria.objects.get(pk=pk)
context = {} context = {}
context.update(get_identificação_basica(sessao_plenaria)) context.update(get_identificacao_basica(sessao_plenaria))
context.update(get_mesa_diretora(sessao_plenaria)) context.update(get_mesa_diretora(sessao_plenaria))
context.update(get_presenca_sessao(sessao_plenaria)) context.update(get_presenca_sessao(sessao_plenaria))
context.update(get_expedientes(sessao_plenaria)) context.update(get_expedientes(sessao_plenaria))
@ -1310,8 +1324,8 @@ def resumo_ata_pdf(request,pk):
context.update(get_presenca_ordem_do_dia(sessao_plenaria)) context.update(get_presenca_ordem_do_dia(sessao_plenaria))
context.update(get_materias_ordem_do_dia(sessao_plenaria)) context.update(get_materias_ordem_do_dia(sessao_plenaria))
context.update(get_oradores_ordemdia(sessao_plenaria)) context.update(get_oradores_ordemdia(sessao_plenaria))
context.update(get_oradores_explicações_pessoais(sessao_plenaria)) context.update(get_oradores_explicacoes_pessoais(sessao_plenaria))
context.update(get_ocorrencias_da_sessão(sessao_plenaria)) context.update(get_ocorrencias_da_sessao(sessao_plenaria))
context.update(get_assinaturas(sessao_plenaria)) context.update(get_assinaturas(sessao_plenaria))
context.update({'object': sessao_plenaria}) context.update({'object': sessao_plenaria})
context.update({'data': dt.today().strftime('%d/%m/%Y')}) context.update({'data': dt.today().strftime('%d/%m/%Y')})
@ -1411,7 +1425,6 @@ def relatorio_sessao_plenaria_pdf(request, pk):
Legislatura".format(inf_basicas_dic['num_sessao_plen'], Legislatura".format(inf_basicas_dic['num_sessao_plen'],
inf_basicas_dic['nom_sessao'], inf_basicas_dic['nom_sessao'],
inf_basicas_dic['num_sessao_leg'], inf_basicas_dic['num_sessao_leg'],
inf_basicas_dic['num_legislatura'],
inf_basicas_dic['num_legislatura'] inf_basicas_dic['num_legislatura']
) )

1
sapl/rules/map_rules.py

@ -287,6 +287,7 @@ rules_group_geral = {
(parlamentares.Bloco, __base__, __perms_publicas__), (parlamentares.Bloco, __base__, __perms_publicas__),
(parlamentares.CargoBloco, __base__, __perms_publicas__), (parlamentares.CargoBloco, __base__, __perms_publicas__),
(parlamentares.CargoBlocoPartido, __base__, __perms_publicas__), (parlamentares.CargoBlocoPartido, __base__, __perms_publicas__),
(parlamentares.AfastamentoParlamentar, __base__, __perms_publicas__),
(sessao.TipoSessaoPlenaria, __base__, __perms_publicas__), (sessao.TipoSessaoPlenaria, __base__, __perms_publicas__),
(sessao.TipoResultadoVotacao, __base__, __perms_publicas__), (sessao.TipoResultadoVotacao, __base__, __perms_publicas__),

22
sapl/sessao/forms.py

@ -22,7 +22,7 @@ from sapl.parlamentares.models import Parlamentar, Mandato
from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES, from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
MateriaPesquisaOrderingFilter, autor_label, MateriaPesquisaOrderingFilter, autor_label,
autor_modal, timezone, choice_anos_com_sessaoplenaria, autor_modal, timezone, choice_anos_com_sessaoplenaria,
FileFieldCheckMixin) FileFieldCheckMixin, verifica_afastamento_parlamentar)
from .models import (ExpedienteMateria, JustificativaAusencia, from .models import (ExpedienteMateria, JustificativaAusencia,
Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria,
@ -599,8 +599,14 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
class OradorForm(ModelForm): class OradorForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['parlamentar'].queryset = \ sessao = SessaoPlenaria.objects.get(id=kwargs['initial']['id_sessao'])
Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar') parlamentares_ativos = Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
for p in parlamentares_ativos:
if verifica_afastamento_parlamentar(p, sessao.data_inicio, sessao.data_fim):
parlamentares_ativos = parlamentares_ativos.exclude(id=p.id)
self.fields['parlamentar'].queryset = parlamentares_ativos
def clean(self): def clean(self):
super(OradorForm, self).clean() super(OradorForm, self).clean()
@ -641,9 +647,13 @@ class OradorExpedienteForm(ModelForm):
id_sessao = int(self.initial['id_sessao']) id_sessao = int(self.initial['id_sessao'])
sessao = SessaoPlenaria.objects.get(id=id_sessao) sessao = SessaoPlenaria.objects.get(id=id_sessao)
legislatura_vigente = sessao.legislatura legislatura_vigente = sessao.legislatura
self.fields['parlamentar'].queryset = \
Parlamentar.objects.filter(mandato__legislatura=legislatura_vigente, parlamentares_ativos = Parlamentar.objects.filter(ativo=True).order_by('nome_parlamentar')
ativo=True).order_by('nome_parlamentar') for p in parlamentares_ativos:
if verifica_afastamento_parlamentar(p, sessao.data_inicio, sessao.data_fim):
parlamentares_ativos = parlamentares_ativos.exclude(id=p.id)
self.fields['parlamentar'].queryset = parlamentares_ativos
def clean(self): def clean(self):
super(OradorExpedienteForm, self).clean() super(OradorExpedienteForm, self).clean()

24
sapl/sessao/migrations/0045_auto_20190809_1319.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-09 16:19
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0044_merge_20190802_1117'),
]
operations = [
migrations.AlterModelOptions(
name='tipoexpediente',
options={'ordering': ['ordenacao'], 'verbose_name': 'Tipo de Expediente', 'verbose_name_plural': 'Tipos de Expediente'},
),
migrations.AddField(
model_name='tipoexpediente',
name='ordenacao',
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Ordenação'),
),
]

24
sapl/sessao/migrations/0046_auto_20190809_1319.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-08-09 16:19
from __future__ import unicode_literals
from django.db import migrations
def migra_ordenacao_tipos(apps, schema_editor):
TipoExpediente = apps.get_model('sessao', 'TipoExpediente')
for i,tipo in enumerate(TipoExpediente.objects.all().order_by('nome')):
tipo.ordenacao=i+1
tipo.save()
class Migration(migrations.Migration):
dependencies = [
('sessao', '0045_auto_20190809_1319'),
]
operations = [
migrations.RunPython(migra_ordenacao_tipos)
]

8
sapl/sessao/models.py

@ -172,7 +172,7 @@ class SessaoPlenaria(models.Model):
if self.tipo.tipo_numeracao == tnc.quizenal: if self.tipo.tipo_numeracao == tnc.quizenal:
base += ' da {}ª Quinzena'.format( base += ' da {}ª Quinzena'.format(
1 if self.data_inicio.day > 15 else 2) 1 if self.data_inicio.day <= 15 else 2)
if self.tipo.tipo_numeracao <= tnc.mensal: if self.tipo.tipo_numeracao <= tnc.mensal:
base += ' do mês de {}'.format( base += ' do mês de {}'.format(
@ -295,11 +295,15 @@ class ExpedienteMateria(AbstractOrdemDia):
@reversion.register() @reversion.register()
class TipoExpediente(models.Model): class TipoExpediente(models.Model):
nome = models.CharField(max_length=100, verbose_name=_('Tipo')) nome = models.CharField(max_length=100, verbose_name=_('Tipo'))
ordenacao = models.PositiveIntegerField(
blank=True,
null=True,
verbose_name=_("Ordenação"))
class Meta: class Meta:
verbose_name = _('Tipo de Expediente') verbose_name = _('Tipo de Expediente')
verbose_name_plural = _('Tipos de Expediente') verbose_name_plural = _('Tipos de Expediente')
ordering = ['nome'] ordering = ['ordenacao']
def __str__(self): def __str__(self):
return self.nome return self.nome

18
sapl/sessao/tests/test_sessao_view.py

@ -12,12 +12,12 @@ from sapl.sessao.models import (SessaoPlenaria, TipoSessaoPlenaria,
from sapl.parlamentares.models import Parlamentar, CargoMesa, Filiacao from sapl.parlamentares.models import Parlamentar, CargoMesa, Filiacao
from sapl.sessao.views import (get_identificação_basica, get_conteudo_multimidia, from sapl.sessao.views import (get_identificacao_basica, get_conteudo_multimidia,
get_mesa_diretora, get_presenca_sessao, get_mesa_diretora, get_presenca_sessao,
get_expedientes, get_materias_expediente, get_expedientes, get_materias_expediente,
get_oradores_expediente, get_presenca_ordem_do_dia, get_oradores_expediente, get_presenca_ordem_do_dia,
get_materias_ordem_do_dia, get_oradores_explicações_pessoais, get_materias_ordem_do_dia, get_oradores_explicacoes_pessoais,
get_ocorrencias_da_sessão get_ocorrencias_da_sessao
) )
@ -74,8 +74,8 @@ class TestResumoView():
cargo=self.cargo_mesa) cargo=self.cargo_mesa)
self.integrante_mesa.save() self.integrante_mesa.save()
def test_get_identificação_basica(self): def test_get_identificacao_basica(self):
id_basica = get_identificação_basica(self.sessao_plenaria) id_basica = get_identificacao_basica(self.sessao_plenaria)
info_basica = id_basica['basica'] info_basica = id_basica['basica']
assert info_basica[0] == 'Tipo de Sessão: ' + str(self.sessao_plenaria.tipo) assert info_basica[0] == 'Tipo de Sessão: ' + str(self.sessao_plenaria.tipo)
@ -129,12 +129,12 @@ class TestResumoView():
def test_get_materias_expediente(self): def test_get_materias_expediente(self):
pass pass
def test_get_oradores_explicações_pessoais(self): def test_get_oradores_explicacoes_pessoais(self):
parlamentar = mommy.make(Parlamentar) parlamentar = mommy.make(Parlamentar)
partido_sigla = mommy.make(Filiacao, parlamentar=parlamentar) partido_sigla = mommy.make(Filiacao, parlamentar=parlamentar)
orador = mommy.make(Orador,sessao_plenaria=self.sessao_plenaria,parlamentar=parlamentar) orador = mommy.make(Orador,sessao_plenaria=self.sessao_plenaria,parlamentar=parlamentar)
resultado_get_oradores = get_oradores_explicações_pessoais(self.sessao_plenaria) resultado_get_oradores = get_oradores_explicacoes_pessoais(self.sessao_plenaria)
assert resultado_get_oradores['oradores_explicacoes'] == [{ assert resultado_get_oradores['oradores_explicacoes'] == [{
'numero_ordem': orador.numero_ordem, 'numero_ordem': orador.numero_ordem,
@ -142,8 +142,8 @@ class TestResumoView():
'sgl_partido': partido_sigla.partido.sigla 'sgl_partido': partido_sigla.partido.sigla
}] }]
def test_get_ocorrencias_da_sessão(self): def test_get_ocorrencias_da_sessao(self):
ocorrencia = mommy.make(OcorrenciaSessao, sessao_plenaria=self.sessao_plenaria) ocorrencia = mommy.make(OcorrenciaSessao, sessao_plenaria=self.sessao_plenaria)
resultado_get_ocorrencia = get_ocorrencias_da_sessão(self.sessao_plenaria) resultado_get_ocorrencia = get_ocorrencias_da_sessao(self.sessao_plenaria)
assert resultado_get_ocorrencia['ocorrencias_da_sessao'][0] == ocorrencia assert resultado_get_ocorrencia['ocorrencias_da_sessao'][0] == ocorrencia

117
sapl/sessao/views.py

@ -35,10 +35,12 @@ from sapl.materia.models import (Autoria, TipoMateriaLegislativa,
from sapl.materia.views import MateriaLegislativaPesquisaView from sapl.materia.views import MateriaLegislativaPesquisaView
from sapl.painel.models import Cronometro, PainelConfig from sapl.painel.models import Cronometro, PainelConfig
from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato,
Parlamentar, SessaoLegislativa) Parlamentar, SessaoLegislativa,
AfastamentoParlamentar)
from sapl.sessao.apps import AppConfig from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip, filiacao_data from sapl.utils import (show_results_filter_set, remover_acentos, get_client_ip, filiacao_data,
verifica_afastamento_parlamentar)
from .forms import (AdicionarVariasMateriasFilterSet, ExpedienteForm, from .forms import (AdicionarVariasMateriasFilterSet, ExpedienteForm,
JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm, JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm,
@ -461,10 +463,12 @@ def get_presencas_generic(model, sessao, legislatura):
legislatura=legislatura).order_by('parlamentar__nome_parlamentar') legislatura=legislatura).order_by('parlamentar__nome_parlamentar')
for m in mandato: for m in mandato:
if m.parlamentar in presentes: parlamentar = m.parlamentar
yield (m.parlamentar, True) p_afastado = verifica_afastamento_parlamentar(parlamentar, sessao.data_inicio, sessao.data_fim)
if parlamentar in presentes:
yield (parlamentar, True, p_afastado)
else: else:
yield (m.parlamentar, False) yield (parlamentar, False, p_afastado)
class TipoExpedienteCrud(CrudAux): class TipoExpedienteCrud(CrudAux):
@ -606,6 +610,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
layout_key = 'ExpedienteMateriaDetail' layout_key = 'ExpedienteMateriaDetail'
# Orador das Explicações Pessoais
class OradorCrud(MasterDetailCrud): class OradorCrud(MasterDetailCrud):
model = Orador model = Orador
parent_field = 'sessao_plenaria' parent_field = 'sessao_plenaria'
@ -624,32 +629,6 @@ class OradorCrud(MasterDetailCrud):
context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'}) context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context return context
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().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
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
form_class = OradorForm form_class = OradorForm
@ -671,16 +650,7 @@ class OradorExpedienteCrud(OradorCrud):
kwargs={'pk': self.kwargs['pk']}) kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView): class DetailView(MasterDetailCrud.DetailView):
form_class = OradorForm
def get_initial(self):
initial = super().get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero':self.object.numero_ordem})
return initial
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -692,7 +662,15 @@ class OradorExpedienteCrud(OradorCrud):
return context return context
class DetailView(MasterDetailCrud.DetailView): class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorForm
def get_initial(self):
initial = super().get_initial()
initial.update({'id_sessao': self.object.sessao_plenaria.id})
initial.update({'numero': self.object.numero_ordem})
return initial
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
@ -748,6 +726,15 @@ class OradorExpedienteCrud(OradorCrud):
return {'id_sessao': self.object.sessao_plenaria.id, return {'id_sessao': self.object.sessao_plenaria.id,
'numero': self.object.numero_ordem} 'numero': self.object.numero_ordem}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
pk = context['root_pk']
sessao = SessaoPlenaria.objects.get(id=pk)
tipo_sessao = sessao.tipo
if tipo_sessao.nome == "Solene":
context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
class ListView(MasterDetailCrud.ListView): class ListView(MasterDetailCrud.ListView):
@ -771,13 +758,12 @@ class OradorExpedienteCrud(OradorCrud):
context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'}) context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context return context
class DeleteView(MasterDetailCrud.DeleteView):
class UpdateView(MasterDetailCrud.UpdateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
pk = context['root_pk'] sessao_pk = context['root_pk']
sessao = SessaoPlenaria.objects.get(id=pk) sessao = SessaoPlenaria.objects.get(id=sessao_pk)
tipo_sessao = sessao.tipo tipo_sessao = sessao.tipo
if tipo_sessao.nome == "Solene": if tipo_sessao.nome == "Solene":
context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'}) context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
@ -944,6 +930,14 @@ class SessaoCrud(Crud):
namespace = self.model._meta.app_config.name namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'sessaoplenaria_list')) return reverse('%s:%s' % (namespace, 'sessaoplenaria_list'))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
sessao = context['object']
tipo_sessao = sessao.tipo
if tipo_sessao.nome == "Solene":
context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
return context
class DetailView(Crud.DetailView): class DetailView(Crud.DetailView):
@property @property
@ -961,7 +955,6 @@ class SessaoCrud(Crud):
tipo_sessao = sessao.tipo tipo_sessao = sessao.tipo
if tipo_sessao.nome == "Solene": if tipo_sessao.nome == "Solene":
context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'}) context.update({'subnav_template_name': 'sessao/subnav-solene.yaml'})
# self.layout_key = 'SessaoSolene'
return context return context
@ -1298,7 +1291,9 @@ class MesaView(FormMixin, DetailView):
org_parlamentares_vagos.sort( org_parlamentares_vagos.sort(
key=lambda x: remover_acentos(x.nome_parlamentar)) key=lambda x: remover_acentos(x.nome_parlamentar))
org_parlamentares_vagos = [ org_parlamentares_vagos = [
p for p in org_parlamentares_vagos if p.ativo] p for p in org_parlamentares_vagos if (p.ativo and
not verifica_afastamento_parlamentar(p, sessao.data_inicio, sessao.data_fim)
)]
# Se todos os cargos estiverem ocupados, a listagem de parlamentares # Se todos os cargos estiverem ocupados, a listagem de parlamentares
# deve ser renderizada vazia # deve ser renderizada vazia
if not cargos_vagos: if not cargos_vagos:
@ -1534,7 +1529,7 @@ def get_turno(turno):
return '' return ''
def get_identificação_basica(sessao_plenaria): def get_identificacao_basica(sessao_plenaria):
# ===================================================================== # =====================================================================
# Identificação Básica # Identificação Básica
data_inicio = sessao_plenaria.data_inicio data_inicio = sessao_plenaria.data_inicio
@ -1829,7 +1824,7 @@ def get_oradores_ordemdia(sessao_plenaria):
return context return context
def get_oradores_explicações_pessoais(sessao_plenaria): def get_oradores_explicacoes_pessoais(sessao_plenaria):
oradores_explicacoes = [] oradores_explicacoes = []
for orador in Orador.objects.filter( for orador in Orador.objects.filter(
sessao_plenaria_id=sessao_plenaria.id).order_by('numero_ordem'): sessao_plenaria_id=sessao_plenaria.id).order_by('numero_ordem'):
@ -1851,7 +1846,7 @@ def get_oradores_explicações_pessoais(sessao_plenaria):
return context return context
def get_ocorrencias_da_sessão(sessao_plenaria): def get_ocorrencias_da_sessao(sessao_plenaria):
ocorrencias_sessao = OcorrenciaSessao.objects.filter( ocorrencias_sessao = OcorrenciaSessao.objects.filter(
sessao_plenaria_id=sessao_plenaria.id) sessao_plenaria_id=sessao_plenaria.id)
context = {'ocorrencias_da_sessao': ocorrencias_sessao} context = {'ocorrencias_da_sessao': ocorrencias_sessao}
@ -1892,7 +1887,7 @@ class ResumoView(DetailView):
# ===================================================================== # =====================================================================
# Identificação Básica # Identificação Básica
context.update(get_identificação_basica(self.object)) context.update(get_identificacao_basica(self.object))
# ===================================================================== # =====================================================================
# Conteúdo Multimídia # Conteúdo Multimídia
context.update(get_conteudo_multimidia(self.object)) context.update(get_conteudo_multimidia(self.object))
@ -1947,10 +1942,10 @@ class ResumoView(DetailView):
context.update(get_oradores_ordemdia(self.object)) context.update(get_oradores_ordemdia(self.object))
# ===================================================================== # =====================================================================
# Oradores nas Explicações Pessoais # Oradores nas Explicações Pessoais
context.update(get_oradores_explicações_pessoais(self.object)) context.update(get_oradores_explicacoes_pessoais(self.object))
# ===================================================================== # =====================================================================
# Ocorrẽncias da Sessão # Ocorrẽncias da Sessão
context.update(get_ocorrencias_da_sessão(self.object)) context.update(get_ocorrencias_da_sessao(self.object))
# ===================================================================== # =====================================================================
# Indica a ordem com a qual o template será renderizado # Indica a ordem com a qual o template será renderizado
dict_ord_template = { dict_ord_template = {
@ -2087,16 +2082,13 @@ class ExpedienteView(FormMixin, DetailView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
context = self.get_context_data(object=self.object) context = self.get_context_data(object=self.object)
tipos = TipoExpediente.objects.all().order_by('nome') tipos = TipoExpediente.objects.all().order_by('ordenacao', 'nome')
expedientes_sessao = ExpedienteSessao.objects.filter( expedientes_sessao = ExpedienteSessao.objects.filter(
sessao_plenaria_id=self.object.id).order_by('tipo__nome') sessao_plenaria_id=self.object.id).order_by('tipo__ordenacao', 'tipo__nome')
expedientes_salvos = [] expedientes_salvos = [e.tipo.id for e in expedientes_sessao]
for e in expedientes_sessao:
expedientes_salvos.append(e.tipo)
tipos_null = list(set(tipos) - set(expedientes_salvos)) tipos_null = TipoExpediente.objects.all().exclude(id__in=expedientes_salvos).order_by('ordenacao', 'nome')
tipos_null.sort(key=lambda x: x.nome)
expedientes = [] expedientes = []
for e, t in zip(expedientes_sessao, tipos): for e, t in zip(expedientes_sessao, tipos):
@ -3303,8 +3295,7 @@ class PautaSessaoDetailView(DetailView):
expedientes = [] expedientes = []
for e in expediente: for e in expediente:
tipo = TipoExpediente.objects.get( tipo = e.tipo
id=e.tipo_id)
conteudo = sub( conteudo = sub(
'&nbsp;', ' ', strip_tags(e.conteudo.replace('<br/>', '\n'))) '&nbsp;', ' ', strip_tags(e.conteudo.replace('<br/>', '\n')))

8
sapl/static/sapl/frontend/css/chunk-45646c50.b20a1ea4.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/chunk-45646c50.b20a1ea4.css.gz

Binary file not shown.

8
sapl/static/sapl/frontend/css/chunk-45646c50.d0eb5406.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/chunk-45646c50.d0eb5406.css.gz

Binary file not shown.

104
sapl/static/sapl/frontend/css/chunk-vendors.28796d79.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/chunk-vendors.28796d79.css.gz

Binary file not shown.

101
sapl/static/sapl/frontend/css/chunk-vendors.2ce8185b.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/chunk-vendors.2ce8185b.css.gz

Binary file not shown.

1
sapl/static/sapl/frontend/css/global.cb631d5e.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/global.cb631d5e.css.gz

Binary file not shown.

1
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.d160bbe2.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf → sapl/static/sapl/frontend/fonts/fa-brands-400.3165b14b.eot

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.3165b14b.eot.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.457cb96b.woff

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.4b115e11.woff2

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.b90365bc.woff

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot → sapl/static/sapl/frontend/fonts/fa-brands-400.f2e186cf.ttf

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.f2e186cf.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.f861a57c.woff2

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf → sapl/static/sapl/frontend/fonts/fa-regular-400.2cd8d991.ttf

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.2cd8d991.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.65779ebc.woff2

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.5dd3976c.woff → sapl/static/sapl/frontend/fonts/fa-regular-400.7ab2cb05.woff

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot → sapl/static/sapl/frontend/fonts/fa-regular-400.a03df7ab.eot

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.a03df7ab.eot.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.bd52a727.woff2

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.2cd2be17.woff2

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.46280631.woff2

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot → sapl/static/sapl/frontend/fonts/fa-solid-900.5ee32f5c.ttf

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.5ee32f5c.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.61969d43.woff

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.657a4694.woff

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf → sapl/static/sapl/frontend/fonts/fa-solid-900.a547e21e.eot

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.a547e21e.eot.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg.gz

Binary file not shown.

1407
sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg → sapl/static/sapl/frontend/img/fa-brands-400.f249e44d.svg

File diff suppressed because it is too large

Before

Width:  |  Height:  |  Size: 644 KiB

After

Width:  |  Height:  |  Size: 676 KiB

BIN
sapl/static/sapl/frontend/img/fa-brands-400.f249e44d.svg.gz

Binary file not shown.

22
sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg → sapl/static/sapl/frontend/img/fa-regular-400.2fad4ee0.svg

@ -1,8 +1,12 @@
<?xml version="1.0" standalone="no"?> <?xml version="1.0" standalone="no"?>
<!--
Font Awesome Free 5.10.1 by @fontawesome - https://fontawesome.com
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
-->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata> <metadata>
Created by FontForge 20190112 at Tue Feb 12 10:24:59 2019 Created by FontForge 20190112 at Fri Aug 2 14:42:17 2019
By Robert Madole By Robert Madole
Copyright (c) Font Awesome Copyright (c) Font Awesome
</metadata> </metadata>
@ -54,7 +58,7 @@ d="M336 448c26.5098 0 48 -21.4902 48 -48v-464l-192 112l-192 -112v464c0 26.5098 2
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM458 48c3.31152 0 6 2.68848 6 6v276c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-276 d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM458 48c3.31152 0 6 2.68848 6 6v276c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-276
c0 -3.31152 2.68848 -6 6 -6h404zM128 296c22.0908 0 40 -17.9092 40 -40s-17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40zM96 96v48l39.5137 39.5146c4.6875 4.68652 12.2852 4.68652 16.9717 0l39.5146 -39.5146l119.514 119.515 c0 -3.31152 2.68848 -6 6 -6h404zM128 296c22.0908 0 40 -17.9092 40 -40s-17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40zM96 96v48l39.5137 39.5146c4.6875 4.68652 12.2852 4.68652 16.9717 0l39.5146 -39.5146l119.514 119.515
c4.6875 4.68652 12.2852 4.68652 16.9717 0l87.5146 -87.5146v-80h-320z" /> c4.6875 4.68652 12.2852 4.68652 16.9717 0l87.5146 -87.5146v-80h-320z" />
<glyph glyph-name="edit" unicode="&#xf044;" horiz-adv-x="575" <glyph glyph-name="edit" unicode="&#xf044;" horiz-adv-x="576"
d="M402.3 103.1l32 32c5 5 13.7002 1.5 13.7002 -5.69922v-145.4c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h273.5c7.09961 0 10.7002 -8.59961 5.7002 -13.7002l-32 -32c-1.5 -1.5 -3.5 -2.2998 -5.7002 -2.2998h-241.5v-352h352 d="M402.3 103.1l32 32c5 5 13.7002 1.5 13.7002 -5.69922v-145.4c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h273.5c7.09961 0 10.7002 -8.59961 5.7002 -13.7002l-32 -32c-1.5 -1.5 -3.5 -2.2998 -5.7002 -2.2998h-241.5v-352h352
v113.5c0 2.09961 0.799805 4.09961 2.2998 5.59961zM558.9 304.9l-262.601 -262.601l-90.3994 -10c-26.2002 -2.89941 -48.5 19.2002 -45.6006 45.6006l10 90.3994l262.601 262.601c22.8994 22.8994 59.8994 22.8994 82.6992 0l43.2002 -43.2002 v113.5c0 2.09961 0.799805 4.09961 2.2998 5.59961zM558.9 304.9l-262.601 -262.601l-90.3994 -10c-26.2002 -2.89941 -48.5 19.2002 -45.6006 45.6006l10 90.3994l262.601 262.601c22.8994 22.8994 59.8994 22.8994 82.6992 0l43.2002 -43.2002
c22.9004 -22.9004 22.9004 -60 0.100586 -82.7998zM460.1 274l-58.0996 58.0996l-185.8 -185.899l-7.2998 -65.2998l65.2998 7.2998zM524.9 353.7l-43.2002 43.2002c-4.10059 4.09961 -10.7998 4.09961 -14.7998 0l-30.9004 -30.9004l58.0996 -58.0996l30.9004 30.8994 c22.9004 -22.9004 22.9004 -60 0.100586 -82.7998zM460.1 274l-58.0996 58.0996l-185.8 -185.899l-7.2998 -65.2998l65.2998 7.2998zM524.9 353.7l-43.2002 43.2002c-4.10059 4.09961 -10.7998 4.09961 -14.7998 0l-30.9004 -30.9004l58.0996 -58.0996l30.9004 30.8994
@ -97,7 +101,7 @@ l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.20
<glyph glyph-name="folder" unicode="&#xf07b;" <glyph glyph-name="folder" unicode="&#xf07b;"
d="M464 320c26.5098 0 48 -21.4902 48 -48v-224c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h146.74c8.49023 0 16.6299 -3.37012 22.6299 -9.37012l54.6299 -54.6299h192zM464 48v224h-198.62 d="M464 320c26.5098 0 48 -21.4902 48 -48v-224c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h146.74c8.49023 0 16.6299 -3.37012 22.6299 -9.37012l54.6299 -54.6299h192zM464 48v224h-198.62
c-8.49023 0 -16.6299 3.37012 -22.6299 9.37012l-54.6299 54.6299h-140.12v-288h416z" /> c-8.49023 0 -16.6299 3.37012 -22.6299 9.37012l-54.6299 54.6299h-140.12v-288h416z" />
<glyph glyph-name="folder-open" unicode="&#xf07c;" horiz-adv-x="575" <glyph glyph-name="folder-open" unicode="&#xf07c;" horiz-adv-x="576"
d="M527.9 224c37.6992 0 60.6992 -41.5 40.6992 -73.4004l-79.8994 -128c-8.7998 -14.0996 -24.2002 -22.5996 -40.7002 -22.5996h-400c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h160l64 -64h160c26.5 0 48 -21.5 48 -48v-48h47.9004zM48 330v-233.4l62.9004 104.2 d="M527.9 224c37.6992 0 60.6992 -41.5 40.6992 -73.4004l-79.8994 -128c-8.7998 -14.0996 -24.2002 -22.5996 -40.7002 -22.5996h-400c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h160l64 -64h160c26.5 0 48 -21.5 48 -48v-48h47.9004zM48 330v-233.4l62.9004 104.2
c8.69922 14.4004 24.2998 23.2002 41.0996 23.2002h280v42c0 3.2998 -2.7002 6 -6 6h-173.9l-64 64h-134.1c-3.2998 0 -6 -2.7002 -6 -6zM448 48l80 128h-378.8l-77.2002 -128h376z" /> c8.69922 14.4004 24.2998 23.2002 41.0996 23.2002h280v42c0 3.2998 -2.7002 6 -6 6h-173.9l-64 64h-134.1c-3.2998 0 -6 -2.7002 -6 -6zM448 48l80 128h-378.8l-77.2002 -128h376z" />
<glyph glyph-name="chart-bar" unicode="&#xf080;" <glyph glyph-name="chart-bar" unicode="&#xf080;"
@ -113,7 +117,7 @@ c0.400391 0.399414 22.4004 24.1992 37.7002 54.8994c-27.5 27.2002 -44 61.2002 -44
l19.7998 -4.5c16 -3.69922 32.5 -5.59961 49 -5.59961c86.7002 0 160 51.2998 160 112s-73.2998 112 -160 112s-160 -51.2998 -160 -112c0 -28.7002 16.2002 -50.5996 29.7002 -64l24.7998 -24.5l-15.5 -31.0996c-2.59961 -5.10059 -5.2998 -10.1006 -8 -14.8008 l19.7998 -4.5c16 -3.69922 32.5 -5.59961 49 -5.59961c86.7002 0 160 51.2998 160 112s-73.2998 112 -160 112s-160 -51.2998 -160 -112c0 -28.7002 16.2002 -50.5996 29.7002 -64l24.7998 -24.5l-15.5 -31.0996c-2.59961 -5.10059 -5.2998 -10.1006 -8 -14.8008
c14.5996 5.10059 29 12.3008 43.0996 21.4004zM498.3 96c13.5 13.4004 29.7002 35.2998 29.7002 64c0 49.2002 -48.2998 91.5 -112.7 106c0.299805 -3.2998 0.700195 -6.59961 0.700195 -10c0 -80.9004 -78 -147.5 -179.3 -158.3 c14.5996 5.10059 29 12.3008 43.0996 21.4004zM498.3 96c13.5 13.4004 29.7002 35.2998 29.7002 64c0 49.2002 -48.2998 91.5 -112.7 106c0.299805 -3.2998 0.700195 -6.59961 0.700195 -10c0 -80.9004 -78 -147.5 -179.3 -158.3
c29.0996 -29.6006 77.2998 -49.7002 131.3 -49.7002c16.5 0 33 1.90039 49 5.59961l19.9004 4.60059l17.0996 -11.1006c14.0996 -9.09961 28.5 -16.2998 43.0996 -21.3994c-2.69922 4.7002 -5.39941 9.7002 -8 14.7998l-15.5 31.0996z" /> c29.0996 -29.6006 77.2998 -49.7002 131.3 -49.7002c16.5 0 33 1.90039 49 5.59961l19.9004 4.60059l17.0996 -11.1006c14.0996 -9.09961 28.5 -16.2998 43.0996 -21.3994c-2.69922 4.7002 -5.39941 9.7002 -8 14.7998l-15.5 31.0996z" />
<glyph glyph-name="star-half" unicode="&#xf089;" horiz-adv-x="308" <glyph glyph-name="star-half" unicode="&#xf089;" horiz-adv-x="576"
d="M288 62.7002v-54.2998l-130.7 -68.6006c-23.3994 -12.2998 -50.8994 7.60059 -46.3994 33.7002l25 145.5l-105.7 103c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2002l65.2998 132.4c5.90039 11.8994 17.2998 17.7998 28.7002 17.7998v-68.0996l-62.2002 -126 d="M288 62.7002v-54.2998l-130.7 -68.6006c-23.3994 -12.2998 -50.8994 7.60059 -46.3994 33.7002l25 145.5l-105.7 103c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2002l65.2998 132.4c5.90039 11.8994 17.2998 17.7998 28.7002 17.7998v-68.0996l-62.2002 -126
l-139 -20.2002l100.601 -98l-23.7002 -138.4z" /> l-139 -20.2002l100.601 -98l-23.7002 -138.4z" />
<glyph glyph-name="lemon" unicode="&#xf094;" <glyph glyph-name="lemon" unicode="&#xf094;"
@ -137,7 +141,7 @@ c8.58398 0 16.373 -3.04785 22.1201 -8h2.67871c6.96387 0 14.8623 6.19336 30.1816
v-0.0839844c0 -6.21777 -0.974609 -16.2148 -2.17578 -22.3154h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994c0 26.4004 -20.625 35.2002 -44 35.2002 v-0.0839844c0 -6.21777 -0.974609 -16.2148 -2.17578 -22.3154h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994c0 26.4004 -20.625 35.2002 -44 35.2002
c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988 c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" /> c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
<glyph glyph-name="hand-point-left" unicode="&#xf0a5;" horiz-adv-x="511" <glyph glyph-name="hand-point-left" unicode="&#xf0a5;"
d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529 d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529
l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64 l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-2.96094 5.8125 -6.51367 15.6973 -7.92969 22.0645h-35.6465 c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-2.96094 5.8125 -6.51367 15.6973 -7.92969 22.0645h-35.6465
@ -261,14 +265,14 @@ h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416z" />
d="M288 200v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v28c0 6.59961 5.40039 12 12 12h168c6.59961 0 12 -5.40039 12 -12zM276 128c6.59961 0 12 -5.40039 12 -12v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12 d="M288 200v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v28c0 6.59961 5.40039 12 12 12h168c6.59961 0 12 -5.40039 12 -12zM276 128c6.59961 0 12 -5.40039 12 -12v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12
v28c0 6.59961 5.40039 12 12 12h168zM384 316.1v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996l83.9004 -83.9004c9 -8.90039 14.0996 -21.2002 14.0996 -33.9004z v28c0 6.59961 5.40039 12 12 12h168zM384 316.1v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996l83.9004 -83.9004c9 -8.90039 14.0996 -21.2002 14.0996 -33.9004z
M256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288z" /> M256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288z" />
<glyph glyph-name="thumbs-up" unicode="&#xf164;" horiz-adv-x="480" <glyph glyph-name="thumbs-up" unicode="&#xf164;"
d="M466.27 161.31c4.6748 -22.6465 0.864258 -44.5371 -8.98926 -62.9893c2.95898 -23.8682 -4.02148 -48.5654 -17.3398 -66.9902c-0.954102 -55.9072 -35.8232 -95.3301 -112.94 -95.3301c-7 0 -15 0.00976562 -22.2197 0.00976562 d="M466.27 161.31c4.6748 -22.6465 0.864258 -44.5371 -8.98926 -62.9893c2.95898 -23.8682 -4.02148 -48.5654 -17.3398 -66.9902c-0.954102 -55.9072 -35.8232 -95.3301 -112.94 -95.3301c-7 0 -15 0.00976562 -22.2197 0.00976562
c-102.742 0 -133.293 38.9395 -177.803 39.9404c-3.56934 -13.7764 -16.085 -23.9502 -30.9775 -23.9502h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h98.7598c19.1455 16.9531 46.0137 60.6533 68.7598 83.4004 c-102.742 0 -133.293 38.9395 -177.803 39.9404c-3.56934 -13.7764 -16.085 -23.9502 -30.9775 -23.9502h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h98.7598c19.1455 16.9531 46.0137 60.6533 68.7598 83.4004
c13.667 13.667 10.1533 108.6 71.7607 108.6c57.5801 0 95.2695 -31.9355 95.2695 -104.73c0 -18.4092 -3.92969 -33.7295 -8.84961 -46.5391h36.4795c48.6025 0 85.8203 -41.5654 85.8203 -85.5801c0 -19.1504 -4.95996 -34.9902 -13.7305 -49.8408zM404.52 107.48 c13.667 13.667 10.1533 108.6 71.7607 108.6c57.5801 0 95.2695 -31.9355 95.2695 -104.73c0 -18.4092 -3.92969 -33.7295 -8.84961 -46.5391h36.4795c48.6025 0 85.8203 -41.5654 85.8203 -85.5801c0 -19.1504 -4.95996 -34.9902 -13.7305 -49.8408zM404.52 107.48
c21.5811 20.3838 18.6992 51.0645 5.21094 65.6191c9.44922 0 22.3594 18.9102 22.2695 37.8105c-0.0898438 18.9102 -16.71 37.8203 -37.8203 37.8203h-103.989c0 37.8193 28.3594 55.3691 28.3594 94.5391c0 23.75 0 56.7305 -47.2695 56.7305 c21.5811 20.3838 18.6992 51.0645 5.21094 65.6191c9.44922 0 22.3594 18.9102 22.2695 37.8105c-0.0898438 18.9102 -16.71 37.8203 -37.8203 37.8203h-103.989c0 37.8193 28.3594 55.3691 28.3594 94.5391c0 23.75 0 56.7305 -47.2695 56.7305
c-18.9102 -18.9102 -9.45996 -66.1797 -37.8203 -94.54c-26.5596 -26.5703 -66.1797 -97.46 -94.54 -97.46h-10.9199v-186.17c53.6113 0 100.001 -37.8203 171.64 -37.8203h37.8203c35.5117 0 60.8203 17.1201 53.1201 65.9004 c-18.9102 -18.9102 -9.45996 -66.1797 -37.8203 -94.54c-26.5596 -26.5703 -66.1797 -97.46 -94.54 -97.46h-10.9199v-186.17c53.6113 0 100.001 -37.8203 171.64 -37.8203h37.8203c35.5117 0 60.8203 17.1201 53.1201 65.9004
c15.2002 8.16016 26.5 36.4395 13.9395 57.5703zM88 16c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" /> c15.2002 8.16016 26.5 36.4395 13.9395 57.5703zM88 16c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
<glyph glyph-name="thumbs-down" unicode="&#xf165;" horiz-adv-x="480" <glyph glyph-name="thumbs-down" unicode="&#xf165;"
d="M466.27 222.69c8.77051 -14.8506 13.7305 -30.6904 13.7305 -49.8408c0 -44.0146 -37.2178 -85.5801 -85.8203 -85.5801h-36.4795c4.91992 -12.8096 8.84961 -28.1299 8.84961 -46.5391c0 -72.7949 -37.6895 -104.73 -95.2695 -104.73 d="M466.27 222.69c8.77051 -14.8506 13.7305 -30.6904 13.7305 -49.8408c0 -44.0146 -37.2178 -85.5801 -85.8203 -85.5801h-36.4795c4.91992 -12.8096 8.84961 -28.1299 8.84961 -46.5391c0 -72.7949 -37.6895 -104.73 -95.2695 -104.73
c-61.6074 0 -58.0938 94.9326 -71.7607 108.6c-22.7461 22.7471 -49.6133 66.4473 -68.7598 83.4004h-7.05176c-5.5332 -9.56152 -15.8662 -16 -27.708 -16h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h64c8.11328 0 15.5146 -3.02539 21.1553 -8 c-61.6074 0 -58.0938 94.9326 -71.7607 108.6c-22.7461 22.7471 -49.6133 66.4473 -68.7598 83.4004h-7.05176c-5.5332 -9.56152 -15.8662 -16 -27.708 -16h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h64c8.11328 0 15.5146 -3.02539 21.1553 -8
h10.8447c40.9971 0 73.1953 39.9902 176.78 39.9902c7.21973 0 15.2197 0.00976562 22.2197 0.00976562c77.1172 0 111.986 -39.4229 112.94 -95.3301c13.3184 -18.4248 20.2979 -43.1221 17.3398 -66.9902c9.85352 -18.4521 13.6641 -40.3428 8.98926 -62.9893zM64 152 h10.8447c40.9971 0 73.1953 39.9902 176.78 39.9902c7.21973 0 15.2197 0.00976562 22.2197 0.00976562c77.1172 0 111.986 -39.4229 112.94 -95.3301c13.3184 -18.4248 20.2979 -43.1221 17.3398 -66.9902c9.85352 -18.4521 13.6641 -40.3428 8.98926 -62.9893zM64 152
@ -282,7 +286,7 @@ c-11.0996 7.5 -17.7998 20 -17.7998 33.5s6.59961 26 17.7998 33.5996l59.7998 40.5l
l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9.5 -9.59961 13.7002 -23.2002 11.0996 -36.4004l-13.6992 -71zM381.3 140.5l76.7998 52.0996l-76.7998 52l17.6006 91.1006l-91 -17.6006l-51.9004 76.9004l-51.7998 -76.7998 l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9.5 -9.59961 13.7002 -23.2002 11.0996 -36.4004l-13.6992 -71zM381.3 140.5l76.7998 52.0996l-76.7998 52l17.6006 91.1006l-91 -17.6006l-51.9004 76.9004l-51.7998 -76.7998
l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136 l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136
c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" /> c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" />
<glyph glyph-name="moon" unicode="&#xf186;" horiz-adv-x="511" <glyph glyph-name="moon" unicode="&#xf186;"
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c13.0068 -0.00195312 33.9443 -1.91797 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836 d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c13.0068 -0.00195312 33.9443 -1.91797 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208 c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208
c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" /> c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" />
@ -730,7 +734,7 @@ c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM328 296 c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM328 296
c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17 c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" /> c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
<glyph glyph-name="kiss-wink-heart" unicode="&#xf598;" horiz-adv-x="503" <glyph glyph-name="kiss-wink-heart" unicode="&#xf598;" horiz-adv-x="504"
d="M304 139.5c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002 d="M304 139.5c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002 c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002
c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM374.5 223c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-2.5 -2.2998 -7.90039 -4.7002 -13.7002 -1.59961c-4.39941 2.39941 -6.89941 7.39941 -6.09961 12.3994 c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM374.5 223c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-2.5 -2.2998 -7.90039 -4.7002 -13.7002 -1.59961c-4.39941 2.39941 -6.89941 7.39941 -6.09961 12.3994

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

BIN
sapl/static/sapl/frontend/img/fa-regular-400.2fad4ee0.svg.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg.gz

Binary file not shown.

741
sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg → sapl/static/sapl/frontend/img/fa-solid-900.fdc155d5.svg

File diff suppressed because it is too large

Before

Width:  |  Height:  |  Size: 797 KiB

After

Width:  |  Height:  |  Size: 820 KiB

BIN
sapl/static/sapl/frontend/img/fa-solid-900.fdc155d5.svg.gz

Binary file not shown.

0
sapl/static/sapl/frontend/js/chunk-2d0c4a82.226eafb5.js → sapl/static/sapl/frontend/js/chunk-2d0c4a82.43dad737.js

0
sapl/static/sapl/frontend/js/chunk-2d0c4a82.226eafb5.js.gz → sapl/static/sapl/frontend/js/chunk-2d0c4a82.43dad737.js.gz

0
sapl/static/sapl/frontend/js/chunk-2d0e8be2.59add782.js → sapl/static/sapl/frontend/js/chunk-2d0e8be2.2b08ebc9.js

0
sapl/static/sapl/frontend/js/chunk-2d0e8be2.59add782.js.gz → sapl/static/sapl/frontend/js/chunk-2d0e8be2.2b08ebc9.js.gz

0
sapl/static/sapl/frontend/js/chunk-3e2c11a1.f6016ea0.js → sapl/static/sapl/frontend/js/chunk-3e2c11a1.2ff29933.js

0
sapl/static/sapl/frontend/js/chunk-3e2c11a1.f6016ea0.js.gz → sapl/static/sapl/frontend/js/chunk-3e2c11a1.2ff29933.js.gz

0
sapl/static/sapl/frontend/js/chunk-45646c50.c4980cfa.js → sapl/static/sapl/frontend/js/chunk-45646c50.4e66dd13.js

0
sapl/static/sapl/frontend/js/chunk-45646c50.c4980cfa.js.gz → sapl/static/sapl/frontend/js/chunk-45646c50.4e66dd13.js.gz

0
sapl/static/sapl/frontend/js/chunk-4cf2dae1.f538501c.js → sapl/static/sapl/frontend/js/chunk-4cf2dae1.13047e21.js

0
sapl/static/sapl/frontend/js/chunk-4cf2dae1.f538501c.js.gz → sapl/static/sapl/frontend/js/chunk-4cf2dae1.13047e21.js.gz

314
sapl/static/sapl/frontend/js/chunk-vendors.0af160fc.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/chunk-vendors.0af160fc.js.gz

Binary file not shown.

304
sapl/static/sapl/frontend/js/chunk-vendors.eaff380d.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/chunk-vendors.eaff380d.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/compilacao.97a57151.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/compilacao.97a57151.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/compilacao.bb73875d.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/compilacao.bb73875d.js.gz

Binary file not shown.

2
sapl/static/sapl/frontend/js/global.6df749cd.js → sapl/static/sapl/frontend/js/global.40c7bff1.js

File diff suppressed because one or more lines are too long

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save