diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index e5f8576ed..e0215dd60 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 @@ -1027,32 +1027,45 @@ class JustificativaAusenciaForm(ModelForm): return justificativa -class ExpedienteLeitura(forms.Form): - materia = forms.CharField( - label='Matéria', - widget=forms.TextInput(attrs={'readonly': 'readonly'})) - - materia__ementa = forms.CharField( - label='Ementa', - widget=forms.TextInput(attrs={'readonly': 'readonly'})) +class OrdemExpedienteLeituraForm(forms.ModelForm): observacao = forms.CharField(required=False, label='Observação', widget=forms.Textarea,) + class Meta: + model = RegistroLeitura + fields = ['materia', + 'ordem', + 'expediente', + 'observacao'] + widgets = {'materia': forms.HiddenInput(), + 'ordem': forms.HiddenInput(), + 'expediente': 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( - [('materia', 12)]) - row2 = to_row( - [('materia__ementa', 12)]) - row3 = to_row( - [('observacao', 12)]) + [('observacao', 12)]) + + actions = [HTML('Cancelar')] self.helper = SaplFormHelper() self.helper.form_method = 'POST' self.helper.layout = Layout( Fieldset(_('Leitura de Matéria'), - row1, row2, row3, - form_actions(label='Salvar')) + 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/models.py b/sapl/sessao/models.py index 7b5743759..84b890296 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -861,3 +861,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_add=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( + 'RegistroVotacao 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 686f08bea..3509a5117 100644 --- a/sapl/sessao/urls.py +++ b/sapl/sessao/urls.py @@ -35,7 +35,8 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente, VotacaoEmBlocoOrdemDia, VotacaoEmBlocoExpediente, VotacaoEmBlocoSimbolicaView, VotacaoEmBlocoNominalView, recuperar_nome_tipo_sessao, - ExpedienteLeituraView) + ExpedienteLeituraView, + OrdemDiaLeituraView) from .apps import AppConfig @@ -151,13 +152,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'), @@ -165,8 +164,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'), @@ -196,5 +194,7 @@ urlpatterns = [ 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'), ] diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 0504e8064..737406711 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, ExpedienteLeitura +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: @@ -302,9 +307,15 @@ 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: - if not obj.tipo_votacao == 4: + if obj.tipo_votacao != 4: btn_registrar = '''
%s
%s' % - (url, - resultado_descricao, - resultado_observacao)) + resultado = ('%s

%s
' % + (url, + resultado_descricao, + resultado_observacao)) else: if obj.tipo_votacao == 2: @@ -4345,26 +4374,63 @@ class RetiradaPautaCrud(MasterDetailCrud): pass -class ExpedienteLeituraView(FormView): + +class AbstractLeituraView(FormView): template_name = 'sessao/votacao/leitura_form.html' - form_class = ExpedienteLeitura 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() sessao = SessaoPlenaria.objects.get(id=self.kwargs['pk']) - expediente = ExpedienteMateria.objects.get(id=self.kwargs['oid']) materia = MateriaLegislativa.objects.get(id=self.kwargs['mid']) - return {'materia': materia, 'materia__ementa':materia.ementa} + 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 + return initial def form_valid(self, form): - expediente = ExpedienteMateria.objects.get(id=self.kwargs['oid']) - expediente.resultado = "Matéria lida" - expediente.votacao_aberta = False - expediente.save() + 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'] - return reverse('sapl.sessao:expedientemateria_list', - kwargs={'pk': pk}) \ No newline at end of file + 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): + return self.get_success_url() + + +class ExpedienteLeituraView(AbstractLeituraView): + expediente = True + + +class OrdemDiaLeituraView(AbstractLeituraView): + expediente = False \ No newline at end of file diff --git a/sapl/templates/sessao/layouts.yaml b/sapl/templates/sessao/layouts.yaml index 911d6b9c9..67abdf16d 100644 --- a/sapl/templates/sessao/layouts.yaml +++ b/sapl/templates/sessao/layouts.yaml @@ -67,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 index 66ca3ac69..c49f24804 100644 --- a/sapl/templates/sessao/votacao/leitura_form.html +++ b/sapl/templates/sessao/votacao/leitura_form.html @@ -1,3 +1,6 @@ -{% extends "crud/form.html" %} -{% load i18n %} +{% extends "base.html" %} +{% load i18n crispy_forms_tags %} +{% block base_content %} + {% crispy form %} +{% endblock base_content %}