Browse Source

feat: nova funcionalidade para leitura em bloco de materias do expediente (#3618)

* feat: nova funcionalidade para leitura em bloco de materias do expediente

* fix: Ajustes na Leitura em bloco, inclusao da funcionalidade para Ordem do dia

Co-authored-by: joao <joao@mezzoplanejamento.com.br>
pull/3628/merge
joaohortsenado 2 years ago
committed by Edward Oliveira
parent
commit
d39b65a828
  1. 7
      sapl/sessao/urls.py
  2. 142
      sapl/sessao/views.py
  3. 114
      sapl/templates/sessao/leitura/leitura_bloco.html
  4. 6
      sapl/templates/sessao/subnav.yaml

7
sapl/sessao/urls.py

@ -31,6 +31,7 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente,
sessao_legislativa_legislatura_ajax,
VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente,
VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView,
LeituraEmBlocoExpediente, LeituraEmBlocoOrdemDia,
recuperar_nome_tipo_sessao,
ExpedienteLeituraView,
OrdemDiaLeituraView,
@ -158,6 +159,12 @@ urlpatterns = [
url(r'^sessao/(?P<pk>\d+)/votacao_bloco_expediente$',
VotacaoEmBlocoExpediente.as_view(),
name='votacao_bloco_expediente'),
url(r'^sessao/(?P<pk>\d+)/leitura_bloco_expediente$',
LeituraEmBlocoExpediente.as_view(),
name='leitura_bloco_expediente'),
url(r'^sessao/(?P<pk>\d+)/leitura_bloco_ordem_dia$',
LeituraEmBlocoOrdemDia.as_view(),
name='leitura_bloco_ordem_dia'),
url(r'^sessao/(?P<pk>\d+)/resumo$',
ResumoView.as_view(), name='resumo'),
url(r'^sessao/(?P<pk>\d+)/resumo_ata$',

142
sapl/sessao/views.py

@ -62,7 +62,6 @@ from .models import (Bancada, CargoBancada, CargoMesa,
RetiradaPauta, TipoJustificativa, JustificativaAusencia, OradorOrdemDia,
ORDENACAO_RESUMO, RegistroLeitura)
TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
TipoJustificativaCrud = CrudAux.build(TipoJustificativa, 'tipo_justificativa')
CargoBancadaCrud = CrudAux.build(CargoBancada, '')
@ -167,7 +166,8 @@ def verifica_sessao_iniciada(request, spk, is_leitura=False):
username = request.user.username
aux_text = 'leitura' if is_leitura else 'votação'
logger.info('user=' + username + '. Não é possível abrir matérias para {}. '
'Esta SessaoPlenaria (id={}) não foi iniciada ou está finalizada.'.format(aux_text, spk))
'Esta SessaoPlenaria (id={}) não foi iniciada ou está finalizada.'.format(
aux_text, spk))
msg = _('Não é possível abrir matérias para {}. '
'Esta Sessão Plenária não foi iniciada ou está finalizada.'
' Vá em "Abertura"->"Dados Básicos" e altere os valores dos campos necessários.'.format(aux_text))
@ -274,8 +274,8 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
exist_leitura = obj.registroleitura_set.filter(
materia=obj.materia).exists()
if (obj.tipo_votacao != 4 and not exist_resultado and not exist_retirada) or\
(obj.tipo_votacao == 4 and not exist_leitura):
if (obj.tipo_votacao != LEITURA and not exist_resultado and not exist_retirada) or \
(obj.tipo_votacao == LEITURA and not exist_leitura):
if obj.votacao_aberta:
url = ''
if is_expediente:
@ -1815,7 +1815,8 @@ def insere_parlamentar_composicao(request):
cargo_id=composicao.cargo.id).exists()
if parlamentar_ja_inserido:
logger.debug("user=" + username + ". Parlamentar (id={}) já inserido na sessao_plenaria(id={}) e cargo(ìd={})."
logger.debug(
"user=" + username + ". Parlamentar (id={}) já inserido na sessao_plenaria(id={}) e cargo(ìd={})."
.format(request.POST['parlamentar'], composicao.sessao_plenaria.id, composicao.cargo.id))
return JsonResponse({'msg': ('Parlamentar já inserido!', 0)})
@ -1968,7 +1969,6 @@ def get_mesa_diretora(sessao_plenaria):
def get_presenca_sessao(sessao_plenaria):
parlamentares_sessao = [p.parlamentar for p in SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=sessao_plenaria.id
).order_by('parlamentar__nome_parlamentar').distinct()]
@ -2029,7 +2029,8 @@ def get_materias_expediente(sessao_plenaria):
for m in ExpedienteMateria.objects.select_related("materia").filter(sessao_plenaria_id=sessao_plenaria.id):
tramitacao = ''
data_sessao = sessao_plenaria.data_fim if sessao_plenaria.data_fim else sessao_plenaria.data_inicio
for aux_tramitacao in Tramitacao.objects.filter(materia=m.materia, data_tramitacao__lte=data_sessao).order_by('-data_tramitacao', '-id'):
for aux_tramitacao in Tramitacao.objects.filter(materia=m.materia, data_tramitacao__lte=data_sessao).order_by(
'-data_tramitacao', '-id'):
if aux_tramitacao.turno:
tramitacao = aux_tramitacao
break
@ -2175,7 +2176,8 @@ def get_materias_ordem_do_dia(sessao_plenaria):
for o in OrdemDia.objects.filter(sessao_plenaria_id=sessao_plenaria.id):
tramitacao = ''
data_sessao = sessao_plenaria.data_fim if sessao_plenaria.data_fim else sessao_plenaria.data_inicio
for aux_tramitacao in Tramitacao.objects.filter(materia=o.materia, data_tramitacao__lte=data_sessao).order_by('-data_tramitacao', '-id'):
for aux_tramitacao in Tramitacao.objects.filter(materia=o.materia, data_tramitacao__lte=data_sessao).order_by(
'-data_tramitacao', '-id'):
if aux_tramitacao.turno:
tramitacao = aux_tramitacao
break
@ -2510,7 +2512,6 @@ class ExpedienteView(FormMixin, DetailView):
list_conteudo = request.POST.getlist('conteudo')
for tipo, conteudo in zip(list_tipo, list_conteudo):
ExpedienteSessao.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_id=tipo).delete()
@ -2523,7 +2524,8 @@ class ExpedienteView(FormMixin, DetailView):
msg = _('Registro salvo com sucesso')
messages.add_message(self.request, messages.SUCCESS, msg)
self.logger.info('user=' + username + '. ExpedienteSessao(sessao_plenaria_id={} e tipo_id={}) salvo com sucesso.'
self.logger.info(
'user=' + username + '. ExpedienteSessao(sessao_plenaria_id={} e tipo_id={}) salvo com sucesso.'
.format(self.object.id, tipo))
return self.form_valid(form)
@ -2609,7 +2611,8 @@ class OcorrenciaSessaoView(FormMixin, DetailView):
username = self.request.user.username
self.logger.info(
'user=' + username + '. OcorrenciaSessao de sessao_plenaria_id={} atualizada com sucesso.'.format(self.object.id))
'user=' + username + '. OcorrenciaSessao de sessao_plenaria_id={} atualizada com sucesso.'.format(
self.object.id))
@method_decorator(permission_required('sessao.add_ocorrenciasessao'))
def post(self, request, *args, **kwargs):
@ -2677,7 +2680,8 @@ class ConsideracoesFinaisView(FormMixin, DetailView):
username = self.request.user.username
self.logger.info(
'user=' + username + '. consideracoesFinais de sessao_plenaria_id={} atualizada com sucesso.'.format(self.object.id))
'user=' + username + '. consideracoesFinais de sessao_plenaria_id={} atualizada com sucesso.'.format(
self.object.id))
@method_decorator(permission_required('sessao.add_consideracoesfinais'))
def post(self, request, *args, **kwargs):
@ -2701,7 +2705,6 @@ class ConsideracoesFinaisView(FormMixin, DetailView):
class VotacaoEditView(SessaoPermissionMixin):
'''
Votação Simbólica e Secreta
'''
@ -2774,7 +2777,6 @@ class VotacaoEditView(SessaoPermissionMixin):
class VotacaoView(SessaoPermissionMixin):
"""
Votação Simbólica e Secreta
"""
@ -2895,7 +2897,8 @@ class VotacaoView(SessaoPermissionMixin):
except Exception as e:
username = request.user.username
self.logger.error('user=' + username + '. Problemas ao salvar RegistroVotacao da materia de id={} '
'e da ordem de id={}. '.format(materia_id, ordem_id) + str(e))
'e da ordem de id={}. '.format(materia_id, ordem_id) + str(
e))
return self.form_invalid(form)
else:
ordem = OrdemDia.objects.get(id=ordem_id)
@ -3266,7 +3269,8 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
if not ordem or not votacao:
self.logger.error(
'user=' + username + '. Objeto OrdemDia com id={} ou RegistroVotacao de OrdemDia não existe.'.format(ordem_id))
'user=' + username + '. Objeto OrdemDia com id={} ou RegistroVotacao de OrdemDia não existe.'.format(
ordem_id))
raise Http404()
materia = ordem.materia
@ -3530,7 +3534,6 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView):
class VotacaoExpedienteView(SessaoPermissionMixin):
"""
Votação Simbólica e Secreta
"""
@ -3683,7 +3686,6 @@ class VotacaoExpedienteView(SessaoPermissionMixin):
class VotacaoExpedienteEditView(SessaoPermissionMixin):
"""
Votação Simbólica e Secreta
"""
@ -4070,7 +4072,8 @@ def verifica_materia_sessao_plenaria_ajax(request):
materia=id_materia_selecionada
).exists()
return JsonResponse({'is_materia_presente': is_materia_presente, 'is_materia_presente_any_sessao': is_materia_presente_any_sessao})
return JsonResponse(
{'is_materia_presente': is_materia_presente, 'is_materia_presente_any_sessao': is_materia_presente_any_sessao})
class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
@ -4316,7 +4319,6 @@ class JustificativaAusenciaCrud(MasterDetailCrud):
@property
def layout_display(self):
layout = super().layout_display
if self.object.ausencia == 2:
@ -4335,7 +4337,6 @@ class JustificativaAusenciaCrud(MasterDetailCrud):
layout_key = None
def get_context_data_old(self, **kwargs):
context = super().get_context_data(**kwargs)
presencas = SessaoPlenariaPresenca.objects.filter(
@ -4371,7 +4372,6 @@ class JustificativaAusenciaCrud(MasterDetailCrud):
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = JustificativaAusenciaForm
layout_key = None
@ -4384,6 +4384,97 @@ class JustificativaAusenciaCrud(MasterDetailCrud):
pass
class LeituraEmBloco(PermissionRequiredForAppCrudMixin, ListView):
template_name = 'sessao/leitura/leitura_bloco.html'
app_label = AppConfig.label
expediente = True
paginate_by = 100
def get_queryset(self):
return ExpedienteMateria.objects.filter(sessao_plenaria_id=self.kwargs['pk'],
retiradapauta=None, tipo_votacao=LEITURA, registroleitura__materia=None)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['pk'] = self.kwargs['pk']
context['root_pk'] = self.kwargs['pk']
if not verifica_sessao_iniciada(self.request, self.kwargs['pk']):
context['sessao_iniciada'] = False
return context
context['sessao_iniciada'] = True
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
if self.expediente:
context['expediente'] = True
else:
context['expediente'] = False
return context
def post(self, request, *args, **kwargs):
if 'marcadas_4' in request.POST:
models = None
selectedlist = request.POST.getlist('marcadas_4')
if request.POST['origem'] == 'ordem':
models = OrdemDia.objects.filter(id__in=selectedlist)
elif request.POST['origem'] == 'expediente':
models = ExpedienteMateria.objects.filter(id__in=selectedlist)
if not models:
messages.add_message(self.request, messages.ERROR,
_('Impossível localizar as matérias selecionadas'))
return self.get(request, self.kwargs)
materias = [m.materia for m in models]
RegistroLeitura.objects.filter(materia__in=materias).delete()
leituras = []
for m in models:
obj = None
if isinstance(m, ExpedienteMateria):
obj = RegistroLeitura(expediente=m, materia=m.materia,
observacao=request.POST['observacao'],
user=self.request.user,
ip=get_client_ip(self.request))
elif isinstance(m, OrdemDia):
obj = RegistroLeitura(ordem=m, materia=m.materia,
observacao=request.POST['observacao'],
user=self.request.user,
ip=get_client_ip(self.request))
leituras.append(obj)
RegistroLeitura.objects.bulk_create(leituras)
else:
messages.add_message(self.request, messages.ERROR, _('Nenhuma matéria selecionada para leitura em Bloco'))
return self.get(request, self.kwargs)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
if self.request.POST['origem'] == 'ordem':
return reverse('sapl.sessao:ordemdia_list',
kwargs={'pk': self.kwargs['pk']})
else:
return reverse('sapl.sessao:expedientemateria_list',
kwargs={'pk': self.kwargs['pk']})
class LeituraEmBlocoExpediente(LeituraEmBloco):
expediente = True
paginate_by = 100
def get_queryset(self):
return ExpedienteMateria.objects.filter(sessao_plenaria_id=self.kwargs['pk'],
retiradapauta=None, tipo_votacao=LEITURA, registroleitura__materia=None)
class LeituraEmBlocoOrdemDia(LeituraEmBloco):
expediente = False
paginate_by = 100
def get_queryset(self):
return OrdemDia.objects.filter(sessao_plenaria_id=self.kwargs['pk'],
retiradapauta=None, tipo_votacao=LEITURA, registroleitura__materia=None)
class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView):
template_name = 'sessao/votacao/votacao_bloco.html'
app_label = AppConfig.label
@ -4423,7 +4514,6 @@ class VotacaoEmBlocoOrdemDia(VotacaoEmBlocoExpediente):
class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateView):
"""
Votação Simbólica
"""
@ -4551,8 +4641,10 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
votacao.save()
except Exception as e:
username = request.user.username
self.logger.error('user=' + username + '. Problemas ao salvar RegistroVotacao da materia de id={} '
'e da ordem de id={}. '.format(expediente.materia.id, expediente.id) + str(e))
self.logger.error(
'user=' + username + '. Problemas ao salvar RegistroVotacao da materia de id={} '
'e da ordem de id={}. '.format(expediente.materia.id,
expediente.id) + str(e))
return self.form_invalid(form, context)
else:
expediente.resultado = resultado.nome

114
sapl/templates/sessao/leitura/leitura_bloco.html

@ -0,0 +1,114 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block base_content %}
{% if sessao_iniciada %}
<form method="POST" enctype="application/x-www-form-urlencoded" id="form" action="{% url 'sapl.sessao:leitura_bloco_expediente' pk %}">
{% csrf_token %}
<br><br>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3>{% trans "Mensagem de Leitura" %}</h3></td>
</tr>
</thead>
<tr>
<td class="col-md-12">
<div class="row">
<div class="col-md-12">
Observações
<textarea id="observacao" name="observacao" cols="10" rows="10" class="form-control"></textarea>
</div>
</div>
</td>
</tr>
</table>
<br>
<h3 id='frase_selecione'>{% if expediente %} Selecione o(s) expediente(s) desejado(s). {% else %} Selecione a(s) ordem(s) do dia desejada(s). {% endif %}</h3>
<table id='tab_mats' class="table table-striped table-bordered">
<thead class="thead-default">
<tr>
<td><h3> {% if expediente %} {% trans "Expediente" %} {% else %} {% trans "Ordem do Dia" %} {% endif %} </h3></td>
</tr>
</thead>
<div class="checkbox" id="check_all">
<label for="id_check_all">
<input type="checkbox" id="id_check_all" onchange="toggleCheck(this)" /> Marcar/Desmarcar Todos
</label>
</div>
{% for o in object_list %}
<tr class="{% if o.tipo_votacao == 4 %}Leitura{% endif %}" {% if o.tipo_votacao != 4 %} style="display:none;" {% endif %}>
<td>
<input type="checkbox" name="marcadas_{{o.tipo_votacao}}" id="{{o.id}}" value="{{o.id}}" {% if check %} checked {% endif %}>
<strong><a href="{% url 'sapl.materia:materialegislativa_detail' o.materia.id %}">{{o.materia.tipo.sigla}} {{o.materia.numero}}/{{o.materia.ano}} - {{o.materia.tipo}}</strong></a></br>
{% if o.materia.numeracao_set.last %}
<strong>Processo:</strong> &nbsp; {{o.materia.numeracao_set.last}}<br>
{% endif %}
<strong>Autor:</strong>
{% for a in o.materia.autoria_set.all %}
{% if not forloop.first %}
, &nbsp;&nbsp; {{a.autor|default_if_none:""}}
{% else %}
&nbsp;{{a.autor|default_if_none:""}}
{% endif %}
{% endfor %}
<br>
{% if o.materia.numero_protocolo %}
<strong>Protocolo:</strong> &nbsp; {{o.materia.numero_protocolo}}</br>
{% endif %}
{% if o.materia.tramitacao_set.first %}
{% if o.materia.tramitacao_set.first.turno %}
<strong>Turno:</strong>&nbsp;
{% for t in turno_choices %}
{% if t.0 == o.materia.tramitacao_set.first.turno %}
{{ t.1 }}
{% endif %}
{% endfor %}<br>
{% endif %}
{% endif %}
<strong>Ementa:</strong>&nbsp;{{ o.materia.ementa|safe }}<br>
<p></p>
</td>
</tr>
{% endfor %}
</table>
{% include 'paginacao.html' %}
<table class="table table-striped table-bordered" style="display:none" id="nenhuma_mat">
<tr>
<td>
<h3>{% if expediente %} Nenhuma matéria do expediente aberta. {% else %} Nenhuma matéria da ordem do dia aberta. {% endif %} </h3>
</td>
</tr>
</table>
{% if expediente %}
<a href="{% url 'sapl.sessao:expedientemateria_list' pk %}" class="btn btn-warning mb-3" id="but_cancel">Voltar</a>
<input type="hidden" id="origem" name="origem" value="expediente">
{% else %}
<a href="{% url 'sapl.sessao:ordemdia_list' pk %}" class="btn btn-warning mb-3" id="but_cancel">Voltar</a>
<input type="hidden" id="origem" name="origem" value="ordem">
{% endif %}
<input type="submit" value="Registrar Leitura" class="btn btn-primary mb-3 float-right" id="but_reg">
</form>
{% endif %}
{% endblock base_content %}
{% block extra_js %}
<script>
function toggleCheck(elem) {
let checkboxes = document.getElementsByName('marcadas_4');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
</script>
{% endblock extra_js%}

6
sapl/templates/sessao/subnav.yaml

@ -32,6 +32,9 @@
- title: {% trans 'Votação em Bloco' %}
url: votacao_bloco_expediente
check_permission: sessao.add_sessaoplenaria
- title: {% trans 'Leitura em Bloco' %}
url: leitura_bloco_expediente
check_permission: sessao.add_sessaoplenaria
- title: {% trans 'Copiar Matérias para Sessão Posterior' %}
url: transf_mat_exp
check_permission: sessao.add_sessaoplenaria
@ -48,6 +51,9 @@
- title: {% trans 'Votação em Bloco' %}
url: votacao_bloco_ordemdia
check_permission: sessao.add_sessaoplenaria
- title: {% trans 'Leitura em Bloco' %}
url: leitura_bloco_ordem_dia
check_permission: sessao.add_sessaoplenaria
- title: {% trans 'Copiar Matérias para Sessão Posterior' %}
url: transf_mat_ordemdia
check_permission: sessao.add_sessaoplenaria

Loading…
Cancel
Save