From 5799669cb8fb50e04d40a4b2c2421ef76e52f071 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Wed, 9 Oct 2019 11:51:22 -0300 Subject: [PATCH] =?UTF-8?q?Fix=20#2927=20#2507=20-=20Mat=C3=A9rias=20apena?= =?UTF-8?q?s=20lidas=20e=20n=C3=A3o=20votadas=20(#2953)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #2927 - Matérias apenas lidas, mas não votadas * Adiciona Leitura para OrdemDia e cria model RegistroLeitura * Adiciona cancelamento de leitura * Adiciona matérias apenas lidas no painel * Adiciona url de cancelar leitura * Fix permissões * Adiciona registro de usuário e ip no RegistroLeitura --- sapl/painel/views.py | 84 +++++--- sapl/rules/map_rules.py | 1 + sapl/sessao/forms.py | 56 ++++- .../migrations/0046_auto_20190827_1228.py | 62 ++++++ .../migrations/0047_auto_20190829_1253.py | 30 +++ sapl/sessao/models.py | 53 ++++- sapl/sessao/urls.py | 23 +- sapl/sessao/views.py | 196 +++++++++++++++--- sapl/templates/painel/index.html | 26 ++- .../sessao/expedientemateria_form.html | 19 +- sapl/templates/sessao/layouts.yaml | 2 + .../sessao/votacao/leitura_form.html | 6 + 12 files changed, 482 insertions(+), 76 deletions(-) create mode 100644 sapl/sessao/migrations/0046_auto_20190827_1228.py create mode 100644 sapl/sessao/migrations/0047_auto_20190829_1253.py create mode 100644 sapl/templates/sessao/votacao/leitura_form.html diff --git a/sapl/painel/views.py b/sapl/painel/views.py index 5cadba9a1..097c033a2 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -21,7 +21,7 @@ from sapl.parlamentares.models import Legislatura, Parlamentar, Votante from sapl.sessao.models import (ExpedienteMateria, OradorExpediente, OrdemDia, PresencaOrdemDia, RegistroVotacao, SessaoPlenaria, SessaoPlenariaPresenca, - VotoParlamentar) + VotoParlamentar, RegistroLeitura) from sapl.utils import filiacao_data, get_client_ip, sort_lista_chave from .models import Cronometro @@ -361,7 +361,7 @@ def get_presentes(pk, response, materia): else: presentes = SessaoPlenariaPresenca.objects.filter( sessao_plenaria_id=pk) - + sessao = SessaoPlenaria.objects.get(id=pk) num_presentes = len(presentes) data_sessao = sessao.data_inicio @@ -408,6 +408,8 @@ def get_presentes(pk, response, materia): tipo_votacao = 'Nominal' elif materia.tipo_votacao == 3: tipo_votacao = 'Secreta' + elif materia.tipo_votacao == 4: + tipo_votacao = 'Leitura' response.update({ 'tipo_resultado': materia.resultado, @@ -442,15 +444,27 @@ def response_nenhuma_materia(response): def get_votos(response, materia): logger = logging.getLogger(__name__) if type(materia) == OrdemDia: - registro = RegistroVotacao.objects.filter( - ordem=materia, materia=materia.materia).last() + if materia.tipo_votacao != 4: + registro = RegistroVotacao.objects.filter( + ordem=materia, materia=materia.materia).order_by('data_hora').last() + leitura = None + else: + leitura = RegistroLeitura.objects.filter( + ordem=materia, materia=materia.materia).order_by('data_hora').last() + registro = None tipo = 'ordem' elif type(materia) == ExpedienteMateria: - registro = RegistroVotacao.objects.filter( - expediente=materia, materia=materia.materia).last() + if materia.tipo_votacao != 4: + registro = RegistroVotacao.objects.filter( + expediente=materia, materia=materia.materia).order_by('data_hora').last() + leitura = None + else: + leitura = RegistroLeitura.objects.filter( + expediente=materia, materia=materia.materia).order_by('data_hora').last() + registro = None tipo = 'expediente' - if not registro: + if not registro and not leitura: response.update({ 'numero_votos_sim': 0, 'numero_votos_nao': 0, @@ -479,7 +493,15 @@ def get_votos(response, materia): logger.error("Votos do parlamentar (id={}) não encontrados. Retornado vazio." .format(p['parlamentar_id'])) response['presentes'][i]['voto'] = '' - + elif leitura: + response.update({ + 'numero_votos_sim': 0, + 'numero_votos_nao': 0, + 'numero_abstencoes': 0, + 'registro': True, + 'total_votos': 0, + 'tipo_resultado': 'Matéria lida.', + }) else: total = (registro.numero_votos_sim + registro.numero_votos_nao + @@ -556,33 +578,33 @@ def get_dados_painel(request, pk): # Caso não tenha nenhuma aberta, # a matéria a ser mostrada no Painel deve ser a última votada last_ordem_voto = RegistroVotacao.objects.filter( - ordem__sessao_plenaria=sessao).last() + ordem__sessao_plenaria=sessao).order_by('data_hora').last() last_expediente_voto = RegistroVotacao.objects.filter( - expediente__sessao_plenaria=sessao).last() - - if last_ordem_voto: - ultima_ordem_votada = last_ordem_voto.ordem - if last_expediente_voto: - ultimo_expediente_votado = last_expediente_voto.expediente + expediente__sessao_plenaria=sessao).order_by('data_hora').last() - if last_ordem_voto or last_expediente_voto: - # Se alguma ordem E algum expediente já tiver sido votado... - if last_ordem_voto and last_expediente_voto: - materia = ultima_ordem_votada\ - if last_ordem_voto.pk >= last_expediente_voto.pk\ - else ultimo_expediente_votado - - # Caso somente um deles tenha resultado, prioriza a Ordem do Dia - elif last_ordem_voto: - materia = ultima_ordem_votada - - # Caso a Ordem do dia não tenha resultado, mostra o último expediente - elif last_expediente_voto: - materia = ultimo_expediente_votado + last_ordem_leitura = RegistroLeitura.objects.filter( + ordem__sessao_plenaria=sessao).order_by('data_hora').last() + last_expediente_leitura = RegistroLeitura.objects.filter( + expediente__sessao_plenaria=sessao).order_by('data_hora').last() + # Obtém última matéria que foi votada, através do timestamp mais recente + if last_ordem_voto: + ordem_expediente = last_ordem_voto.ordem + ultimo_timestamp = last_ordem_voto.data_hora + if last_expediente_voto and last_expediente_voto.data_hora > ultimo_timestamp: + ordem_expediente = last_expediente_voto.expediente + ultimo_timestamp = last_expediente_voto.data_hora + if last_ordem_leitura and last_ordem_leitura.data_hora > ultimo_timestamp: + ordem_expediente = last_ordem_leitura.ordem + ultimo_timestamp = last_ordem_leitura.data_hora + if last_expediente_leitura and last_expediente_leitura.data_hora > ultimo_timestamp: + ordem_expediente = last_expediente_leitura.expediente + ultimo_timestamp = last_expediente_leitura.data_hora + + if ordem_expediente: return JsonResponse(get_votos( - get_presentes(pk, response, materia), - materia)) + get_presentes(pk, response, ordem_expediente), + ordem_expediente)) # Retorna que não há nenhuma matéria já votada ou aberta return response_nenhuma_materia(get_presentes(pk, response, None)) diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index aa187477d..e057e8d15 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -187,6 +187,7 @@ rules_group_sessao = { (sessao.VotoParlamentar, __base__, __perms_publicas__), (sessao.JustificativaAusencia, __base__, __perms_publicas__), (sessao.RetiradaPauta, __base__, __perms_publicas__), + (sessao.RegistroLeitura, __base__, __perms_publicas__), ] } diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 4e2a0498f..bbf6cb41d 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -28,7 +28,7 @@ from .models import (Bancada, ExpedienteMateria, JustificativaAusencia, Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoResultadoVotacao, OcorrenciaSessao, RetiradaPauta, TipoRetiradaPauta, OradorOrdemDia, ORDENACAO_RESUMO, - ResumoOrdenacao) + ResumoOrdenacao, RegistroLeitura) MES_CHOICES = RANGE_MESES @@ -358,6 +358,8 @@ class ExpedienteMateriaForm(ModelForm): initial=datetime.strftime(timezone.now(), '%d/%m/%Y'), widget=forms.TextInput(attrs={'readonly': 'readonly'})) + apenas_leitura = forms.BooleanField(label='Apenas Leitura', required=False) + class Meta: model = ExpedienteMateria fields = ['data_ordem', 'numero_ordem', 'tipo_materia', 'observacao', @@ -493,7 +495,7 @@ class VotacaoForm(forms.Form): resultado_votacao = forms.CharField(label='Resultado da Votação') def clean(self): - cleaned_data = super(VotacaoForm, self).clean() + cleaned_data = super().clean() if not self.is_valid(): return cleaned_data @@ -598,7 +600,7 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet): ] 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['autoria__autor__tipo'].label = 'Tipo de Autor' @@ -1023,3 +1025,51 @@ class JustificativaAusenciaForm(ModelForm): justificativa.materias_do_expediente.clear() justificativa.materias_da_ordem_do_dia.clear() return justificativa + + +class OrdemExpedienteLeituraForm(forms.ModelForm): + + observacao = forms.CharField(required=False, label='Observação', widget=forms.Textarea,) + + class Meta: + model = RegistroLeitura + fields = ['materia', + 'ordem', + 'expediente', + 'observacao', + 'user', + 'ip'] + widgets = {'materia': forms.HiddenInput(), + 'ordem': forms.HiddenInput(), + 'expediente': forms.HiddenInput(), + 'user': forms.HiddenInput(), + 'ip': forms.HiddenInput() + } + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + instance = self.initial['instance'] + if instance: + self.instance = instance.first() + self.fields['observacao'].initial = self.instance.observacao + + row1 = to_row( + [('observacao', 12)]) + + actions = [HTML('Cancelar Leitura')] + + self.helper = SaplFormHelper() + self.helper.form_method = 'POST' + self.helper.layout = Layout( + Fieldset(_('Leitura de Matéria'), + HTML(''' + Matéria: {{materia}}
+ Ementa: {{materia.ementa}}
+ '''), + row1, + form_actions(more=actions), + ) + ) \ No newline at end of file diff --git a/sapl/sessao/migrations/0046_auto_20190827_1228.py b/sapl/sessao/migrations/0046_auto_20190827_1228.py new file mode 100644 index 000000000..d37e2b200 --- /dev/null +++ b/sapl/sessao/migrations/0046_auto_20190827_1228.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-08-27 15:28 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0055_auto_20190816_0943'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('sessao', '0045_auto_20190816_1337'), + ] + + operations = [ + migrations.CreateModel( + name='RegistroLeitura', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('observacao', models.TextField(blank=True, verbose_name='Observações')), + ('ip', models.CharField(blank=True, default='', max_length=30, verbose_name='IP')), + ('data_hora', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Data/Hora')), + ], + options={ + 'verbose_name': 'Leitura', + 'verbose_name_plural': 'Leituras', + }, + ), + migrations.AlterField( + model_name='expedientemateria', + name='tipo_votacao', + field=models.PositiveIntegerField(choices=[(1, 'Simbólica'), (2, 'Nominal'), (3, 'Secreta'), (4, 'Leitura')], default=1, verbose_name='Tipo de votação'), + ), + migrations.AlterField( + model_name='ordemdia', + name='tipo_votacao', + field=models.PositiveIntegerField(choices=[(1, 'Simbólica'), (2, 'Nominal'), (3, 'Secreta'), (4, 'Leitura')], default=1, verbose_name='Tipo de votação'), + ), + migrations.AddField( + model_name='registroleitura', + name='expediente', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sessao.ExpedienteMateria'), + ), + migrations.AddField( + model_name='registroleitura', + name='materia', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.MateriaLegislativa'), + ), + migrations.AddField( + model_name='registroleitura', + name='ordem', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='sessao.OrdemDia'), + ), + migrations.AddField( + model_name='registroleitura', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/sapl/sessao/migrations/0047_auto_20190829_1253.py b/sapl/sessao/migrations/0047_auto_20190829_1253.py new file mode 100644 index 000000000..277233e37 --- /dev/null +++ b/sapl/sessao/migrations/0047_auto_20190829_1253.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-08-29 15:53 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sessao', '0046_auto_20190827_1228'), + ] + + operations = [ + migrations.AlterField( + model_name='registroleitura', + name='data_hora', + field=models.DateTimeField(auto_now=True, null=True, verbose_name='Data/Hora'), + ), + migrations.AlterField( + model_name='registrovotacao', + name='data_hora', + field=models.DateTimeField(auto_now=True, null=True, verbose_name='Data/Hora'), + ), + migrations.AlterField( + model_name='votoparlamentar', + name='data_hora', + field=models.DateTimeField(auto_now=True, null=True, verbose_name='Data/Hora'), + ), + ] diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py index 2856a0602..ba4404b26 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -311,6 +311,7 @@ class AbstractOrdemDia(models.Model): (1, 'simbolica', 'Simbólica'), (2, 'nominal', 'Nominal'), (3, 'secreta', 'Secreta'), + (4, 'leitura', 'Leitura') ) sessao_plenaria = models.ForeignKey(SessaoPlenaria, @@ -560,7 +561,7 @@ class RegistroVotacao(models.Model): default='') data_hora = models.DateTimeField( verbose_name=_('Data/Hora'), - auto_now_add=True, + auto_now=True, blank=True, null=True) @@ -611,7 +612,7 @@ class VotoParlamentar(models.Model): # RegistroVotacaoParlamentar default='') data_hora = models.DateTimeField( verbose_name=_('Data/Hora'), - auto_now_add=True, + auto_now=True, blank=True, null=True) @@ -880,3 +881,51 @@ class RetiradaPauta(models.Model): 'ReritadaPauta deve ter exatamente um dos campos ' 'ordem ou expediente preenchido. Ambos estão preenchidos: ' '{}, {}'. format(self.ordem, self.expediente)) + + +@reversion.register() +class RegistroLeitura(models.Model): + materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE) + ordem = models.ForeignKey(OrdemDia, + blank=True, + null=True, + on_delete=models.CASCADE) + expediente = models.ForeignKey(ExpedienteMateria, + blank=True, + null=True, + on_delete=models.CASCADE) + observacao = models.TextField( + blank=True, verbose_name=_('Observações')) + user = models.ForeignKey(get_settings_auth_user_model(), + on_delete=models.PROTECT, + null=True, + blank=True) + ip = models.CharField(verbose_name=_('IP'), + max_length=30, + blank=True, + default='') + data_hora = models.DateTimeField( + verbose_name=_('Data/Hora'), + auto_now=True, + blank=True, + null=True) + + class Meta: + verbose_name = _('Leitura') + verbose_name_plural = _('Leituras') + + def __str__(self): + return _('Leitura - ' + 'Matéria: %(materia)s') % { + 'materia': self.materia} + + def clean(self): + """Exatamente um dos campos ordem ou expediente deve estar preenchido. + """ + # TODO remover esse método quando OrdemDia e ExpedienteMateria + # forem reestruturados e os campos ordem e expediente forem unificados + if not xor(bool(self.ordem), bool(self.expediente)): + raise ValidationError( + 'RegistroLeitura deve ter exatamente um dos campos ' + 'ordem ou expediente preenchido. Ambos estão preenchidos: ' + '{}, {}'. format(self.ordem, self.expediente)) \ No newline at end of file diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py index c14bc6915..3e5dd67d7 100644 --- a/sapl/sessao/urls.py +++ b/sapl/sessao/urls.py @@ -34,7 +34,10 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente, sessao_legislativa_legislatura_ajax, VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente, VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView, - recuperar_nome_tipo_sessao) + recuperar_nome_tipo_sessao, + ExpedienteLeituraView, + OrdemDiaLeituraView, + retirar_leitura) from .apps import AppConfig @@ -150,13 +153,11 @@ urlpatterns = [ PesquisarSessaoPlenariaView.as_view(), name='pesquisar_sessao'), url(r'^sessao/(?P\d+)/matordemdia/votnom/(?P\d+)/(?P\d+)$', VotacaoNominalView.as_view(), name='votacaonominal'), - url(r'^sessao/(?P\d+)/matordemdia/votnom' - '/edit/(?P\d+)/(?P\d+)$', + url(r'^sessao/(?P\d+)/matordemdia/votnom/edit/(?P\d+)/(?P\d+)$', VotacaoNominalEditView.as_view(), name='votacaonominaledit'), url(r'^sessao/(?P\d+)/matordemdia/votsec/(?P\d+)/(?P\d+)$', VotacaoView.as_view(), name='votacaosecreta'), - url(r'^sessao/(?P\d+)/matordemdia/votsec' - '/view/(?P\d+)/(?P\d+)$', + url(r'^sessao/(?P\d+)/matordemdia/votsec/view/(?P\d+)/(?P\d+)$', VotacaoEditView.as_view(), name='votacaosecretaedit'), url(r'^sessao/(?P\d+)/matordemdia/votsimb/(?P\d+)/(?P\d+)$', VotacaoView.as_view(), name='votacaosimbolica'), @@ -164,8 +165,7 @@ urlpatterns = [ url(r'^sessao/(?P\d+)/matordemdia/votsimbbloco/$', VotacaoView.as_view(), name='votacaosimbolicabloco'), - url(r'^sessao/(?P\d+)/matordemdia/votsimb' - '/view/(?P\d+)/(?P\d+)$', + url(r'^sessao/(?P\d+)/matordemdia/votsimb/view/(?P\d+)/(?P\d+)$', VotacaoEditView.as_view(), name='votacaosimbolicaedit'), url(r'^sessao/(?P\d+)/matexp/votnom/(?P\d+)/(?P\d+)$', VotacaoNominalExpedienteView.as_view(), name='votacaonominalexp'), @@ -192,4 +192,13 @@ urlpatterns = [ url(r'^sessao/mudar-ordem-materia-sessao/', mudar_ordem_materia_sessao, name='mudar_ordem_materia_sessao'), + + url(r'^sessao/(?P\d+)/matexp/leitura/(?P\d+)/(?P\d+)$', + ExpedienteLeituraView.as_view(), name='leituraexp'), + url(r'^sessao/(?P\d+)/matordemdia/leitura/(?P\d+)/(?P\d+)$', + OrdemDiaLeituraView.as_view(), name='leituraod'), + + url(r'^sessao/(?P\d+)/(?P\d+)/(?P\d+)/retirar-leitura$', + retirar_leitura, name='retirar_leitura'), + ] diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 18ef96341..cbf896934 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -34,7 +34,7 @@ from sapl.materia.views import MateriaLegislativaPesquisaView from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, Parlamentar, SessaoLegislativa) from sapl.sessao.apps import AppConfig -from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm +from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm, OrdemExpedienteLeituraForm from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, @@ -49,7 +49,8 @@ from .models import (Bancada, CargoBancada, CargoMesa, PresencaOrdemDia, RegistroVotacao, ResumoOrdenacao, SessaoPlenaria, SessaoPlenariaPresenca, TipoExpediente, TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar, TipoRetiradaPauta, - RetiradaPauta, TipoJustificativa, JustificativaAusencia, OradorOrdemDia, ORDENACAO_RESUMO) + RetiradaPauta, TipoJustificativa, JustificativaAusencia, OradorOrdemDia, + ORDENACAO_RESUMO, RegistroLeitura) TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria') @@ -142,12 +143,12 @@ def verifica_votacoes_abertas(request): kwargs={'pk': v.id}), v.__str__())) username = request.user.username - logger.info('user=' + username + '. Já existem votações abertas nas seguintes Sessões: ' + + logger.info('user=' + username + '. Já existem votações ou leituras abertas nas seguintes Sessões: ' + ', '.join(msg_abertas) + '. Para abrir ' - 'outra, termine ou feche as votações abertas.') - msg = _('Já existem votações abertas nas seguintes Sessões: ' + + 'outra, termine ou feche as votações ou leituras abertas.') + msg = _('Já existem votações ou leituras abertas nas seguintes Sessões: ' + ', '.join(msg_abertas) + '. Para abrir ' - 'outra, termine ou feche as votações abertas.') + 'outra, termine ou feche as votações ou leituras abertas.') messages.add_message(request, messages.INFO, msg) return False @@ -254,7 +255,11 @@ def customize_link_materia(context, pk, has_permission, is_expediente): materia=obj.materia).exists() exist_retirada = obj.retiradapauta_set.filter( materia=obj.materia).exists() - if not exist_resultado and not exist_retirada: + 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.votacao_aberta: url = '' if is_expediente: @@ -276,6 +281,13 @@ def customize_link_materia(context, pk, has_permission, is_expediente): 'pk': obj.sessao_plenaria_id, 'oid': obj.pk, 'mid': obj.materia_id}) + elif obj.tipo_votacao == 4: + url = reverse('sapl.sessao:leituraexp', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + else: if obj.tipo_votacao == 1: url = reverse('sapl.sessao:votacaosimbolica', @@ -295,13 +307,28 @@ def customize_link_materia(context, pk, has_permission, is_expediente): 'pk': obj.sessao_plenaria_id, 'oid': obj.pk, 'mid': obj.materia_id}) + elif obj.tipo_votacao == 4: + url = reverse('sapl.sessao:leituraod', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) + if has_permission: - btn_registrar = ''' -
- -
''' % ( - url) + if obj.tipo_votacao != 4: + btn_registrar = ''' +
+ +
''' % ( + url) + else: + btn_registrar = ''' +
+ +
''' % ( + url) resultado = btn_registrar else: @@ -319,12 +346,20 @@ def customize_link_materia(context, pk, has_permission, is_expediente): }) + '?tipo_materia=ordem' if has_permission: - btn_abrir = ''' - Matéria não votada
- Abrir Votação''' % (url) - resultado = btn_abrir + if not obj.tipo_votacao == 4: + btn_abrir = ''' + Matéria não votada
+ Abrir Votação''' % (url) + resultado = btn_abrir + else: + btn_abrir = ''' + Matéria não lida
+ Abrir para Leitura''' % (url) + resultado = btn_abrir else: resultado = '''Não há resultado''' @@ -341,10 +376,16 @@ def customize_link_materia(context, pk, has_permission, is_expediente): retirada_observacao)) else: - resultado = obj.registrovotacao_set.filter( - materia_id=obj.materia_id).last() - resultado_descricao = resultado.tipo_resultado_votacao.nome - resultado_observacao = resultado.observacao + if obj.tipo_votacao == 4: + resultado = obj.registroleitura_set.filter( + materia_id=obj.materia_id).last() + resultado_descricao = "Matéria lida" + resultado_observacao = resultado.observacao + else: + resultado = obj.registrovotacao_set.filter( + materia_id=obj.materia_id).last() + resultado_descricao = obj.resultado + resultado_observacao = obj.observacao if has_permission: url = '' @@ -368,6 +409,12 @@ def customize_link_materia(context, pk, has_permission, is_expediente): 'pk': obj.sessao_plenaria_id, 'oid': obj.pk, 'mid': obj.materia_id}) + elif obj.tipo_votacao == 4: + url = reverse('sapl.sessao:leituraexp', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) else: if obj.tipo_votacao == 1: url = reverse('sapl.sessao:votacaosimbolicaedit', @@ -387,11 +434,17 @@ def customize_link_materia(context, pk, has_permission, is_expediente): 'pk': obj.sessao_plenaria_id, 'oid': obj.pk, 'mid': obj.materia_id}) + elif obj.tipo_votacao == 4: + url = reverse('sapl.sessao:leituraod', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.pk, + 'mid': obj.materia_id}) - resultado = ('%s
%s
' % - (url, - resultado_descricao, - resultado_observacao)) + resultado = ('%s

%s
' % + (url, + resultado_descricao, + resultado_observacao)) else: if obj.tipo_votacao == 2: @@ -4325,3 +4378,92 @@ class RetiradaPautaCrud(MasterDetailCrud): class DeleteView(MasterDetailCrud.DeleteView): pass + + + +class AbstractLeituraView(FormView): + template_name = 'sessao/votacao/leitura_form.html' + success_url = '/' + form_class = OrdemExpedienteLeituraForm + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['materia'] = MateriaLegislativa.objects.get(id=self.kwargs['mid']) + return context + + def get_initial(self): + initial = super().get_initial() + materia = MateriaLegislativa.objects.get(id=self.kwargs['mid']) + initial['materia'] = materia + initial['materia__ementa'] = materia.ementa + if self.expediente: + expediente = ExpedienteMateria.objects.get(id=self.kwargs['oid']) + instance = RegistroLeitura.objects.filter(materia=materia, expediente=expediente) + initial['expediente'] = expediente + else: + ordem = OrdemDia.objects.get(id=self.kwargs['oid']) + instance = RegistroLeitura.objects.filter(materia=materia, ordem=ordem) + initial['ordem'] = ordem + initial['instance'] = instance + initial['user'] = self.request.user + initial['ip'] = get_client_ip(self.request) + return initial + + def form_valid(self, form): + if self.expediente: + model = ExpedienteMateria + else: + model = OrdemDia + ordem_expediente = model.objects.get(id=self.kwargs['oid']) + ordem_expediente.resultado = "Matéria lida" + ordem_expediente.votacao_aberta = False + ordem_expediente.save() + form.save() + return super().form_valid(form) + + def get_success_url(self): + pk = self.kwargs['pk'] + if self.expediente: + url = reverse('sapl.sessao:expedientemateria_list', + kwargs={'pk': pk}) + else: + url = reverse('sapl.sessao:ordemdia_list', + kwargs={'pk': pk}) + return url + + def cancel_url(self): + url = reverse('sapl.sessao:retirar_leitura', + kwargs={ + 'pk': self.kwargs['pk'], + 'iso': 1 if not self.expediente else 0, + 'oid': self.kwargs['oid']}) + return url + + +class ExpedienteLeituraView(AbstractLeituraView): + expediente = True + + +class OrdemDiaLeituraView(AbstractLeituraView): + expediente = False + + +@permission_required('sessao.change_expedientemateria', + 'sessao.change_ordemdia') +def retirar_leitura(request, pk, iso, oid): + is_ordem = bool(int(iso)) + if not is_ordem: + ordem_expediente = ExpedienteMateria.objects.get(id=oid) + RegistroLeitura.objects.filter(materia=ordem_expediente.materia, expediente=ordem_expediente).delete() + succ_url = reverse('sapl.sessao:expedientemateria_list', + kwargs={'pk': pk}) + else: + ordem_expediente = OrdemDia.objects.get(id=oid) + RegistroLeitura.objects.filter(materia=ordem_expediente.materia, ordem=ordem_expediente).delete() + succ_url = reverse('sapl.sessao:ordemdia_list', + kwargs={'pk': pk}) + ordem_expediente.resultado = "" + ordem_expediente.votacao_aberta = False + ordem_expediente.save() + + return HttpResponseRedirect(succ_url) \ No newline at end of file diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index 217a09053..a7d08aeda 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -99,6 +99,7 @@

Matéria em Votação

+
@@ -421,23 +422,40 @@ else{ $("#observacao_materia").text(''); } - if (data['tipo_resultado'] && data['status_painel'] == true){ + if(data['tipo_votacao'] != 'Leitura'){ + $("#resultado_votacao").css("color", "#45919D"); + $("#mat_em_votacao").text("Matéria em Votação"); + $("#resultado_votacao_div").show(); + } + else{ + $("#resultado_votacao_div").hide(); + $("#mat_em_votacao").text("Matéria em Leitura"); + } + console.log(data["tipo_resultado"], data['tipo_votacao']); $("#resultado_votacao").text(data["tipo_resultado"]); - $("#resultado_votacao").css("color", "#45919D"); + var resultado_votacao_upper = $("#resultado_votacao").text().toUpperCase(); + console.log(resultado_votacao_upper, data['tipo_resultado']); if (resultado_votacao_upper.search("APROV") != -1){ $("#resultado_votacao").css("color", "green"); $("#mat_em_votacao").text("Matéria Votada"); } - if (resultado_votacao_upper.search("REJEIT") != -1){ + else if (resultado_votacao_upper.search("REJEIT") != -1){ $("#resultado_votacao").css("color", "red"); $("#mat_em_votacao").text("Matéria Votada"); } + else if (resultado_votacao_upper.search("LIDA") != -1){ + $("#mat_em_votacao").text("Matéria Lida"); + } } else{ $("#resultado_votacao").text(''); - $("#mat_em_votacao").text("Matéria em Votação"); + if(data['tipo_votacao'] != 'Leitura') + $("#mat_em_votacao").text("Matéria em Votação"); + else{ + $("#mat_em_votacao").text("Matéria em Leitura"); + } } }, error: function(err) { diff --git a/sapl/templates/sessao/expedientemateria_form.html b/sapl/templates/sessao/expedientemateria_form.html index 60a547e54..e90ec63ff 100644 --- a/sapl/templates/sessao/expedientemateria_form.html +++ b/sapl/templates/sessao/expedientemateria_form.html @@ -32,11 +32,26 @@ }); } } - var fields = ["#id_tipo_materia", "#id_numero_materia", "#id_ano_materia"] + var fields = ["#id_tipo_materia", "#id_numero_materia", "#id_ano_materia"]; for (i = 0; i < fields.length; i++) { $(fields[i]).change(recuperar_materia); } - recuperar_materia() + recuperar_materia(); + + $(document).ready(function(){ + $("select[name='tipo_votacao']").children("option[value='4']").remove(); + $('#id_apenas_leitura').change(function(event){ + $('#div_id_tipo_votacao').toggle(); + if($('#id_apenas_leitura').prop('checked')){ + $("select[name='tipo_votacao']").append(new Option('Leitura', '4')); + $("select[name='tipo_votacao']").val('4'); + } + else{ + $("select[name='tipo_votacao']").children("option[value='4']").remove(); + $("select[name='tipo_votacao']").val('1'); + } + }) + }); {% endblock %} diff --git a/sapl/templates/sessao/layouts.yaml b/sapl/templates/sessao/layouts.yaml index 9f08885b8..67abdf16d 100644 --- a/sapl/templates/sessao/layouts.yaml +++ b/sapl/templates/sessao/layouts.yaml @@ -59,6 +59,7 @@ ExpedienteMateria: - data_ordem numero_ordem - tipo_materia numero_materia ano_materia - tipo_votacao + - apenas_leitura - observacao OrdemDia: @@ -66,6 +67,7 @@ OrdemDia: - data_ordem numero_ordem - tipo_materia numero_materia ano_materia - tipo_votacao + - apenas_leitura - observacao ExpedienteMateriaDetail: diff --git a/sapl/templates/sessao/votacao/leitura_form.html b/sapl/templates/sessao/votacao/leitura_form.html new file mode 100644 index 000000000..c49f24804 --- /dev/null +++ b/sapl/templates/sessao/votacao/leitura_form.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% load i18n crispy_forms_tags %} + +{% block base_content %} + {% crispy form %} +{% endblock base_content %}