Repository: interlegis/sapl

Issue:
Em adicionar Audiência pública falta o campo para adicionar o parlamentar responsável e a proposição que a criou
- Incluir um campo que liste o parlamentar autor da audiência.

- Incluir um campo que liste as proposições do autor para linkar a proposição solicitada de autorização e aprovação da audiência. 

ex.: toda audiência precisa ser aprovada em plenário através de um requerimento.


Discussion:
Os campos Tipo de Matéria, Número de Matéria, e Ano de matéria não poderiam ser utilizadas pra indicar o requerimento que deu origem à matéria?
Uma audência é **SEMPRE** aberta via REQUERIMENTO? Não existe outro tipo de documento que seja utilizado para abrir em outras casas legislativas?

Resolving patch:
diff --git a/sapl/audiencia/forms.py b/sapl/audiencia/forms.py
--- a/sapl/audiencia/forms.py
+++ b/sapl/audiencia/forms.py
@@ -10,44 +10,56 @@
 from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica, AnexoAudienciaPublica
 from sapl.crispy_layout_mixin import form_actions, SaplFormHelper, SaplFormLayout, to_row
 from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
+from sapl.parlamentares.models import Parlamentar
 from sapl.utils import timezone, FileFieldCheckMixin, validar_arquivo
 
 class AudienciaForm(FileFieldCheckMixin, forms.ModelForm):
     logger = logging.getLogger(__name__)
     data_atual = timezone.now()
 
-    tipo = forms.ModelChoiceField(required=True,
-                                  label='Tipo de Audiência Pública',
-                                  queryset=TipoAudienciaPublica.objects.all().order_by('nome'))
+    tipo = forms.ModelChoiceField(
+        required=True,
+        label=_('Tipo de Audiência Pública'),
+        queryset=TipoAudienciaPublica.objects.all().order_by('nome'))
 
     tipo_materia = forms.ModelChoiceField(
         label=_('Tipo Matéria'),
         required=False,
         queryset=TipoMateriaLegislativa.objects.all(),
-        empty_label='Selecione',
-    )
+        empty_label=_('Selecione'))
 
     numero_materia = forms.CharField(
-        label='Número Matéria', required=False)
+        label=_('Número Matéria'),
+        required=False)
 
     ano_materia = forms.CharField(
-        label='Ano Matéria',
+        label=_('Ano Matéria'),
         required=False)
 
-    materia = forms.ModelChoiceField(required=False,
-                                     widget=forms.HiddenInput(),
-                                     queryset=MateriaLegislativa.objects.all())
+    materia = forms.ModelChoiceField(
+        required=False,
+        widget=forms.HiddenInput(),
+        queryset=MateriaLegislativa.objects.all())
+
+    parlamentar_autor = forms.ModelChoiceField(
+        label=_("Parlamentar Autor"),
+        required=False,
+        queryset=Parlamentar.objects.all())
+
+    requerimento = forms.ModelChoiceField(
+        label=_("Requerimento"),
+        required=False,
+        queryset=MateriaLegislativa.objects.select_related("tipo").filter(tipo__descricao="Requerimento"))
 
     class Meta:
         model = AudienciaPublica
         fields = ['tipo', 'numero', 'nome',
                   'tema', 'data', 'hora_inicio', 'hora_fim',
-                  'observacao', 'audiencia_cancelada', 'url_audio',
+                  'observacao', 'audiencia_cancelada', 'parlamentar_autor', 'requerimento', 'url_audio',
                   'url_video', 'upload_pauta', 'upload_ata',
                   'upload_anexo', 'tipo_materia', 'numero_materia',
                   'ano_materia', 'materia']
 
-
     def __init__(self, **kwargs):
         super(AudienciaForm, self).__init__(**kwargs)
 
@@ -62,9 +74,7 @@ def __init__(self, **kwargs):
             for t in tipos:
                 t.save()
 
-
     def clean(self):
-                
         cleaned_data = super(AudienciaForm, self).clean()
         if not self.is_valid():
             return cleaned_data
@@ -72,6 +82,8 @@ def clean(self):
         materia = cleaned_data['numero_materia']
         ano_materia = cleaned_data['ano_materia']
         tipo_materia = cleaned_data['tipo_materia']
+        parlamentar_autor = cleaned_data["parlamentar_autor"]
+        requerimento = cleaned_data["requerimento"]
 
         if materia and ano_materia and tipo_materia:
             try:
@@ -107,12 +119,14 @@ def clean(self):
                 cleaned_data['numero'] = 1
 
         if self.cleaned_data['hora_inicio'] and self.cleaned_data['hora_fim']:
-            if (self.cleaned_data['hora_fim'] <
-                self.cleaned_data['hora_inicio']):
-                    msg = _('A hora de fim ({}) não pode ser anterior a hora '
-                    'de início({})'.format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']))
-                    self.logger.error('Hora de fim anterior à hora de início.')
-                    raise ValidationError(msg)
+            if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']:
+                msg = _('A hora de fim ({}) não pode ser anterior a hora de início({})'
+                        .format(self.cleaned_data['hora_fim'], self.cleaned_data['hora_inicio']))
+                self.logger.error('Hora de fim anterior à hora de início.')
+                raise ValidationError(msg)
+
+        if parlamentar_autor.autor.first() not in requerimento.autores.all():
+            raise ValidationError("Parlamentar Autor selecionado não faz parte da autoria do Requerimento selecionado.")
 
         upload_pauta = self.cleaned_data.get('upload_pauta', False)
         upload_ata = self.cleaned_data.get('upload_ata', False)
@@ -120,10 +134,10 @@ def clean(self):
 
         if upload_pauta:
             validar_arquivo(upload_pauta, "Pauta da Audiência Pública")
-        
+
         if upload_ata:
             validar_arquivo(upload_ata, "Ata da Audiência Pública")
-        
+
         if upload_anexo:
             validar_arquivo(upload_anexo, "Anexo da Audiência Pública")
 
diff --git a/sapl/audiencia/migrations/0015_auto_20200518_1158.py b/sapl/audiencia/migrations/0015_auto_20200518_1158.py
new file mode 100644
--- /dev/null
+++ b/sapl/audiencia/migrations/0015_auto_20200518_1158.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.29 on 2020-05-18 14:58
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('parlamentares', '0031_auto_20200407_1406'),
+        ('materia', '0067_auto_20200416_1538'),
+        ('audiencia', '0014_auto_20191023_1538'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='audienciapublica',
+            name='parlamentar_autor',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Parlamentar', verbose_name='Parlamentar Autor'),
+        ),
+        migrations.AddField(
+            model_name='audienciapublica',
+            name='requerimento',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='requerimento', to='materia.MateriaLegislativa', verbose_name='Requerimento da Audiência Pública'),
+        ),
+    ]
diff --git a/sapl/audiencia/models.py b/sapl/audiencia/models.py
--- a/sapl/audiencia/models.py
+++ b/sapl/audiencia/models.py
@@ -80,6 +80,19 @@ class AudienciaPublica(models.Model):
         default=False,
         choices=YES_NO_CHOICES,
         verbose_name=_('Audiência Cancelada?'))
+    parlamentar_autor = models.ForeignKey(
+        Parlamentar,
+        on_delete=models.PROTECT,
+        null=True,
+        blank=True,
+        verbose_name=_('Parlamentar Autor'))
+    requerimento = models.ForeignKey(
+        MateriaLegislativa,
+        null=True,
+        blank=True,
+        on_delete=models.PROTECT,
+        verbose_name=_('Requerimento da Audiência Pública'),
+        related_name=_('requerimento'))
     url_audio = models.URLField(
         max_length=150, blank=True,
         verbose_name=_('URL Arquivo Áudio (Formatos MP3 / AAC)'))


Test patch: