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/migrations/0064_auto_20220713_2335.py b/sapl/sessao/migrations/0064_auto_20220713_2335.py
new file mode 100644
index 000000000..0c0c34866
--- /dev/null
+++ b/sapl/sessao/migrations/0064_auto_20220713_2335.py
@@ -0,0 +1,25 @@
+# Generated by Django 2.2.28 on 2022-07-14 02:35
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('materia', '0081_auto_20220321_0934'),
+ ('sessao', '0063_merge_20220609_0838'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='expedientemateria',
+ name='tramitacao',
+ field=models.ForeignKey(blank=True, default='', null=True, on_delete=django.db.models.deletion.PROTECT, to='materia.Tramitacao', verbose_name='Situação Atual'),
+ ),
+ migrations.AddField(
+ model_name='ordemdia',
+ name='tramitacao',
+ field=models.ForeignKey(blank=True, default='', null=True, on_delete=django.db.models.deletion.PROTECT, to='materia.Tramitacao', verbose_name='Situação Atual'),
+ ),
+ ]
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..94824b248 100755
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -1,12 +1,8 @@
-
from collections import OrderedDict
from datetime import datetime
-from re import sub
-
-import pytz
-
-from sapl.settings import TIME_ZONE
+import json
import logging
+from re import sub
from django.conf import settings
from django.contrib import messages
@@ -28,6 +24,7 @@ from django.views.generic.base import RedirectView
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from django_filters.views import FilterView
+import pytz
from sapl.base.models import AppConfig as AppsAppConfig
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
@@ -41,6 +38,7 @@ from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato,
Parlamentar, SessaoLegislativa)
from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm, OrdemExpedienteLeituraForm
+from sapl.settings import TIME_ZONE
from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip
from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm,
@@ -754,7 +752,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 +788,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 +799,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
@@ -840,6 +840,33 @@ def recuperar_materia(request):
return response
+def recuperar_tramitacao(request):
+ tipo = request.GET['tipo_materia']
+ numero = request.GET['numero_materia']
+ ano = request.GET['ano_materia']
+
+ try:
+ materia = MateriaLegislativa.objects.get(tipo_id=tipo,
+ ano=ano,
+ numero=numero)
+ tramitacao = {}
+ for obj in materia.tramitacao_set.all():
+ tramitacao[obj.id] = {
+ 'status': obj.status.descricao,
+ 'texto': obj.texto,
+ 'data_tramitacao': obj.data_tramitacao.strftime('%d/%m/%Y'),
+ 'unidade_tramitacao_local': str(obj.unidade_tramitacao_local),
+ 'unidade_tramitacao_destino': str(obj.unidade_tramitacao_destino)
+
+ }
+
+ response = JsonResponse(tramitacao)
+ except ObjectDoesNotExist:
+ response = JsonResponse({'id': 0})
+
+ return response
+
+
class ExpedienteMateriaCrud(MasterDetailCrud):
model = ExpedienteMateria
parent_field = 'sessao_plenaria'
@@ -904,6 +931,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 +942,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
@@ -2081,15 +2110,17 @@ def get_assinaturas(sessao_plenaria):
return context
+
def get_assinaturas_presidente(sessao_plenaria):
mesa_dia = get_mesa_diretora(sessao_plenaria)['mesa']
- presidente_dia = [m['parlamentar'] for m in mesa_dia if m['cargo'].descricao == 'Presidente']
- presidente_dia = presidente_dia[0] if presidente_dia else ''
+ presidente_dia = [m['parlamentar']
+ for m in mesa_dia if m['cargo'].descricao == 'Presidente']
+ presidente_dia = presidente_dia[0] if presidente_dia else ''
context = {}
assinatura_presidente = [
- {'parlamentar': presidente_dia, 'cargo': "Presidente"}]
+ {'parlamentar': presidente_dia, 'cargo': "Presidente"}]
context.update({'assinatura_mesa': assinatura_presidente})
return context
@@ -3703,7 +3734,8 @@ class PautaSessaoView(TemplateView):
template_name = "sessao/pauta_inexistente.html"
def get(self, request, *args, **kwargs):
- sessao = SessaoPlenaria.objects.filter(publicar_pauta = True).order_by("-data_inicio").first()
+ sessao = SessaoPlenaria.objects.filter(
+ publicar_pauta=True).order_by("-data_inicio").first()
if not sessao:
return self.render_to_response({})
@@ -3755,10 +3787,12 @@ class PautaSessaoDetailView(DetailView):
sessao_plenaria = SessaoPlenaria.objects.get(id=self.object.id)
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()
+ 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() if m.tramitacao is None else m.tramitacao
numeracao = m.materia.numeracao_set.first()
materias_expediente.append({
@@ -3810,10 +3844,12 @@ class PautaSessaoDetailView(DetailView):
sessao_plenaria = SessaoPlenaria.objects.get(id=self.object.id)
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)
+ 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({
@@ -3919,7 +3955,7 @@ class PesquisarPautaSessaoView(PesquisarSessaoPlenariaView):
def get_filterset_kwargs(self, filterset_class):
kwargs = super().get_filterset_kwargs(filterset_class)
qs = kwargs.get('queryset')
- qs = qs.filter(publicar_pauta = True)
+ qs = qs.filter(publicar_pauta=True)
kwargs['queryset'] = qs
return kwargs
@@ -3948,14 +3984,14 @@ def verifica_materia_sessao_plenaria_ajax(request):
sessao_plenaria=pk_sessao_plenaria, materia=id_materia_selecionada
).exists()
is_materia_presente_any_sessao = ExpedienteMateria.objects.filter(
- materia=id_materia_selecionada
+ materia=id_materia_selecionada
).exists()
elif tipo_materia_sessao == MATERIAS_ORDEMDIA:
is_materia_presente = OrdemDia.objects.filter(
sessao_plenaria=pk_sessao_plenaria, materia=id_materia_selecionada
).exists()
is_materia_presente_any_sessao = OrdemDia.objects.filter(
- materia=id_materia_selecionada
+ materia=id_materia_selecionada
).exists()
return JsonResponse({'is_materia_presente': is_materia_presente, 'is_materia_presente_any_sessao': is_materia_presente_any_sessao})
diff --git a/sapl/templates/sessao/expedientemateria_form.html b/sapl/templates/sessao/expedientemateria_form.html
index 424679dd5..c11517dd2 100644
--- a/sapl/templates/sessao/expedientemateria_form.html
+++ b/sapl/templates/sessao/expedientemateria_form.html
@@ -17,7 +17,7 @@
{ tipo_materia: tipo_materia, numero_materia: numero_materia, ano_materia: ano_materia },
function(data, status) {
if ($(".ementa-materia").length === 0){
- $("#div_id_tipo_materia").closest('.row').after($('