mirror of https://github.com/interlegis/sapl.git
committed by
GitHub
22 changed files with 1026 additions and 878 deletions
@ -0,0 +1,89 @@ |
|||||
|
@import "~bootstrap/scss/variables"; |
||||
|
|
||||
|
// Estilização do tab-content conectado ao nav-tabs (substitui inline style) |
||||
|
.nav-tabs + .tab-content { |
||||
|
border: 1px solid $nav-tabs-border-color; |
||||
|
border-top: 0; |
||||
|
border-radius: 0 0 $border-radius $border-radius; |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 992px) { |
||||
|
.nav-tabs { |
||||
|
position: relative; |
||||
|
flex-direction: column; |
||||
|
border: 1px solid $nav-tabs-border-color; |
||||
|
border-radius: $border-radius; // Totalmente arredondado — parece um botão/select |
||||
|
background-color: $white; |
||||
|
overflow: hidden; // Recorta filhos nas bordas arredondadas |
||||
|
|
||||
|
// Seta indicando dropdown |
||||
|
&::after { |
||||
|
content: "▾"; |
||||
|
position: absolute; |
||||
|
right: 0.75rem; |
||||
|
top: 0.6rem; |
||||
|
font-size: 1rem; |
||||
|
color: $secondary; |
||||
|
pointer-events: none; |
||||
|
transition: transform 0.2s ease; |
||||
|
} |
||||
|
|
||||
|
// Oculta todos os itens por padrão |
||||
|
.nav-item { |
||||
|
display: none; |
||||
|
width: 100%; |
||||
|
|
||||
|
.nav-link { |
||||
|
border: none; |
||||
|
border-bottom: 1px solid $nav-tabs-border-color; |
||||
|
border-radius: 0; |
||||
|
width: 100%; |
||||
|
text-align: left; |
||||
|
padding-right: 2rem; |
||||
|
margin-bottom: 0; |
||||
|
|
||||
|
&.active { |
||||
|
background-color: $nav-tabs-link-active-bg; |
||||
|
color: $nav-tabs-link-active-color; |
||||
|
border-color: transparent; |
||||
|
} |
||||
|
|
||||
|
&:hover:not(.active) { |
||||
|
background-color: $light; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&:last-child .nav-link { |
||||
|
border-bottom: none; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// CSS nativo: exibe somente o item ativo (browsers com suporte a :has) |
||||
|
.nav-item:has(.nav-link.active) { |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
// Estado expandido: via :focus-within (nativo) ou .nav-tabs--open (fallback JS) |
||||
|
&:focus-within, |
||||
|
&.nav-tabs--open { |
||||
|
border-radius: $border-radius $border-radius 0 0; // Arredonda apenas topo quando aberto |
||||
|
overflow: visible; |
||||
|
z-index: $zindex-dropdown; |
||||
|
|
||||
|
&::after { |
||||
|
transform: rotate(180deg); |
||||
|
} |
||||
|
|
||||
|
.nav-item { |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Em mobile, tab-content é visualmente independente do nav-tabs (que vira um select) |
||||
|
.nav-tabs + .tab-content { |
||||
|
border-top: 1px solid $nav-tabs-border-color; |
||||
|
border-radius: $border-radius; // Rounding completo — desconectado do nav-tabs |
||||
|
margin-top: 0.5rem; |
||||
|
} |
||||
|
} |
||||
@ -1,2 +1,3 @@ |
|||||
@import "./bootstrap/nav_navbar"; |
@import "./bootstrap/nav_navbar"; |
||||
|
@import "./bootstrap/nav_tabs"; |
||||
@import "./bootstrap/table"; |
@import "./bootstrap/table"; |
||||
|
|||||
@ -0,0 +1,34 @@ |
|||||
|
# Generated by Django 2.2.28 on 2026-04-13 01:48 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
from datetime import date |
||||
|
|
||||
|
def add_legislatura_to_mesa_diretora(apps, schema_editor): |
||||
|
schema_editor.execute(""" |
||||
|
UPDATE parlamentares_mesadiretora md |
||||
|
SET |
||||
|
legislatura_id = sl.legislatura_id, |
||||
|
data_inicio = sl.data_inicio, |
||||
|
data_fim = sl.data_fim |
||||
|
FROM |
||||
|
parlamentares_sessaolegislativa sl |
||||
|
WHERE |
||||
|
sl.id = md.sessao_legislativa_id |
||||
|
""") |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0045_auto_20251201_1531'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='mesadiretora', |
||||
|
name='legislatura', |
||||
|
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Legislatura', verbose_name='Legislatura'), |
||||
|
), |
||||
|
migrations.RunPython(add_legislatura_to_mesa_diretora), |
||||
|
] |
||||
@ -0,0 +1,23 @@ |
|||||
|
# Generated by Django 2.2.28 on 2026-04-13 01:56 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0046_mesadiretora_legislatura'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='mesadiretora', |
||||
|
name='legislatura', |
||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Legislatura', verbose_name='Legislatura'), |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name='mesadiretora', |
||||
|
name='sessao_legislativa', |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,42 @@ |
|||||
|
# Generated by Django 2.2.28 on 2026-04-13 13:49 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
def preencher_titulo_mesa_diretora(apps, schema_editor): |
||||
|
schema_editor.execute(""" |
||||
|
UPDATE parlamentares_mesadiretora |
||||
|
SET titulo = 'Mesa Diretora' || |
||||
|
CASE WHEN EXTRACT(YEAR FROM data_fim)::integer - EXTRACT(YEAR FROM data_inicio)::integer = 1 |
||||
|
THEN ' Biênio' |
||||
|
ELSE '' |
||||
|
END || ' ' || |
||||
|
EXTRACT(YEAR FROM data_inicio)::integer::text || '/' || |
||||
|
EXTRACT(YEAR FROM data_fim)::integer::text |
||||
|
WHERE data_inicio IS NOT NULL AND data_fim IS NOT NULL |
||||
|
""") |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0047_auto_20260412_2256'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='mesadiretora', |
||||
|
options={'ordering': ('-legislatura', '-data_inicio'), 'verbose_name': 'Mesa Diretora', 'verbose_name_plural': 'Mesas Diretoras'}, |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='mesadiretora', |
||||
|
name='titulo', |
||||
|
field=models.CharField(default='', max_length=100, verbose_name='Título da Mesa Diretora'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='composicaomesa', |
||||
|
name='mesa_diretora', |
||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='composicaomesa_set', to='parlamentares.MesaDiretora'), |
||||
|
), |
||||
|
migrations.RunPython(preencher_titulo_mesa_diretora), |
||||
|
] |
||||
@ -0,0 +1,39 @@ |
|||||
|
# Generated by Django 2.2.28 on 2026-04-17 22:17 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0048_auto_20260413_1049'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='composicaomesa', |
||||
|
name='cargo', |
||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='parlamentares.CargoMesa', verbose_name='Cargo'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='composicaomesa', |
||||
|
name='mesa_diretora', |
||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='composicaomesa_set', to='parlamentares.MesaDiretora', verbose_name='Mesa Diretora'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='composicaomesa', |
||||
|
name='parlamentar', |
||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='parlamentares.Parlamentar', verbose_name='Parlamentar'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='mesadiretora', |
||||
|
name='data_fim', |
||||
|
field=models.DateField(verbose_name='Data Fim'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='mesadiretora', |
||||
|
name='data_inicio', |
||||
|
field=models.DateField(verbose_name='Data Início'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,19 @@ |
|||||
|
# Generated by Django 2.2.28 on 2026-04-18 01:35 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0049_auto_20260417_1917'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='mesadiretora', |
||||
|
name='legislatura', |
||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='mesadiretora_set', to='parlamentares.Legislatura', verbose_name='Legislatura'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,401 @@ |
|||||
|
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 |
||||
|
|
||||
|
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={}) |
||||
|
|
||||
|
assert not form.is_valid() |
||||
|
|
||||
|
errors = form.errors |
||||
|
|
||||
|
assert errors['titulo'] == [_('Este campo é obrigatório.')] |
||||
|
assert errors['data_inicio'] == [_('Este campo é obrigatório.')] |
||||
|
assert errors['data_fim'] == [_('Este campo é obrigatório.')] |
||||
|
assert errors['legislatura'] == [_('Este campo é obrigatório.')] |
||||
|
|
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_mesadiretora_form_data_inicio_maior_que_data_fim(): |
||||
|
legislatura = baker.make( |
||||
|
'parlamentares.Legislatura', |
||||
|
data_inicio='2021-01-01', |
||||
|
data_fim='2024-12-31' |
||||
|
) |
||||
|
|
||||
|
form = MesaDiretoraForm(data={ |
||||
|
'titulo': 'Mesa Diretora 2021-2022', |
||||
|
'data_inicio': '2022-01-01', |
||||
|
'data_fim': '2021-12-31', |
||||
|
'legislatura': legislatura.id, |
||||
|
}) |
||||
|
|
||||
|
assert not form.is_valid() |
||||
|
errors = form.errors |
||||
|
assert errors['__all__'] == [_('A data de início deve ser anterior à data de fim.')] |
||||
|
|
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_mesadiretora_form_valido(): |
||||
|
legislatura = baker.make( |
||||
|
'parlamentares.Legislatura', |
||||
|
data_inicio='2021-01-01', |
||||
|
data_fim='2024-12-31' |
||||
|
) |
||||
|
|
||||
|
form = MesaDiretoraForm(data={ |
||||
|
'titulo': 'Mesa Diretora 2021-2022', |
||||
|
'data_inicio': '2021-01-01', |
||||
|
'data_fim': '2022-12-31', |
||||
|
'legislatura': legislatura.id, |
||||
|
}) |
||||
|
|
||||
|
assert form.is_valid() |
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_mesadiretora_form_intersecao(): |
||||
|
legislatura = baker.make( |
||||
|
'parlamentares.Legislatura', |
||||
|
data_inicio='2021-01-01', |
||||
|
data_fim='2024-12-31' |
||||
|
) |
||||
|
baker.make( |
||||
|
'parlamentares.MesaDiretora', |
||||
|
legislatura=legislatura, |
||||
|
titulo='Mesa Diretora 2021-2022', |
||||
|
data_inicio='2021-01-01', |
||||
|
data_fim='2022-12-31') |
||||
|
|
||||
|
form = MesaDiretoraForm(data={ |
||||
|
'titulo': 'Mesa Diretora 2022-2023', |
||||
|
'data_inicio': '2022-01-01', |
||||
|
'data_fim': '2023-12-31', |
||||
|
'legislatura': legislatura.id, |
||||
|
}) |
||||
|
|
||||
|
assert not form.is_valid() |
||||
|
errors = form.errors |
||||
|
assert errors['__all__'] == [_('As datas da mesa diretora se sobrepõem com outra mesa diretora existente.')] |
||||
|
|
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_mesadiretora_form_data_fora_da_legislatura(): |
||||
|
legislatura = baker.make( |
||||
|
'parlamentares.Legislatura', |
||||
|
data_inicio='2021-01-01', |
||||
|
data_fim='2024-12-31') |
||||
|
|
||||
|
form = MesaDiretoraForm(data={ |
||||
|
'titulo': 'Mesa Diretora 2020-2021', |
||||
|
'data_inicio': '2020-01-01', |
||||
|
'data_fim': '2021-12-31', |
||||
|
'legislatura': legislatura.id, |
||||
|
}) |
||||
|
|
||||
|
assert not form.is_valid() |
||||
|
errors = form.errors |
||||
|
assert errors['__all__'] == [_('As datas da mesa diretora devem estar dentro do período da legislatura.')] |
||||
|
|
||||
|
|
||||
|
# ===================================================================== |
||||
|
# 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() |
||||
|
|
||||
|
errors = form.errors |
||||
|
|
||||
|
assert errors['parlamentar'] == [_('Este campo é obrigatório.')] |
||||
|
assert errors['cargo'] == [_('Este campo é obrigatório.')] |
||||
|
|
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_composicaomesa_form_valido(): |
||||
|
parlamentar = baker.make('parlamentares.Parlamentar') |
||||
|
cargo = baker.make('parlamentares.CargoMesa') |
||||
|
mesa_diretora = baker.make('parlamentares.MesaDiretora') |
||||
|
mandato = baker.make( |
||||
|
'parlamentares.Mandato', |
||||
|
parlamentar=parlamentar, |
||||
|
legislatura=mesa_diretora.legislatura) |
||||
|
|
||||
|
form = ComposicaoMesaForm(data={ |
||||
|
'parlamentar': parlamentar.id, |
||||
|
'cargo': cargo.id, |
||||
|
}, initial={ |
||||
|
'mesa_diretora': mesa_diretora, |
||||
|
}) |
||||
|
|
||||
|
assert form.is_valid() |
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_composicaomesa_form_parlamentar_ocupando_cargo_na_mesma_mesa(): |
||||
|
parlamentar = baker.make('parlamentares.Parlamentar') |
||||
|
cargo1 = baker.make('parlamentares.CargoMesa') |
||||
|
cargo2 = baker.make('parlamentares.CargoMesa') |
||||
|
mesa_diretora = baker.make('parlamentares.MesaDiretora') |
||||
|
mandato = baker.make( |
||||
|
'parlamentares.Mandato', |
||||
|
parlamentar=parlamentar, |
||||
|
legislatura=mesa_diretora.legislatura) |
||||
|
|
||||
|
ComposicaoMesa.objects.create( |
||||
|
parlamentar=parlamentar, |
||||
|
cargo=cargo1, |
||||
|
mesa_diretora=mesa_diretora |
||||
|
) |
||||
|
|
||||
|
form = ComposicaoMesaForm(data={ |
||||
|
'parlamentar': parlamentar.id, |
||||
|
'cargo': cargo2.id, |
||||
|
}, initial={ |
||||
|
'mesa_diretora': mesa_diretora, |
||||
|
}) |
||||
|
|
||||
|
assert not form.is_valid() |
||||
|
errors = form.errors |
||||
|
assert errors['__all__'] == [_('Parlamentar já ocupa um cargo nesta mesa diretora.')] |
||||
|
|
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_composicaomesa_form_parlamentar_cargo_unico_mesma_mesa(): |
||||
|
parlamentar1 = baker.make('parlamentares.Parlamentar') |
||||
|
parlamentar2 = baker.make('parlamentares.Parlamentar') |
||||
|
|
||||
|
cargo = baker.make('parlamentares.CargoMesa', unico=True) |
||||
|
|
||||
|
mesa_diretora = baker.make('parlamentares.MesaDiretora') |
||||
|
|
||||
|
mandato1 = baker.make('parlamentares.Mandato', parlamentar=parlamentar1, legislatura=mesa_diretora.legislatura) |
||||
|
mandato2 = baker.make('parlamentares.Mandato', parlamentar=parlamentar2, legislatura=mesa_diretora.legislatura) |
||||
|
|
||||
|
ComposicaoMesa.objects.create( |
||||
|
parlamentar=parlamentar1, |
||||
|
cargo=cargo, |
||||
|
mesa_diretora=mesa_diretora |
||||
|
) |
||||
|
|
||||
|
form = ComposicaoMesaForm(data={ |
||||
|
'parlamentar': parlamentar2.id, |
||||
|
'cargo': cargo.id, |
||||
|
}, initial={ |
||||
|
'mesa_diretora': mesa_diretora, |
||||
|
}) |
||||
|
|
||||
|
assert not form.is_valid() |
||||
|
errors = form.errors |
||||
|
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') |
||||
|
cargo = baker.make('parlamentares.CargoMesa') |
||||
|
mesa_diretora = baker.make('parlamentares.MesaDiretora') |
||||
|
mandato = baker.make( |
||||
|
'parlamentares.Mandato', |
||||
|
parlamentar=parlamentar, |
||||
|
legislatura=mesa_diretora.legislatura) |
||||
|
|
||||
|
response = admin_client.post(reverse('sapl.parlamentares:composicaomesa_create', kwargs={'pk': mesa_diretora.id}), data={ |
||||
|
'parlamentar': parlamentar.id, |
||||
|
'cargo': cargo.id, |
||||
|
}) |
||||
|
|
||||
|
assert ComposicaoMesa.objects.filter(parlamentar=parlamentar, cargo=cargo, mesa_diretora=mesa_diretora).exists() |
||||
|
|
||||
|
@pytest.mark.django_db(transaction=False) |
||||
|
def test_composicaomesa_form_view_update(admin_client): |
||||
|
parlamentar = baker.make('parlamentares.Parlamentar') |
||||
|
cargo = baker.make('parlamentares.CargoMesa') |
||||
|
mesa_diretora = baker.make('parlamentares.MesaDiretora') |
||||
|
mandato = baker.make( |
||||
|
'parlamentares.Mandato', |
||||
|
parlamentar=parlamentar, |
||||
|
legislatura=mesa_diretora.legislatura) |
||||
|
|
||||
|
composicao = ComposicaoMesa.objects.create( |
||||
|
parlamentar=parlamentar, |
||||
|
cargo=cargo, |
||||
|
mesa_diretora=mesa_diretora |
||||
|
) |
||||
|
|
||||
|
new_cargo = baker.make('parlamentares.CargoMesa') |
||||
|
|
||||
|
response = admin_client.post(reverse('sapl.parlamentares:composicaomesa_update', kwargs={'pk': composicao.id}), data={ |
||||
|
'parlamentar': parlamentar.id, |
||||
|
'cargo': new_cargo.id, |
||||
|
}) |
||||
|
|
||||
|
composicao.refresh_from_db() |
||||
|
assert composicao.cargo == new_cargo |
||||
@ -1,312 +0,0 @@ |
|||||
{% extends "crud/detail.html" %} |
|
||||
{% load i18n %} |
|
||||
{% block actions %} {% endblock %} |
|
||||
|
|
||||
{% block detail_content %} |
|
||||
{% if sessoes|length == 0 %} |
|
||||
<div class="alert alert-danger alert-dismissible" role="alert"> |
|
||||
<b>{{legislatura_selecionada}}</b> não possui nenhuma Sessão Legislativa cadastrada.<br /> |
|
||||
Clique <a href="{% url 'sapl.parlamentares:sessaolegislativa_create' %}">aqui</a> para cadastrar uma nova. |
|
||||
</div> |
|
||||
|
|
||||
{% else %} |
|
||||
<div class="alert alert-danger alert-dismissible" id="div-error" role="alert" style="display: none"> |
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> |
|
||||
<span aria-hidden="true">×</span> |
|
||||
</button> |
|
||||
<b><span id="error-message"></span></b> |
|
||||
</div> |
|
||||
|
|
||||
<div class="alert alert-success alert-dismissible" id="div-success" style="display: none" role="alert"> |
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> |
|
||||
<span aria-hidden="true">×</span> |
|
||||
</button> |
|
||||
<b><span id="success-message"></span></b> |
|
||||
</div> |
|
||||
|
|
||||
<fieldset class="form-group"> |
|
||||
<legend>Escolha da Legislatura e da Sessão Legislativa</legend> |
|
||||
<div class="row"> |
|
||||
<div class="col-md-6"> |
|
||||
<label>Escolha uma Legislatura</label> |
|
||||
<select name="legislatura" id="id_legislatura" class="form-control"> |
|
||||
{% for l in legislaturas %} |
|
||||
<option value="{{l.id}}" {% if l == legislatura_selecionada %} selected {% endif %}> |
|
||||
{{l}} |
|
||||
</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
</div> |
|
||||
<div class="col-md-6"> |
|
||||
<label>Escolha uma Sessão Legislativa</label> |
|
||||
<select name="sessao" id="id_sessao_legislativa" class="form-control"> |
|
||||
{% for s in sessoes %} |
|
||||
<option value="{{s.id}}" {% if s == sessao_selecionada %} selected {% endif %}> |
|
||||
{{s}} |
|
||||
</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
</div> |
|
||||
</div> |
|
||||
</fieldset> |
|
||||
<br /> |
|
||||
<fieldset class="form-group"> |
|
||||
<legend>Escolha da Composição da Mesa Diretora</legend> |
|
||||
<div class="row"> |
|
||||
<div class="col-md-4"> |
|
||||
<label>Composição da Mesa Diretora</label> |
|
||||
<select multiple size="5" class="form-control" id="id_composicao_mesa" name="composicao_mesa"> |
|
||||
{% for p in composicao_mesa %} |
|
||||
<option value="{{p.id}}"> |
|
||||
{{p.parlamentar}} || {{p.cargo}} |
|
||||
</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
</div> |
|
||||
|
|
||||
<div class="col-md-4" align="center"> |
|
||||
<br /><br /> |
|
||||
{% if perms.parlamentares.add_cargomesa %} |
|
||||
<input type="submit" style="display: none" name="Incluir" id="id_incluir" Value="Incluir" class="btn btn-primary" /> |
|
||||
{% endif %} |
|
||||
<br /> |
|
||||
<br /> |
|
||||
{% if perms.parlamentares.add_composicaomesa %} |
|
||||
<input type="submit" style="display: none" name="Excluir" id="id_excluir" Value="Excluir" class="btn btn-danger" /> |
|
||||
{% endif %} |
|
||||
</div> |
|
||||
|
|
||||
<div class="col-md-4"> |
|
||||
<label id='parlamentar-cargo-title' style="display: none">Parlamentar | Cargo</label> |
|
||||
<select class="form-control" name="parlamentar" id="id_parlamentar" style="display: none"> |
|
||||
{% for p in parlamentares %} |
|
||||
<option value="{{p.id}}">{{p.nome_parlamentar}}</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
<br /> |
|
||||
<select class="form-control" name="cargo" id="id_cargo" style="display: none"> |
|
||||
{% for c in cargos_vagos %} |
|
||||
<option value="{{c.id}}">{{c}}</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
</fieldset> |
|
||||
{% endif %} |
|
||||
{% endblock detail_content %} |
|
||||
|
|
||||
|
|
||||
{% block extra_js %} |
|
||||
|
|
||||
<script language="Javascript"> |
|
||||
|
|
||||
//############################################################## |
|
||||
// Inicialização da View # |
|
||||
//############################################################## |
|
||||
|
|
||||
// Se a composicao estiver completa, deve-se esconder o botão e os |
|
||||
// campos de inserção |
|
||||
$(document).ready(function(){ |
|
||||
if($("#id_parlamentar").val() == null || $("#id_cargo").val() == null){ |
|
||||
$("#id_parlamentar").hide(); |
|
||||
$("#id_cargo").hide(); |
|
||||
$("#parlamentar-cargo-title").hide(); |
|
||||
$('#id_incluir').hide(); |
|
||||
} |
|
||||
else{ |
|
||||
$("#id_parlamentar").show(); |
|
||||
$("#id_cargo").show(); |
|
||||
$("#parlamentar-cargo-title").show(); |
|
||||
$('#id_incluir').show(); |
|
||||
} |
|
||||
|
|
||||
// Se a composição estiver vazia, deve-se esconder |
|
||||
// de Excluir |
|
||||
if (!$("#id_composicao_mesa option").val()){ |
|
||||
$("#id_excluir").hide() |
|
||||
} |
|
||||
else{ |
|
||||
$("#id_excluir").show() |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
//############################################################## |
|
||||
//# EVENT HANDLERS # |
|
||||
//############################################################## |
|
||||
|
|
||||
function errors_handler(msg){ |
|
||||
if (msg == null){ |
|
||||
$("#div-success").hide() |
|
||||
$("#div-error").hide() |
|
||||
$("#success-message").html('') |
|
||||
$("#error-message").html('') |
|
||||
} |
|
||||
else{ |
|
||||
if (msg[1] == 0){ |
|
||||
$("#div-error").show() |
|
||||
$("#error-message").html(msg[0]) |
|
||||
} |
|
||||
else{ |
|
||||
$("#div-success").show() |
|
||||
$("#success-message").html(msg[0]) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
// Atualiza os campos após alguma operação de mudança da Legislatura/Sessao ou |
|
||||
// Inserção/Remoção |
|
||||
function altera_field(id_legislatura, id_sessao=null, msg=null){ |
|
||||
// Pega o novo valor dos campos modificados |
|
||||
var sessao_value = id_sessao |
|
||||
var legislatura_value = id_legislatura |
|
||||
|
|
||||
// Limpa os campos que serão atualizados |
|
||||
$("#id_sessao_legislativa option").remove(); |
|
||||
$("#id_composicao_mesa option").remove(); |
|
||||
$("#id_parlamentar option").remove(); |
|
||||
$("#id_cargo option").remove(); |
|
||||
|
|
||||
|
|
||||
$.get("{% url 'sapl.parlamentares:altera_field_mesa' %}", |
|
||||
{legislatura: legislatura_value, sessao: sessao_value}, |
|
||||
function(data) { |
|
||||
// Caso não venha nenhum dado da requisição, retorna null |
|
||||
if ($.isEmptyObject(data)){ |
|
||||
return null |
|
||||
} |
|
||||
|
|
||||
lista_sessoes = data['lista_sessoes']; |
|
||||
lista_composicao = data['lista_composicao']; |
|
||||
lista_parlamentares = data['lista_parlamentares']; |
|
||||
lista_cargos = data['lista_cargos']; |
|
||||
|
|
||||
// Atualiza a listagem dos campos |
|
||||
if (lista_sessoes != undefined) { |
|
||||
for (i = 0; i < lista_sessoes.length; i++) { |
|
||||
$('#id_sessao_legislativa').append('<option value="' + lista_sessoes[i][0] + '">' + lista_sessoes[i][1] + '</option>'); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (lista_composicao != null) { |
|
||||
for (i = 0; i < lista_composicao.length; i++) { |
|
||||
$('#id_composicao_mesa').append('<option value="' + lista_composicao[i][0] + '">' + lista_composicao[i][1] + ' || ' + lista_composicao[i][2] + '</option>'); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Caso ainda tenha parlamentares/cargos a serem inseridos, preenche a listagem com |
|
||||
// os disponíveis e garante que as ferramentas de inserção estejam disponíveis |
|
||||
if (lista_parlamentares != null && lista_parlamentares.length != 0 && lista_cargos.length != 0){ |
|
||||
$('#id_incluir').show() |
|
||||
$('#id_cargo').show(); |
|
||||
$('#id_parlamentar').show(); |
|
||||
$("#parlamentar-cargo-title").show(); |
|
||||
|
|
||||
for (i = 0; i < lista_parlamentares.length; i++) { |
|
||||
$('#id_parlamentar').append('<option value="' + lista_parlamentares[i][0] + '">' + lista_parlamentares[i][1] + '</option>'); |
|
||||
} |
|
||||
|
|
||||
for (i = 0; i < lista_cargos.length; i++) { |
|
||||
$('#id_cargo').append('<option value="' + lista_cargos[i][0] + '">' + lista_cargos[i][1] + '</option>'); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Caso contrário, esconde do usuário essas opções |
|
||||
else{ |
|
||||
$('#id_incluir').hide(); |
|
||||
$('#id_cargo').hide(); |
|
||||
$('#id_parlamentar').hide(); |
|
||||
$("#parlamentar-cargo-title").hide(); |
|
||||
} |
|
||||
|
|
||||
// Garante que o botão de remoção aparecerá, caso tenha |
|
||||
// algum parlamentar na composição |
|
||||
if (lista_composicao != null && lista_composicao.length != 0){ |
|
||||
$("#id_excluir").show() |
|
||||
} |
|
||||
else{ |
|
||||
$("#id_excluir").hide() |
|
||||
} |
|
||||
|
|
||||
// Garante que a Sessão atual será a selecionada previamente e, no caso em que |
|
||||
// o campo modificado seja o de Legislatura, que a Sessão seja a última daquela |
|
||||
// legislatura |
|
||||
$("#id_sessao_legislativa").val(data['sessao_selecionada']) |
|
||||
|
|
||||
// Caso haja algum erro que venha após a alteração da legislatura/sessao |
|
||||
// Essa mensagem de erro é prioridade |
|
||||
if (data['msg'][1] == 0){ |
|
||||
msg = data['msg'] |
|
||||
} |
|
||||
|
|
||||
errors_handler(msg) |
|
||||
|
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
//############################################################# |
|
||||
//# EVENTS CATCH # |
|
||||
//############################################################# |
|
||||
$("#id_legislatura").change(function(){ |
|
||||
legislatura = $("#id_legislatura").val(); |
|
||||
altera_field(legislatura); |
|
||||
}); |
|
||||
|
|
||||
$("#id_sessao_legislativa").change(function(){ |
|
||||
legislatura = $("#id_legislatura").val(); |
|
||||
sessao = $("#id_sessao_legislativa").val(); |
|
||||
altera_field(legislatura, sessao); |
|
||||
}); |
|
||||
|
|
||||
$('#id_incluir').click(function(){ |
|
||||
$.ajax({ |
|
||||
data: {sessao: $("#id_sessao_legislativa").val(), |
|
||||
parlamentar: $("#id_parlamentar").val(), |
|
||||
cargo: $("#id_cargo").val()}, |
|
||||
type: 'POST', |
|
||||
url: "{% url 'sapl.parlamentares:insere_parlamentar_composicao' %}", |
|
||||
headers: { |
|
||||
'X-CSRFToken': getCookie('csrftoken') |
|
||||
}, |
|
||||
success: function(data){ |
|
||||
var msg = data['msg']; |
|
||||
legislatura = $("#id_legislatura").val(); |
|
||||
sessao = $("#id_sessao_legislativa").val(); |
|
||||
setTimeout(function(data){ |
|
||||
// Atualiza os campos após a inserção |
|
||||
altera_field(legislatura, sessao, msg) |
|
||||
}, 500) |
|
||||
}, |
|
||||
}); |
|
||||
}) |
|
||||
|
|
||||
$('#id_excluir').click(function(){ |
|
||||
// Pega o id do parlamentar que foi selecionado |
|
||||
selecionado = $("#id_composicao_mesa option:selected").val() |
|
||||
|
|
||||
if (selecionado){ |
|
||||
$.ajax({ |
|
||||
data: {composicao_mesa: selecionado}, |
|
||||
type: 'POST', |
|
||||
url: "{% url 'sapl.parlamentares:remove_parlamentar_composicao' %}", |
|
||||
headers: { |
|
||||
'X-CSRFToken': getCookie('csrftoken') |
|
||||
}, |
|
||||
success: function(data){ |
|
||||
var msg = data['msg']; |
|
||||
legislatura = $("#id_legislatura").val(); |
|
||||
sessao = $("#id_sessao_legislativa").val(); |
|
||||
|
|
||||
setTimeout(function(data){ |
|
||||
// Atualiza os campos após a remoção |
|
||||
altera_field(legislatura, sessao, msg) |
|
||||
}, 500) |
|
||||
}, |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
{% endblock %} |
|
||||
@ -0,0 +1,156 @@ |
|||||
|
{% extends "crud/list.html" %} |
||||
|
{% load i18n common_tags crispy_forms_tags cropping %} |
||||
|
|
||||
|
{% block actions_search %} |
||||
|
<div class="actions search flex-grow-1 pr-3"> |
||||
|
{% if filter.form %} |
||||
|
{% crispy filter.form %} |
||||
|
{% endif %} |
||||
|
</div> |
||||
|
{% endblock actions_search %} |
||||
|
|
||||
|
{% block container_table_list %} |
||||
|
{% if perms.parlamentares.add_mesadiretora %} |
||||
|
{{ block.super }} |
||||
|
{% else %} |
||||
|
<div class="row"> |
||||
|
<div class="col-12"> |
||||
|
|
||||
|
<ul class="nav nav-tabs" role="tablist"> |
||||
|
{% for md in object_list %} |
||||
|
{% if request.GET.mesa == md.id|stringformat:"s" or not request.GET.mesa and forloop.first %} |
||||
|
<li class="nav-item" role="presentation"> |
||||
|
<button class="nav-link active" id="tab-mesa-{{ md.id }}-tab" data-toggle="tab" data-target="#tab-mesa-{{ md.id }}" type="button" role="tab" aria-controls="tab-mesa-{{ md.id }}" aria-selected="true">{{ md }}</button> |
||||
|
</li> |
||||
|
{% else %} |
||||
|
<li class="nav-item" role="presentation"> |
||||
|
<button class="nav-link" id="tab-mesa-{{ md.id }}-tab" data-toggle="tab" data-target="#tab-mesa-{{ md.id }}" type="button" role="tab" aria-controls="tab-mesa-{{ md.id }}" aria-selected="false">{{ md }}</button> |
||||
|
</li> |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
<div class="tab-content"> |
||||
|
{% for md in object_list %} |
||||
|
{% if request.GET.mesa == md.id|stringformat:"s" or not request.GET.mesa and forloop.first %} |
||||
|
<div class="lista-parlamentares tab-pane fade show active" id="tab-mesa-{{ md.id }}" role="tabpanel" aria-labelledby="tab-mesa-{{ md.id }}-tab"> |
||||
|
{% else %} |
||||
|
<div class="lista-parlamentares tab-pane fade" id="tab-mesa-{{ md.id }}" role="tabpanel" aria-labelledby="tab-mesa-{{ md.id }}-tab"> |
||||
|
{% endif %} |
||||
|
<i class="text-muted p-2 d-inline-block">(De {{md.data_inicio }} a {{ md.data_fim }})</i> |
||||
|
<a href="{% url 'sapl.parlamentares:mesadiretora_list' %}?mesa={{ md.id }}" class="btn btn-sm btn-link float-right mb-2"> |
||||
|
<i class="fas fa-external-link-alt"></i> |
||||
|
</a> |
||||
|
<table class="table table-striped table-hover table-link-ordering m-0 p-0"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Nome do Parlamentar</th> |
||||
|
<th>Partido</th> |
||||
|
<th>Cargo</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for composicao in md.composicaomesa_set.all %} |
||||
|
<tr> |
||||
|
<td> |
||||
|
<div id="d-flex"> |
||||
|
{% if composicao.parlamentar.fotografia %} |
||||
|
<img class="img-fluid img-thumbnail" src="{% cropped_thumbnail composicao.parlamentar "cropping"%}"> |
||||
|
{% endif %} |
||||
|
<a class="pl-2" href="{% url 'sapl.parlamentares:parlamentar_detail' composicao.parlamentar.pk %}"> |
||||
|
{{composicao.parlamentar.nome_parlamentar}}</a> |
||||
|
</div> |
||||
|
</td> |
||||
|
<td>{{composicao.parlamentar.filiacao_atual}}</td> |
||||
|
<td>{{composicao.cargo}}</td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
|
||||
|
{% endblock container_table_list %} |
||||
|
|
||||
|
{% block extra_js %} |
||||
|
<script> |
||||
|
(function () { |
||||
|
// Suporte nativo a :has() — o CSS cuida de tudo, JS não é necessário |
||||
|
if (typeof CSS !== 'undefined' && CSS.supports && CSS.supports('selector(:has(*))')) return; |
||||
|
|
||||
|
var mq = window.matchMedia('(max-width: 767px)'); |
||||
|
|
||||
|
function collapse(tabs) { |
||||
|
tabs.classList.remove('nav-tabs--open'); |
||||
|
[].forEach.call(tabs.querySelectorAll('.nav-item'), function (item) { |
||||
|
item.style.display = item.querySelector('.nav-link.active') ? 'block' : 'none'; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function expand(tabs) { |
||||
|
[].forEach.call(tabs.querySelectorAll('.nav-item'), function (item) { |
||||
|
item.style.display = 'block'; |
||||
|
}); |
||||
|
tabs.classList.add('nav-tabs--open'); |
||||
|
} |
||||
|
|
||||
|
function init() { |
||||
|
[].forEach.call(document.querySelectorAll('.nav-tabs'), function (tabs) { |
||||
|
if (tabs._dropdownBound) return; |
||||
|
tabs._dropdownBound = true; |
||||
|
|
||||
|
// Expande ao clicar no container (apenas quando fechado) |
||||
|
tabs.addEventListener('click', function () { |
||||
|
if (!mq.matches || tabs.classList.contains('nav-tabs--open')) return; |
||||
|
expand(tabs); |
||||
|
setTimeout(function () { |
||||
|
document.addEventListener('click', function onOutside(ev) { |
||||
|
if (!tabs.contains(ev.target)) { |
||||
|
collapse(tabs); |
||||
|
document.removeEventListener('click', onOutside); |
||||
|
} |
||||
|
}); |
||||
|
}, 0); |
||||
|
}); |
||||
|
|
||||
|
// Colapsa ao selecionar uma aba (apenas quando aberto) |
||||
|
[].forEach.call(tabs.querySelectorAll('.nav-link'), function (link) { |
||||
|
link.addEventListener('click', function () { |
||||
|
if (!tabs.classList.contains('nav-tabs--open')) return; |
||||
|
// Aguarda Bootstrap atualizar a classe .active |
||||
|
setTimeout(function () { collapse(tabs); }, 50); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
// Estado inicial e ao redimensionar |
||||
|
function applyState(matches) { |
||||
|
[].forEach.call(document.querySelectorAll('.nav-tabs'), function (tabs) { |
||||
|
tabs.classList.remove('nav-tabs--open'); |
||||
|
[].forEach.call(tabs.querySelectorAll('.nav-item'), function (item) { |
||||
|
item.style.display = ''; |
||||
|
}); |
||||
|
if (matches) collapse(tabs); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
applyState(mq.matches); |
||||
|
|
||||
|
if (mq.addEventListener) { |
||||
|
mq.addEventListener('change', function (e) { applyState(e.matches); }); |
||||
|
} else { |
||||
|
mq.addListener(function (e) { applyState(e.matches); }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (document.readyState === 'loading') { |
||||
|
document.addEventListener('DOMContentLoaded', init); |
||||
|
} else { |
||||
|
init(); |
||||
|
} |
||||
|
}()); |
||||
|
</script> |
||||
|
{% endblock extra_js %} |
||||
@ -1,146 +0,0 @@ |
|||||
{% extends "crud/detail.html" %} |
|
||||
{% load i18n cropping%} |
|
||||
{% block actions %} {% endblock %} |
|
||||
|
|
||||
{% block detail_content %} |
|
||||
<form method="POST"> |
|
||||
{% csrf_token %} |
|
||||
<fieldset class="form-group"> |
|
||||
<legend>Escolha da Legislatura e da Sessão Legislativa</legend> |
|
||||
<div class="row"> |
|
||||
<div class="col-md-6"> |
|
||||
<label>Escolha uma Legislatura</label> |
|
||||
<select name="legislatura" id="id_legislatura" class="form-control"> |
|
||||
{% for l in legislaturas %} |
|
||||
<option value="{{l.id}}" {% if l == legislatura_selecionada %} selected {% endif %}> |
|
||||
{{l}} |
|
||||
</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
</div> |
|
||||
<div class="col-md-6"> |
|
||||
<label>Escolha uma Sessão Legislativa</label> |
|
||||
<select name="sessao" id="id_sessao_legislativa" class="form-control"> |
|
||||
{% for s in sessoes %} |
|
||||
<option value="{{s.id}}" {% if s == sessao_selecionada %} selected {% endif %}> |
|
||||
{{s}} |
|
||||
</option> |
|
||||
{% endfor %} |
|
||||
</select> |
|
||||
</div> |
|
||||
</div> |
|
||||
</fieldset> |
|
||||
<br /> |
|
||||
<fieldset class="form-group lista-parlamentares"> |
|
||||
<legend>Composição da Mesa Diretora</legend> |
|
||||
<table id="tabela-composicao" class="table table-striped table-hover table-link-ordering"> |
|
||||
<thead> |
|
||||
<tr> |
|
||||
<th></th> |
|
||||
<th>Nome do Parlamentar</th> |
|
||||
<th>Partido</th> |
|
||||
<th>Cargo</th> |
|
||||
</tr> |
|
||||
</thead> |
|
||||
<tbody> |
|
||||
{% for p in composicao_mesa %} |
|
||||
<tr> |
|
||||
{% if p.parlamentar.fotografia %} |
|
||||
<td> |
|
||||
<div id="w-100"> |
|
||||
<img class="img-fluid img-thumbnail" src="{% cropped_thumbnail p.parlamentar "cropping"%}"> |
|
||||
</div> |
|
||||
{% else %} |
|
||||
<td></td> |
|
||||
{% endif %} |
|
||||
<td><a href="{% url 'sapl.parlamentares:parlamentar_detail' p.parlamentar.pk %}">{{p.parlamentar.nome_parlamentar}}</a></td> |
|
||||
<td>{{p.parlamentar.filiacao_atual}}</td> |
|
||||
<td>{{p.cargo}}</td> |
|
||||
</tr> |
|
||||
{% endfor %} |
|
||||
</tbody> |
|
||||
</table> |
|
||||
</fieldset> |
|
||||
</form> |
|
||||
{% endblock detail_content %} |
|
||||
|
|
||||
{% block extra_js %} |
|
||||
|
|
||||
<script language="Javascript"> |
|
||||
|
|
||||
//############################################################## |
|
||||
//# USEFUL FUNCTIONS # |
|
||||
//############################################################## |
|
||||
function retorna_imagem(url){ |
|
||||
if (url != null){ |
|
||||
image_component = '<img class="img-fluid img-thumbnail" src="' + url + '">' |
|
||||
return image_component |
|
||||
} |
|
||||
|
|
||||
else{ |
|
||||
return '' |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//############################################################## |
|
||||
//# EVENT HANDLERS # |
|
||||
//############################################################## |
|
||||
|
|
||||
function altera_field(id_legislatura, id_sessao=null){ |
|
||||
// Pega o novo valor do campo que foi modificado (Sessao/Legislatura) |
|
||||
var sessao_value = id_sessao |
|
||||
var legislatura_value = id_legislatura |
|
||||
|
|
||||
// Limpa o campo que será atualizado |
|
||||
$("#id_sessao_legislativa option").remove(); |
|
||||
$("#tabela-composicao tbody").empty(); |
|
||||
|
|
||||
$.get("/mesa-diretora/altera-field-mesa-public-view", |
|
||||
{legislatura: legislatura_value, sessao: sessao_value}, |
|
||||
function(data) { |
|
||||
// Caso não venha nenhum dado da requisição, retorna null |
|
||||
if ($.isEmptyObject(data)){ |
|
||||
return null |
|
||||
} |
|
||||
|
|
||||
lista_sessoes = data['lista_sessoes']; |
|
||||
lista_parlamentares = data['lista_parlamentares']; |
|
||||
lista_cargos = data['lista_cargos']; |
|
||||
lista_fotos = data['lista_fotos'] |
|
||||
lista_partidos = data['lista_partidos'] |
|
||||
|
|
||||
// Atualiza a listagem de sessões |
|
||||
for (i = 0; i < lista_sessoes.length; i++) { |
|
||||
$('#id_sessao_legislativa').append('<option value="' + lista_sessoes[i][0] + '">' + lista_sessoes[i][1] + '</option>'); |
|
||||
} |
|
||||
|
|
||||
// Atualiza a tabela de composição |
|
||||
for (i = 0; i < lista_parlamentares.length; i++) { |
|
||||
$("#tabela-composicao tbody").append('<tr> <td> <div class="w-100">' + retorna_imagem(lista_fotos[i]) +' </div> </td> <td><a href="/parlamentar/' + lista_parlamentares[i][0] + '">' + lista_parlamentares[i][1] + '</a></td> <td>' + lista_partidos[i] + '</td> <td>'+ lista_cargos[i][1] + '</td> </tr>'); |
|
||||
} |
|
||||
|
|
||||
// Garante que a Sessão atual será a selecionada previamente e, no caso em que |
|
||||
// o campo modificado seja o de Legislatura, que a Sessão seja a última daquela |
|
||||
// legislatura |
|
||||
$("#id_sessao_legislativa").val(data['sessao_selecionada']) |
|
||||
|
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
//############################################################# |
|
||||
//# EVENTS CATCH # |
|
||||
//############################################################# |
|
||||
$("#id_legislatura").change(function(){ |
|
||||
legislatura = $("#id_legislatura").val(); |
|
||||
altera_field(legislatura); |
|
||||
}); |
|
||||
|
|
||||
$("#id_sessao_legislativa").change(function(){ |
|
||||
legislatura = $("#id_legislatura").val(); |
|
||||
sessao = $("#id_sessao_legislativa").val(); |
|
||||
altera_field(legislatura, sessao); |
|
||||
}); |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
{% endblock %} |
|
||||
@ -0,0 +1,5 @@ |
|||||
|
{% load i18n common_tags %} |
||||
|
- title: {% trans 'Mesa Diretora' %} |
||||
|
url: sapl.parlamentares:mesadiretora_detail |
||||
|
- title: {% trans 'Composição da Mesa' %} |
||||
|
url: sapl.parlamentares:composicaomesa_list |
||||
Loading…
Reference in new issue