diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py index 6aea339ff..30089075f 100644 --- a/sapl/sessao/forms.py +++ b/sapl/sessao/forms.py @@ -1,7 +1,8 @@ -from datetime import datetime import re from crispy_forms.layout import Button, Fieldset, HTML, Layout +from datetime import datetime + from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, ValidationError @@ -12,6 +13,7 @@ from django.forms.widgets import CheckboxSelectMultiple from django.utils.translation import ugettext_lazy as _ import django_filters +import sapl.utils from sapl.base.models import Autor, TipoAutor from sapl.crispy_layout_mixin import (form_actions, to_row, SaplFormHelper, SaplFormLayout) @@ -33,13 +35,16 @@ from .models import (Bancada, ExpedienteMateria, ORDENACAO_RESUMO, PresencaOrdemDia, RegistroLeitura, ResumoOrdenacao, RetiradaPauta, SessaoPlenaria, SessaoPlenariaPresenca, - TipoResultadoVotacao, TipoRetiradaPauta) - + TipoResultadoVotacao, TipoRetiradaPauta, Tramitacao) MES_CHOICES = RANGE_MESES DIA_CHOICES = RANGE_DIAS_MES +def tramitacao_select_validation(): + return True + + class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm): class Meta: @@ -109,7 +114,7 @@ class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm): if upload_pauta: validar_arquivo(upload_pauta, "Pauta da Sessão") - + if upload_ata: validar_arquivo(upload_ata, "Ata da Sessão") @@ -117,12 +122,12 @@ class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm): validar_arquivo(upload_anexo, "Anexo da Sessão") hora_inicio = self.cleaned_data['hora_inicio'] - if not re.match(TIME_PATTERN, hora_inicio): + if not re.match(sapl.utils.TIME_PATTERN, hora_inicio): raise ValidationError(f'Formato ou valores de horário de ' f'abertura errados: {hora_inicio}') hora_fim = self.cleaned_data['hora_fim'] - if hora_fim and not re.match(TIME_PATTERN, hora_fim): + if hora_fim and not re.match(sapl.utils.TIME_PATTERN, hora_fim): raise ValidationError(f'Formato ou valores de horário de ' f'encerramento errados: {hora_fim}.') @@ -294,6 +299,12 @@ class BancadaForm(ModelForm): return bancada +class DependentChoiceField(forms.ChoiceField): + + def validate(self, value): + return True + + class ExpedienteMateriaForm(ModelForm): _model = ExpedienteMateria @@ -306,6 +317,10 @@ class ExpedienteMateriaForm(ModelForm): empty_label='Selecione', widget=forms.Select(attrs={'autocomplete': 'off'})) + tramitacao_select = DependentChoiceField( + label=_('Situação Atual'), + widget=forms.Select()) + numero_materia = forms.CharField( label='Número Matéria', required=True, widget=forms.TextInput(attrs={'autocomplete': 'off'})) @@ -326,7 +341,7 @@ class ExpedienteMateriaForm(ModelForm): class Meta: model = ExpedienteMateria fields = ['data_ordem', 'numero_ordem', 'tipo_materia', 'observacao', - 'numero_materia', 'ano_materia', 'tipo_votacao'] + 'numero_materia', 'ano_materia', 'tramitacao_select', 'tipo_votacao'] def clean_numero_ordem(self): sessao = self.instance.sessao_plenaria @@ -363,11 +378,28 @@ class ExpedienteMateriaForm(ModelForm): else: cleaned_data['materia'] = materia + try: + id_t = self.cleaned_data['tramitacao_select'] if self.cleaned_data['tramitacao_select'] != '' else -1 + tramitacao = materia.tramitacao_set.get(pk=self.cleaned_data['tramitacao_select'] if self.cleaned_data['tramitacao_select'] != '' else -1) + except ObjectDoesNotExist: + if self.cleaned_data['tramitacao_select'] != '': + raise ValidationError( + _('Tramitação selecionada não existe para a Matéria: %(value)s'), + code='invalid', + params={'value': self.cleaned_data['tramitacao_select']}, + ) + else: + cleaned_data['tramitacao'] = False + else: + cleaned_data['tramitacao'] = tramitacao + return cleaned_data def save(self, commit=False): expediente = super(ExpedienteMateriaForm, self).save(commit) expediente.materia = self.cleaned_data['materia'] + if self.cleaned_data['tramitacao'] is not False: + expediente.tramitacao = self.cleaned_data['tramitacao'] expediente.save() return expediente @@ -996,7 +1028,7 @@ class OrdemExpedienteLeituraForm(forms.ModelForm): 'ordem', 'expediente', 'observacao', - 'user', + 'user', 'ip'] widgets = {'materia': forms.HiddenInput(), 'ordem': forms.HiddenInput(), @@ -1008,14 +1040,14 @@ class OrdemExpedienteLeituraForm(forms.ModelForm): 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)]) + [('observacao', 12)]) actions = [HTML('Cancelar Leitura')] @@ -1024,11 +1056,11 @@ class OrdemExpedienteLeituraForm(forms.ModelForm): self.helper.form_method = 'POST' self.helper.layout = Layout( Fieldset(_('Leitura de Matéria'), - HTML(''' + HTML(''' Matéria: {{materia}}
Ementa: {{materia.ementa}}
'''), row1, form_actions(more=actions), - ) - ) + ) + ) \ No newline at end of file diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py index 39f144c2c..944c1e81d 100644 --- a/sapl/sessao/models.py +++ b/sapl/sessao/models.py @@ -10,6 +10,7 @@ import reversion from sapl.base.models import Autor from sapl.materia.models import MateriaLegislativa +from sapl.materia.models import Tramitacao from sapl.parlamentares.models import (CargoMesa, Legislatura, Parlamentar, Partido, SessaoLegislativa) from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation, @@ -360,6 +361,12 @@ class AbstractOrdemDia(models.Model): materia = models.ForeignKey(MateriaLegislativa, on_delete=models.PROTECT, verbose_name=_('Matéria')) + tramitacao = models.ForeignKey(Tramitacao, + on_delete=models.PROTECT, + verbose_name=_('Situação Atual'), + blank=True, + default='', + null=True) data_ordem = models.DateField(verbose_name=_('Data da Sessão')) observacao = models.TextField( blank=True, verbose_name=_('Observação')) diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py index af66c2d83..a2269972c 100644 --- a/sapl/sessao/urls.py +++ b/sapl/sessao/urls.py @@ -36,7 +36,8 @@ from sapl.sessao.views import (AdicionarVariasMateriasExpediente, OrdemDiaLeituraView, retirar_leitura, TransferenciaMateriasExpediente, TransferenciaMateriasOrdemDia, - filtra_materias_copia_sessao_ajax, verifica_materia_sessao_plenaria_ajax) + filtra_materias_copia_sessao_ajax, verifica_materia_sessao_plenaria_ajax, + recuperar_tramitacao) from .apps import AppConfig @@ -68,6 +69,7 @@ urlpatterns = [ name='remove_parlamentar_composicao'), url(r'^sessao/recuperar-materia/', recuperar_materia), + url(r'^sessao/recuperar-tramitacao/', recuperar_tramitacao), url(r'^sessao/recuperar-numero-sessao/', recuperar_numero_sessao_view, name='recuperar_numero_sessao_view' diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index 94e5419a0..932ec0f90 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1,4 +1,4 @@ - +import json from collections import OrderedDict from datetime import datetime from re import sub @@ -754,7 +754,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): class BaseMixin(MasterDetailCrud.BaseMixin): list_field_names = ['numero_ordem', 'materia', - ('materia__ementa', '', 'observacao'), + ('materia__ementa', '', 'tramitacao', 'observacao'), 'resultado'] class CreateView(MasterDetailCrud.CreateView): @@ -790,6 +790,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): context["tipo_materia_salvo"] = self.object.materia.tipo.id context["numero_materia_salvo"] = self.object.materia.numero context["ano_materia_salvo"] = self.object.materia.ano + context["tramitacao_salvo"] = None if not self.object.tramitacao else self.object.tramitacao.id return context @@ -800,6 +801,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): initial['numero_materia'] = self.object.materia.numero initial['ano_materia'] = self.object.materia.ano initial['numero_ordem'] = self.object.numero_ordem + initial['tramitacao'] = None if not self.object.tramitacao else self.object.tramitacao.id return initial @@ -839,6 +841,23 @@ def recuperar_materia(request): return response +def recuperar_tramitacao(request): + tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo_materia']) + numero = request.GET['numero_materia'] + ano = request.GET['ano_materia'] + + try: + materia = MateriaLegislativa.objects.get(tipo=tipo, + ano=ano, + numero=numero) + tramitacao = {} + for obj in materia.tramitacao_set.all(): + tramitacao[obj.id] = obj.status.descricao + response = JsonResponse(tramitacao) + except ObjectDoesNotExist: + response = JsonResponse({'id': 0}) + + return response class ExpedienteMateriaCrud(MasterDetailCrud): model = ExpedienteMateria @@ -904,6 +923,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud): context["tipo_materia_salvo"] = self.object.materia.tipo.id context["numero_materia_salvo"] = self.object.materia.numero context["ano_materia_salvo"] = self.object.materia.ano + context["tramitacao_salvo"] = self.object.tramitacao.id if self.object.tramitacao is not None else '' return context @@ -914,6 +934,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud): initial['numero_materia'] = self.object.materia.numero initial['ano_materia'] = self.object.materia.ano initial['numero_ordem'] = self.object.numero_ordem + initial['tramitacao'] = self.object.tramitacao.id if self.object.tramitacao is not None else '' return initial @@ -3757,8 +3778,8 @@ class PautaSessaoDetailView(DetailView): data_sessao = sessao_plenaria.data_inicio.strftime("%Y-%m-%d ") data_hora_sessao = datetime.strptime(data_sessao + sessao_plenaria.hora_inicio, "%Y-%m-%d %H:%M") data_hora_sessao_utc = pytz.timezone(TIME_ZONE).localize(data_hora_sessao).astimezone(pytz.utc) - ultima_tramitacao = m.materia.tramitacao_set.filter(timestamp__lt = data_hora_sessao_utc).order_by( - '-data_tramitacao', '-id').first() + ultima_tramitacao = m.materia.tramitacao_set.filter(timestamp__lt=data_hora_sessao_utc).order_by( + '-data_tramitacao', '-id').first() if m.tramitacao is None else m.tramitacao numeracao = m.materia.numeracao_set.first() materias_expediente.append({ @@ -3813,7 +3834,7 @@ class PautaSessaoDetailView(DetailView): data_hora_sessao = datetime.strptime(data_sessao + sessao_plenaria.hora_inicio, "%Y-%m-%d %H:%M") data_hora_sessao_utc = pytz.timezone(TIME_ZONE).localize(data_hora_sessao).astimezone(pytz.utc) ultima_tramitacao = o.materia.tramitacao_set.filter(timestamp__lt=data_hora_sessao_utc).order_by( - '-data_tramitacao', '-id').first() + '-data_tramitacao', '-id').first() if o.tramitacao is None else o.tramitacao numeracao = o.materia.numeracao_set.first() materias_ordem.append({ diff --git a/sapl/templates/sessao/expedientemateria_form.html b/sapl/templates/sessao/expedientemateria_form.html index 424679dd5..ee992fda3 100644 --- a/sapl/templates/sessao/expedientemateria_form.html +++ b/sapl/templates/sessao/expedientemateria_form.html @@ -54,11 +54,40 @@ } } + function recuperar_tramitacao() { + let tipo_materia = $("#id_tipo_materia").val() + let numero_materia = $("#id_numero_materia").val() + let ano_materia = $("#id_ano_materia").val() + let tramitacao_salvo = "{{ tramitacao_salvo }}" + + if (tipo_materia && numero_materia && ano_materia) { + $.get("/sessao/recuperar-tramitacao", + { tipo_materia: tipo_materia, numero_materia: numero_materia, ano_materia: ano_materia }, + function(data, status) { + if (status == 'success') { + $('#id_tramitacao_select').find('option').remove() + $('#id_tramitacao_select').append(''); + for (const property in data) { + console.log(tramitacao_salvo + "===" + property) + $('#id_tramitacao_select').append(''); + if (property == tramitacao_salvo) { + $("#id_tramitacao_select option[value='"+ property +"']").attr("selected", "selected"); + } + } + } + }); + } + } + var fields = ["#id_tipo_materia", "#id_numero_materia", "#id_ano_materia"]; for (i = 0; i < fields.length; i++){ - $(fields[i]).change(recuperar_materia) + $(fields[i]).change(function() { + recuperar_materia(); + recuperar_tramitacao(); + }); } - recuperar_materia() + recuperar_materia(); + recuperar_tramitacao(); var modal_estilos = 'display: block; width: 85%; max-width: 600px; background: #fff; padding: 15px; border-radius: 5px;' +'-webkit-box-shadow: 0px 6px 14px -2px rgba(0, 0, 0, 0.75); -moz-box-shadow: 0px 6px 14px -2px rgba(0, 0, 0, 0.75);' diff --git a/sapl/templates/sessao/layouts.yaml b/sapl/templates/sessao/layouts.yaml index 814319878..78517b708 100644 --- a/sapl/templates/sessao/layouts.yaml +++ b/sapl/templates/sessao/layouts.yaml @@ -60,6 +60,7 @@ ExpedienteMateria: - tipo_materia numero_materia ano_materia - tipo_votacao - apenas_leitura + - tramitacao_select - observacao OrdemDia: @@ -68,6 +69,7 @@ OrdemDia: - tipo_materia numero_materia ano_materia - tipo_votacao - apenas_leitura + - tramitacao_select - observacao ExpedienteMateriaDetail: @@ -75,6 +77,7 @@ ExpedienteMateriaDetail: - materia - ementa - tipo_votacao + - tramitacao - observacao OrdemDiaDetail: @@ -82,6 +85,7 @@ OrdemDiaDetail: - materia - ementa - tipo_votacao + - tramitacao - observacao Bancada: