Repository: interlegis/sapl

Issue:
Dispensa do interstício
<!--- Forneça um resumo geral da _issue_ no título acima -->
Poder fazer o Segundo Turno de votação da matéria na mesma sessão plenária
## Comportamento Esperado
<!--- Se você está descrevendo um _bug_, conte-nos o que deveria acontecer. -->
<!--- Se você está sugerindo uma mudança/melhoria, conte-nos como deve funcionar. -->
Após o primeiro turno de votação da matéria, o operador poderá inserir a matéria novamente na sessão para votação em segundo turno, se a dispensa do interstício for requerida pelos vereadores. O sistema armazena o resultado das duas votações.
## Comportamento Atual
<!--- Se está descrevendo um bug, conte-nos o que acontece em vez do comportamento esperado. -->
<!--- Se está sugerindo uma mudança/melhoria, explique a diferença com o comportamento atual. -->
O sistema registra somente uma votação da matéria por sessão, caso seja dispensado o interstício, o operador deve apagar a votação da matéria votada em primeiro turno e inseri-la para votação novamente, o que não é bom pois a primeira votação é excluída em definitivo.
## Possível Solução
<!--- Não é obrigatório, mas sugira uma possível correção/razão para o bug -->
<!--- ou ideias de como implementar a adição/mudança. -->
O sistema permitir que a matéria seja votada em dois turnos na mesma sessão plenária.
## Passos para Reproduzir (para bugs)
<!--- Forneça um link para um exemplo, ou um conjunto de passos inequívocos -->
<!--- para reproduzir esse bug. Inclua código para reproduzir, se relevante. -->
1.
2.
3.
4.

## Contexto
<!--- Como esse problema o afeta? O que você está tentando realizar? -->
<!--- Fornecer o contexto nos ajuda a encontrar uma solução que seja mais útil no mundo real -->
Há matérias que são tramitadas em regime de urgência, como por exemplo a destinação de verbas para saúde/combate ao covid-19. Então às vezes os vereadores dispensam o interstício e votam a matéria em dois turnos na mesma sessão. O problema é que o sistema não armazena a votação dos dois turnos na mesma sessão.
## Imagens do Ocorrido
<!--- Representação visual em vídeo ou imagem do ocorrido -->
<!--- Se está descrevendo um bug poste imagens ou vídeos na reprodução do bug citado, caso se aplique -->

## Seu Ambiente
<!--- Inclua detalhes relevantes sobre o ambiente em que você presenciou/experienciou o bug. -->
* Versão usada (_Release_): Release: 3.1.160-RC12
* Nome e versão do navegador: Google Chrome Version 83.0.4103.61 (64-bit)
* Nome e versão do Sistema Operacional (desktop ou mobile): Tablet Android 4.4
* Link para o seu projeto (Caso de fork deste projeto): http://sapl.cmsjp.pr.gov.br/



Discussion:

Resolving patch:
diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py
--- a/sapl/sessao/forms.py
+++ b/sapl/sessao/forms.py
@@ -349,14 +349,6 @@ def clean(self):
         else:
             cleaned_data['materia'] = materia
 
-        exists = self._model.objects.filter(
-            sessao_plenaria=sessao,
-            materia=materia).exists()
-
-        if exists and not self.instance.pk:
-            msg = _('Essa matéria já foi cadastrada.')
-            raise ValidationError(msg)
-
         return cleaned_data
 
     def save(self, commit=False):
diff --git a/sapl/sessao/urls.py b/sapl/sessao/urls.py
--- a/sapl/sessao/urls.py
+++ b/sapl/sessao/urls.py
@@ -36,7 +36,8 @@
                                OrdemDiaLeituraView,
                                retirar_leitura,
                                TransferenciaMateriasExpediente, TransferenciaMateriasOrdemDia,
-                               filtra_materias_copia_sessao_ajax)
+                               filtra_materias_copia_sessao_ajax, verifica_materia_sessao_plenaria_ajax)
+
 
 from .apps import AppConfig
 
@@ -80,6 +81,9 @@
     url(r'^sessao/filtra-materias-copia-sessao-ajax/',
         filtra_materias_copia_sessao_ajax, 
         name='filtra_materias_copia_sessao_ajax_view'),    
+    url(r'^sessao/verifica-materia-sessao-plenaria-ajax/',
+        verifica_materia_sessao_plenaria_ajax,
+        name='verifica_materia_sessao_plenaria_ajax_view'),
 
     url(r'^sessao/(?P<pk>\d+)/(?P<spk>\d+)/abrir-votacao$',
         abrir_votacao,
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -736,6 +736,11 @@ class BaseMixin(MasterDetailCrud.BaseMixin):
     class CreateView(MasterDetailCrud.CreateView):
         form_class = OrdemDiaForm
 
+        def get_context_data(self, **kwargs):
+            context = super().get_context_data(**kwargs)
+            context["tipo_materia_sessao"] = MATERIAS_ORDEMDIA
+            return context
+
         def get_initial(self):
             self.initial['data_ordem'] = SessaoPlenaria.objects.get(
                 pk=self.kwargs['pk']).data_inicio.strftime('%d/%m/%Y')
@@ -753,6 +758,17 @@ def get_success_url(self):
     class UpdateView(MasterDetailCrud.UpdateView):
         form_class = OrdemDiaForm
 
+        def get_context_data(self, **kwargs):
+            context = super().get_context_data(**kwargs)
+
+            context["tipo_materia_sessao"] = MATERIAS_ORDEMDIA
+
+            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
+
+            return context
+
         def get_initial(self):
             initial = super().get_initial()
 
@@ -833,6 +849,11 @@ def get_context_data(self, **kwargs):
     class CreateView(MasterDetailCrud.CreateView):
         form_class = ExpedienteMateriaForm
 
+        def get_context_data(self, **kwargs):
+            context = super().get_context_data(**kwargs)
+            context["tipo_materia_sessao"] = MATERIAS_EXPEDIENTE
+            return context
+
         def get_initial(self):
             initial = super().get_initial()
             initial['data_ordem'] = SessaoPlenaria.objects.get(
@@ -851,6 +872,17 @@ def get_success_url(self):
     class UpdateView(MasterDetailCrud.UpdateView):
         form_class = ExpedienteMateriaForm
 
+        def get_context_data(self, **kwargs):
+            context = super().get_context_data(**kwargs)
+
+            context["tipo_materia_sessao"] = MATERIAS_EXPEDIENTE
+
+            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
+
+            return context
+
         def get_initial(self):
             initial = super().get_initial()
 
@@ -3719,11 +3751,31 @@ def retira_materias_ja_adicionadas(id_sessao, model):
     return lista_id_materias
 
 
+def verifica_materia_sessao_plenaria_ajax(request):
+    # Define se a matéria é do expediente ou da ordem do dia
+    tipo_materia_sessao = int(request.GET['tipo_materia_sessao'])
+
+    id_materia_selecionada = request.GET['id_materia_selecionada']
+    pk_sessao_plenaria = request.GET['pk_sessao_plenaria']
+
+    if tipo_materia_sessao == MATERIAS_EXPEDIENTE:
+        is_materia_presente = ExpedienteMateria.objects.filter(
+            sessao_plenaria=pk_sessao_plenaria, 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()
+
+    return JsonResponse({ 'is_materia_presente': is_materia_presente })
+
+
 class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
                                         MateriaLegislativaPesquisaView):
     filterset_class = AdicionarVariasMateriasFilterSet
     template_name = 'sessao/adicionar_varias_materias_expediente.html'
     app_label = AppConfig.label
+    tipo_materia_sessao = MATERIAS_EXPEDIENTE
 
     logger = logging.getLogger(__name__)
 
@@ -3764,6 +3816,8 @@ def get_context_data(self, **kwargs):
         context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
         context['pk_sessao'] = self.kwargs['pk']
 
+        context["tipo_materia_sessao"] = self.tipo_materia_sessao
+
         return context
 
     def post(self, request, *args, **kwargs):
@@ -3815,6 +3869,7 @@ def post(self, request, *args, **kwargs):
 class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
     filterset_class = AdicionarVariasMateriasFilterSet
     template_name = 'sessao/adicionar_varias_materias_ordem.html'
+    tipo_materia_sessao = MATERIAS_ORDEMDIA
 
     logger = logging.getLogger(__name__)
 


Test patch: