diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index e794cb61d..7acb4a984 100755 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -783,38 +783,6 @@ class MesaDiretoraForm(ModelForm): model = MesaDiretora fields = '__all__' - def clean(self): - super(MesaDiretoraForm, self).clean() - - data = self.cleaned_data - - legislatura = data.get('legislatura', None) - if not legislatura: - raise ValidationError(_('Legislatura é obrigatória.')) - - data_inicio = data.get('data_inicio', None) - data_fim = data.get('data_fim', None) - - if not data_inicio or not data_fim: - raise ValidationError(_('As datas de início e fim da mesa diretora são obrigatórias.')) - - if data_inicio >= data_fim: - raise ValidationError(_('A data de início deve ser anterior à data de fim.')) - - # Verifica se as datas da mesa diretora estão dentro do intervalo da legislatura - if data_inicio < legislatura.data_inicio or data_fim > legislatura.data_fim: - raise ValidationError(_('As datas da mesa diretora devem estar dentro do período da legislatura.')) - - # Verifica se há intersecção de datas com outra mesa diretora da mesma legislatura - intersecao_mesadiretora = MesaDiretora.objects.filter( - legislatura=legislatura, - data_inicio__lte=data_fim, - data_fim__gte=data_inicio - ).exclude(pk=self.instance.pk).exists() - if intersecao_mesadiretora: - raise ValidationError(_('As datas da mesa diretora se sobrepõem com outra mesa diretora existente.')) - - return data class ComposicaoMesaForm(ModelForm): @@ -827,33 +795,6 @@ class ComposicaoMesaForm(ModelForm): def __init__(self, *args, **kwargs): super(ComposicaoMesaForm, self).__init__(*args, **kwargs) + self.instance.mesa_diretora = self.initial.get('mesa_diretora') self.fields['parlamentar'].queryset = self.fields['parlamentar'].queryset.filter( mandato__legislatura=self.initial.get('mesa_diretora').legislatura) - - def clean(self): - super(ComposicaoMesaForm, self).clean() - - data = self.cleaned_data - cargo = data.get('cargo', None) - if not cargo: - raise ValidationError(_('Cargo é obrigatório.')) - - # Verifica se Parlamentar já ocupa algum cargo - parlamentar = data.get('parlamentar', None) - if not parlamentar: - raise ValidationError(_('Parlamentar é obrigatório.')) - - if ComposicaoMesa.objects.filter( - mesa_diretora=self.initial.get('mesa_diretora'), - parlamentar=parlamentar, - ).exclude(pk=self.instance.pk).exists(): - raise ValidationError(_('Parlamentar já ocupa um cargo nesta mesa diretora.')) - - if cargo.unico: - composicao_mesa = ComposicaoMesa.objects.filter( - mesa_diretora=self.initial.get('mesa_diretora'), - cargo=cargo - ).exclude(pk=self.instance.pk) - if composicao_mesa.exists(): - raise ValidationError(_('Cargo único já ocupado por outro parlamentar.')) - return data diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py index 1e3266074..0ca2c8356 100644 --- a/sapl/parlamentares/models.py +++ b/sapl/parlamentares/models.py @@ -1,4 +1,5 @@ +from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ @@ -515,6 +516,25 @@ class MesaDiretora(models.Model): 'data_fim': self.data_fim } + def clean(self): + if self.data_inicio and self.data_fim: + if self.data_inicio >= self.data_fim: + raise ValidationError( + _('A data de início deve ser anterior à data de fim.')) + + if self.legislatura_id: + if self.data_inicio < self.legislatura.data_inicio or self.data_fim > self.legislatura.data_fim: + raise ValidationError( + _('As datas da mesa diretora devem estar dentro do período da legislatura.')) + + if MesaDiretora.objects.filter( + legislatura=self.legislatura, + data_inicio__lte=self.data_fim, + data_fim__gte=self.data_inicio + ).exclude(pk=self.pk).exists(): + raise ValidationError( + _('As datas da mesa diretora se sobrepõem com outra mesa diretora existente.')) + class ComposicaoMesa(models.Model): parlamentar = models.ForeignKey(Parlamentar, on_delete=models.PROTECT, verbose_name=_('Parlamentar')) @@ -533,6 +553,24 @@ class ComposicaoMesa(models.Model): 'parlamentar': self.parlamentar, 'cargo': self.cargo } + def clean(self): + if self.parlamentar_id and self.mesa_diretora_id: + if ComposicaoMesa.objects.filter( + mesa_diretora=self.mesa_diretora, + parlamentar=self.parlamentar, + ).exclude(pk=self.pk).exists(): + raise ValidationError( + _('Parlamentar já ocupa um cargo nesta mesa diretora.')) + + if self.cargo_id and self.mesa_diretora_id: + if self.cargo.unico: + if ComposicaoMesa.objects.filter( + mesa_diretora=self.mesa_diretora, + cargo=self.cargo + ).exclude(pk=self.pk).exists(): + raise ValidationError( + _('Cargo único já ocupado por outro parlamentar.')) + class Frente(models.Model): ''' diff --git a/sapl/parlamentares/tests/test_mesadiretora.py b/sapl/parlamentares/tests/test_mesadiretora.py index ff663488d..053cef26c 100644 --- a/sapl/parlamentares/tests/test_mesadiretora.py +++ b/sapl/parlamentares/tests/test_mesadiretora.py @@ -1,4 +1,7 @@ import pytest +from datetime import date + +from django.core.exceptions import ValidationError from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from model_bakery import baker @@ -7,6 +10,159 @@ from sapl.parlamentares.forms import ComposicaoMesaForm, MesaDiretoraForm from sapl.parlamentares.models import ComposicaoMesa, MesaDiretora +# ===================================================================== +# Testes de validação a nível de Model — MesaDiretora +# ===================================================================== + +@pytest.mark.django_db(transaction=False) +def test_mesadiretora_model_clean_data_inicio_maior_que_data_fim(): + legislatura = baker.make( + 'parlamentares.Legislatura', + data_inicio=date(2021, 1, 1), + data_fim=date(2024, 12, 31) + ) + mesa = MesaDiretora( + titulo='Mesa', + data_inicio=date(2022, 1, 1), + data_fim=date(2021, 12, 31), + legislatura=legislatura + ) + with pytest.raises(ValidationError, match='A data de início deve ser anterior à data de fim.'): + mesa.clean() + + +@pytest.mark.django_db(transaction=False) +def test_mesadiretora_model_clean_data_fora_da_legislatura(): + legislatura = baker.make( + 'parlamentares.Legislatura', + data_inicio=date(2021, 1, 1), + data_fim=date(2024, 12, 31) + ) + mesa = MesaDiretora( + titulo='Mesa', + data_inicio=date(2020, 1, 1), + data_fim=date(2021, 12, 31), + legislatura=legislatura + ) + with pytest.raises(ValidationError, match='As datas da mesa diretora devem estar dentro do período da legislatura.'): + mesa.clean() + + +@pytest.mark.django_db(transaction=False) +def test_mesadiretora_model_clean_intersecao(): + legislatura = baker.make( + 'parlamentares.Legislatura', + data_inicio=date(2021, 1, 1), + data_fim=date(2024, 12, 31) + ) + baker.make( + 'parlamentares.MesaDiretora', + legislatura=legislatura, + titulo='Mesa Existente', + data_inicio=date(2021, 1, 1), + data_fim=date(2022, 12, 31) + ) + mesa = MesaDiretora( + titulo='Nova Mesa', + data_inicio=date(2022, 1, 1), + data_fim=date(2023, 12, 31), + legislatura=legislatura + ) + with pytest.raises(ValidationError, match='As datas da mesa diretora se sobrepõem com outra mesa diretora existente.'): + mesa.clean() + + +@pytest.mark.django_db(transaction=False) +def test_mesadiretora_model_clean_valido(): + legislatura = baker.make( + 'parlamentares.Legislatura', + data_inicio=date(2021, 1, 1), + data_fim=date(2024, 12, 31) + ) + mesa = MesaDiretora( + titulo='Mesa', + data_inicio=date(2021, 1, 1), + data_fim=date(2022, 12, 31), + legislatura=legislatura + ) + mesa.clean() # não deve lançar exceção + + +@pytest.mark.django_db(transaction=False) +def test_mesadiretora_model_full_clean_sem_data_inicio(): + legislatura = baker.make( + 'parlamentares.Legislatura', + data_inicio=date(2021, 1, 1), + data_fim=date(2024, 12, 31) + ) + mesa = MesaDiretora( + titulo='Mesa', + data_fim=date(2022, 12, 31), + legislatura=legislatura + ) + with pytest.raises(ValidationError) as exc_info: + mesa.full_clean() + + assert 'data_inicio' in exc_info.value.message_dict + assert exc_info.value.message_dict['data_inicio'] == [_('Este campo não pode ser nulo.')] + + +# ===================================================================== +# Testes de validação a nível de Model — ComposicaoMesa +# ===================================================================== + +@pytest.mark.django_db(transaction=False) +def test_composicaomesa_model_clean_parlamentar_duplicado(): + parlamentar = baker.make('parlamentares.Parlamentar') + cargo1 = baker.make('parlamentares.CargoMesa') + cargo2 = baker.make('parlamentares.CargoMesa') + mesa_diretora = baker.make('parlamentares.MesaDiretora') + + ComposicaoMesa.objects.create( + parlamentar=parlamentar, cargo=cargo1, mesa_diretora=mesa_diretora + ) + + composicao = ComposicaoMesa( + parlamentar=parlamentar, cargo=cargo2, mesa_diretora=mesa_diretora + ) + with pytest.raises(ValidationError, match='Parlamentar já ocupa um cargo nesta mesa diretora.'): + composicao.clean() + + +@pytest.mark.django_db(transaction=False) +def test_composicaomesa_model_clean_cargo_unico(): + parlamentar1 = baker.make('parlamentares.Parlamentar') + parlamentar2 = baker.make('parlamentares.Parlamentar') + cargo = baker.make('parlamentares.CargoMesa', unico=True) + mesa_diretora = baker.make('parlamentares.MesaDiretora') + + ComposicaoMesa.objects.create( + parlamentar=parlamentar1, cargo=cargo, mesa_diretora=mesa_diretora + ) + + composicao = ComposicaoMesa( + parlamentar=parlamentar2, cargo=cargo, mesa_diretora=mesa_diretora + ) + with pytest.raises(ValidationError, match='Cargo único já ocupado por outro parlamentar.'): + composicao.clean() + + +@pytest.mark.django_db(transaction=False) +def test_composicaomesa_model_clean_valido(): + parlamentar = baker.make('parlamentares.Parlamentar') + cargo = baker.make('parlamentares.CargoMesa') + mesa_diretora = baker.make('parlamentares.MesaDiretora') + + composicao = ComposicaoMesa( + parlamentar=parlamentar, cargo=cargo, mesa_diretora=mesa_diretora + ) + composicao.clean() # não deve lançar exceção + + +# ===================================================================== +# Testes de validação via Form — MesaDiretora +# ===================================================================== + def test_mesadiretora_form_invalido(): form = MesaDiretoraForm(data={}) @@ -64,7 +220,7 @@ def test_mesadiretora_form_intersecao(): data_inicio='2021-01-01', data_fim='2024-12-31' ) - mesa_existente = baker.make( + baker.make( 'parlamentares.MesaDiretora', legislatura=legislatura, titulo='Mesa Diretora 2021-2022', @@ -102,8 +258,14 @@ def test_mesadiretora_form_data_fora_da_legislatura(): assert errors['__all__'] == [_('As datas da mesa diretora devem estar dentro do período da legislatura.')] -def test_composicaomesa_form(): - form = ComposicaoMesaForm(data={}) +# ===================================================================== +# Testes de validação via Form — ComposicaoMesa +# ===================================================================== + +@pytest.mark.django_db(transaction=False) +def test_composicaomesa_form_invalido(): + mesa_diretora = baker.make('parlamentares.MesaDiretora') + form = ComposicaoMesaForm(data={}, initial={'mesa_diretora': mesa_diretora}) assert not form.is_valid() @@ -111,8 +273,6 @@ def test_composicaomesa_form(): assert errors['parlamentar'] == [_('Este campo é obrigatório.')] assert errors['cargo'] == [_('Este campo é obrigatório.')] - assert errors['mesa_diretora'] == [_('Este campo é obrigatório.')] - @pytest.mark.django_db(transaction=False) @@ -128,7 +288,6 @@ def test_composicaomesa_form_valido(): form = ComposicaoMesaForm(data={ 'parlamentar': parlamentar.id, 'cargo': cargo.id, - 'mesa_diretora': mesa_diretora.id, }, initial={ 'mesa_diretora': mesa_diretora, }) @@ -146,7 +305,6 @@ def test_composicaomesa_form_parlamentar_ocupando_cargo_na_mesma_mesa(): parlamentar=parlamentar, legislatura=mesa_diretora.legislatura) - # Cria uma composição de mesa existente com o mesmo parlamentar e mesa ComposicaoMesa.objects.create( parlamentar=parlamentar, cargo=cargo1, @@ -156,7 +314,6 @@ def test_composicaomesa_form_parlamentar_ocupando_cargo_na_mesma_mesa(): form = ComposicaoMesaForm(data={ 'parlamentar': parlamentar.id, 'cargo': cargo2.id, - 'mesa_diretora': mesa_diretora.id, }, initial={ 'mesa_diretora': mesa_diretora, }) @@ -178,7 +335,6 @@ def test_composicaomesa_form_parlamentar_cargo_unico_mesma_mesa(): mandato1 = baker.make('parlamentares.Mandato', parlamentar=parlamentar1, legislatura=mesa_diretora.legislatura) mandato2 = baker.make('parlamentares.Mandato', parlamentar=parlamentar2, legislatura=mesa_diretora.legislatura) - # Cria uma composição de mesa existente com o cargo único ComposicaoMesa.objects.create( parlamentar=parlamentar1, cargo=cargo, @@ -188,7 +344,6 @@ def test_composicaomesa_form_parlamentar_cargo_unico_mesma_mesa(): form = ComposicaoMesaForm(data={ 'parlamentar': parlamentar2.id, 'cargo': cargo.id, - 'mesa_diretora': mesa_diretora.id, }, initial={ 'mesa_diretora': mesa_diretora, }) @@ -198,6 +353,10 @@ def test_composicaomesa_form_parlamentar_cargo_unico_mesma_mesa(): assert errors['__all__'] == [_('Cargo único já ocupado por outro parlamentar.')] +# ===================================================================== +# Testes de integração via View — ComposicaoMesa +# ===================================================================== + @pytest.mark.django_db(transaction=False) def test_composicaomesa_form_view_create(admin_client): parlamentar = baker.make('parlamentares.Parlamentar') @@ -211,7 +370,6 @@ def test_composicaomesa_form_view_create(admin_client): response = admin_client.post(reverse('sapl.parlamentares:composicaomesa_create', kwargs={'pk': mesa_diretora.id}), data={ 'parlamentar': parlamentar.id, 'cargo': cargo.id, - 'mesa_diretora': mesa_diretora.id, }) assert ComposicaoMesa.objects.filter(parlamentar=parlamentar, cargo=cargo, mesa_diretora=mesa_diretora).exists() @@ -237,7 +395,6 @@ def test_composicaomesa_form_view_update(admin_client): response = admin_client.post(reverse('sapl.parlamentares:composicaomesa_update', kwargs={'pk': composicao.id}), data={ 'parlamentar': parlamentar.id, 'cargo': new_cargo.id, - 'mesa_diretora': mesa_diretora.id, }) composicao.refresh_from_db()