diff --git a/docker-compose.yml b/docker-compose.yml index 5c5341afc..2b9a24183 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.57 + image: interlegis/sapl:3.1.58 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 1181650ee..cdc6d25c8 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -466,7 +466,46 @@ class RelatorioHistoricoTramitacaoFilterSet(django_filters.FilterSet): self.form.helper = FormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( - Fieldset(_('Histórico de Tramita'), + Fieldset(_('Histórico de Tramitação'), + row1, row2, + form_actions(label='Pesquisar')) + ) + +class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet): + + filter_overrides = {models.DateField: { + 'filter_class': django_filters.DateFromToRangeFilter, + 'extra': lambda f: { + 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), + 'widget': RangeWidgetOverride} + }} + + @property + def qs(self): + parent = super(RelatorioDataFimPrazoTramitacaoFilterSet, self).qs + return parent.distinct().order_by('-ano', 'tipo', 'numero') + + class Meta: + model = MateriaLegislativa + fields = ['tipo', 'tramitacao__unidade_tramitacao_local', + 'tramitacao__status', 'tramitacao__data_fim_prazo'] + + def __init__(self, *args, **kwargs): + super(RelatorioDataFimPrazoTramitacaoFilterSet, self).__init__( + *args, **kwargs) + + self.filters['tipo'].label = 'Tipo de Matéria' + + row1 = to_row([('tramitacao__data_fim_prazo', 12)]) + row2 = to_row( + [('tipo', 4), + ('tramitacao__unidade_tramitacao_local', 4), + ('tramitacao__status', 4)]) + + self.form.helper = FormHelper() + self.form.helper.form_method = 'GET' + self.form.helper.layout = Layout( + Fieldset(_('Tramitações por fim de prazo'), row1, row2, form_actions(label='Pesquisar')) ) diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 143a89ba8..3b7d76e40 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -16,7 +16,8 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, RelatorioMateriasPorAnoAutorTipoView, RelatorioMateriasPorAutorView, RelatorioMateriasTramitacaoView, - RelatorioPresencaSessaoView, SaplSearchView) + RelatorioPresencaSessaoView, SaplSearchView, + RelatorioDataFimPrazoTramitacaoView) app_name = AppConfig.name @@ -83,6 +84,9 @@ urlpatterns = [ url(r'^sistema/relatorios/historico-tramitacoes$', RelatorioHistoricoTramitacaoView.as_view(), name='historico_tramitacoes'), + url(r'^sistema/relatorios/data-fim-prazo-tramitacoes$', + RelatorioDataFimPrazoTramitacaoView.as_view(), + name='data_fim_prazo_tramitacoes'), url(r'^sistema/relatorios/presenca$', RelatorioPresencaSessaoView.as_view(), name='presenca_sessao'), diff --git a/sapl/base/views.py b/sapl/base/views.py index f31ed1c58..386364420 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -33,7 +33,8 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioMateriasPorAutorFilterSet, RelatorioMateriasTramitacaoilterSet, - RelatorioPresencaSessaoFilterSet) + RelatorioPresencaSessaoFilterSet, + RelatorioDataFimPrazoTramitacaoFilterSet) from .models import AppConfig, CasaLegislativa @@ -357,6 +358,22 @@ class RelatorioHistoricoTramitacaoView(FilterView): return context +class RelatorioDataFimPrazoTramitacaoView(FilterView): + model = MateriaLegislativa + filterset_class = RelatorioDataFimPrazoTramitacaoFilterSet + template_name = 'base/RelatorioDataFimPrazoTramitacao_filter.html' + + def get_context_data(self, **kwargs): + context = super(RelatorioDataFimPrazoTramitacaoView, + self).get_context_data(**kwargs) + context['title'] = _('Fim de Prazo de Tramitações') + qr = self.request.GET.copy() + context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' + + context['show_results'] = show_results_filter_set(qr) + + return context + class RelatorioMateriasTramitacaoView(FilterView): model = MateriaLegislativa diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 2ce7dcfaa..33be2003d 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -3,9 +3,10 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import transaction from django.db.models import Q +from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ from sapl.base.models import Autor, TipoAutor -from sapl.comissoes.models import Comissao, Composicao, Participacao +from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao from sapl.parlamentares.models import Legislatura, Mandato, Parlamentar @@ -69,7 +70,8 @@ class ParticipacaoCreateForm(forms.ModelForm): composicao = Composicao.objects.get(id=self.initial['parent_pk']) participantes = composicao.participacao_set.all() participantes_id = [p.parlamentar.id for p in participantes] - parlamentares = Parlamentar.objects.all().exclude(id__in=participantes_id).order_by('nome_completo') + parlamentares = Parlamentar.objects.all().exclude( + id__in=participantes_id).order_by('nome_completo') parlamentares = [p for p in parlamentares if p.ativo] lista = [] @@ -142,3 +144,30 @@ class ComissaoForm(forms.ModelForm): nome=nome ) return comissao + + +class ReuniaoForm(ModelForm): + + comissao = forms.ModelChoiceField(queryset=Comissao.objects.all(), + widget=forms.HiddenInput()) + + class Meta: + model = Reuniao + exclude = ['cod_andamento_reuniao'] + widgets = { + 'hora_fim': forms.TimeInput(format='%H:%M'), + 'hora_inicio': forms.TimeInput(format='%H:%M'), + } + + def clean(self): + super(ReuniaoForm, self).clean() + + if self.errors: + return + + if self.cleaned_data['hora_fim'] < self.cleaned_data['hora_inicio']: + msg = _('A hora de término da reunião não pode ' + 'ser menor que a de início') + raise ValidationError(msg) + + return self.cleaned_data diff --git a/sapl/comissoes/legacy.yaml b/sapl/comissoes/legacy.yaml index a1093c4d2..2414df885 100644 --- a/sapl/comissoes/legacy.yaml +++ b/sapl/comissoes/legacy.yaml @@ -43,3 +43,21 @@ Participacao (ComposicaoComissao): observacao: obs_composicao parlamentar: cod_parlamentar titular: ind_titular + +Reuniao: + periodo: periodo_reuniao + comissao: cod_comissao + tipo: tipo_comissao + numero: num_comissao + nome: nom_reuniao + tema: tem_reuniao + data: dat_reuniao + hora_inicio: hora_inicio_reuniao + hora_fim: hora_fim_reuniao + local_reuniao: local + observacao: obs_reuniao + ulr_audio: audio_reuniao + url_video: video_reuniao + upload_pauta: pauta_reuniao + upload_ata: ata_reuniao + upload_anexo: anexo_reuniao diff --git a/sapl/comissoes/migrations/0003_reuniao.py b/sapl/comissoes/migrations/0003_reuniao.py new file mode 100644 index 000000000..acdf8bf76 --- /dev/null +++ b/sapl/comissoes/migrations/0003_reuniao.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2017-11-23 13:07 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import sapl.comissoes.models +import sapl.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0002_auto_20170809_1236'), + ] + + operations = [ + migrations.CreateModel( + name='Reuniao', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('numero', models.PositiveIntegerField(verbose_name='Número')), + ('nome', models.CharField(max_length=100, verbose_name='Nome da Reunião')), + ('tema', models.CharField(max_length=100, verbose_name='Tema da Reunião')), + ('data', models.DateField(verbose_name='Data')), + ('hora_inicio', models.CharField(max_length=5, verbose_name='Horário (hh:mm)')), + ('hora_fim', models.CharField(max_length=5, verbose_name='Horário (hh:mm)')), + ('local_reuniao', models.CharField(blank=True, max_length=100, verbose_name='Local Reunião')), + ('observacao', models.CharField(blank=True, max_length=150, verbose_name='Observação')), + ('url_audio', models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)')), + ('url_video', models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)')), + ('upload_pauta', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.pauta_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Pauta da Reunião')), + ('upload_ata', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.ata_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Ata da Reunião')), + ('upload_anexo', models.FileField(blank=True, null=True, upload_to=sapl.comissoes.models.anexo_upload_path, verbose_name='Anexo da Reunião')), + ('comissao', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.Comissao', verbose_name='Comissão')), + ('periodo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.Periodo', verbose_name='Periodo da Composicão da Comissão')), + ('tipo', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.TipoComissao', verbose_name='Tipo')), + ], + options={ + 'verbose_name': 'Reunião de Comissão', + 'verbose_name_plural': 'Reuniões de Comissão', + }, + ), + ] diff --git a/sapl/comissoes/migrations/0005_merge.py b/sapl/comissoes/migrations/0005_merge.py new file mode 100644 index 000000000..f171eb151 --- /dev/null +++ b/sapl/comissoes/migrations/0005_merge.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-26 10:41 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0004_auto_20180102_1652'), + ('comissoes', '0003_reuniao'), + ] + + operations = [ + ] diff --git a/sapl/comissoes/migrations/0006_auto_20180227_0842.py b/sapl/comissoes/migrations/0006_auto_20180227_0842.py new file mode 100644 index 000000000..ebe3e0029 --- /dev/null +++ b/sapl/comissoes/migrations/0006_auto_20180227_0842.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-27 11:42 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0005_merge'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='url_audio', + field=models.URLField(blank=True, max_length=150, null=True, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_video', + field=models.URLField(blank=True, max_length=150, null=True, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)'), + ), + ] diff --git a/sapl/comissoes/migrations/0007_auto_20180227_1025.py b/sapl/comissoes/migrations/0007_auto_20180227_1025.py new file mode 100644 index 000000000..fb13ba123 --- /dev/null +++ b/sapl/comissoes/migrations/0007_auto_20180227_1025.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-27 13:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0006_auto_20180227_0842'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='hora_fim', + field=models.CharField(max_length=5, verbose_name='Horário de Término (hh:mm)'), + ), + migrations.AlterField( + model_name='reuniao', + name='hora_inicio', + field=models.CharField(max_length=5, verbose_name='Horário de Início (hh:mm)'), + ), + ] diff --git a/sapl/comissoes/migrations/0008_auto_20180227_1111.py b/sapl/comissoes/migrations/0008_auto_20180227_1111.py new file mode 100644 index 000000000..478576a1b --- /dev/null +++ b/sapl/comissoes/migrations/0008_auto_20180227_1111.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-02-27 14:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0007_auto_20180227_1025'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='url_audio', + field=models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Áudio (Formatos MP3 / AAC)'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_video', + field=models.URLField(blank=True, max_length=150, verbose_name='URL Arquivo Vídeo (Formatos MP4 / FLV / WebM)'), + ), + ] diff --git a/sapl/comissoes/migrations/0009_auto_20180301_1011.py b/sapl/comissoes/migrations/0009_auto_20180301_1011.py new file mode 100644 index 000000000..db559de75 --- /dev/null +++ b/sapl/comissoes/migrations/0009_auto_20180301_1011.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-01 13:11 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0008_auto_20180227_1111'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='local_reuniao', + field=models.CharField(blank=True, max_length=100, verbose_name='Local da Reunião'), + ), + migrations.AlterField( + model_name='reuniao', + name='observacao', + field=models.TextField(blank=True, max_length=150, verbose_name='Observação'), + ), + migrations.AlterField( + model_name='reuniao', + name='tipo', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='comissoes.TipoComissao', verbose_name='Tipo de Comissão'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_audio', + field=models.URLField(blank=True, max_length=150, verbose_name='URL do Arquivo de Áudio (Formatos MP3 / AAC)'), + ), + migrations.AlterField( + model_name='reuniao', + name='url_video', + field=models.URLField(blank=True, max_length=150, verbose_name='URL do Arquivo de Vídeo (Formatos MP4 / FLV / WebM)'), + ), + ] diff --git a/sapl/comissoes/migrations/0010_auto_20180306_0918.py b/sapl/comissoes/migrations/0010_auto_20180306_0918.py new file mode 100644 index 000000000..b2dd48f87 --- /dev/null +++ b/sapl/comissoes/migrations/0010_auto_20180306_0918.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-03-06 12:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comissoes', '0009_auto_20180301_1011'), + ] + + operations = [ + migrations.AlterField( + model_name='reuniao', + name='hora_fim', + field=models.TimeField(verbose_name='Horário de Término (hh:mm)'), + ), + migrations.AlterField( + model_name='reuniao', + name='hora_inicio', + field=models.TimeField(verbose_name='Horário de Início (hh:mm)'), + ), + ] diff --git a/sapl/comissoes/models.py b/sapl/comissoes/models.py index 078097cab..882fe8638 100644 --- a/sapl/comissoes/models.py +++ b/sapl/comissoes/models.py @@ -1,11 +1,12 @@ - -import reversion from django.db import models from django.utils.translation import ugettext_lazy as _ from model_utils import Choices +import reversion + from sapl.base.models import Autor from sapl.parlamentares.models import Parlamentar -from sapl.utils import YES_NO_CHOICES, SaplGenericRelation +from sapl.utils import (YES_NO_CHOICES, SaplGenericRelation, + restringe_tipos_de_arquivo_txt, texto_upload_path) @reversion.register() @@ -52,22 +53,18 @@ class Comissao(models.Model): secretario = models.CharField( max_length=30, blank=True, verbose_name=_('Secretário')) telefone_reuniao = models.CharField( - max_length=15, - blank=True, + max_length=15, blank=True, verbose_name=_('Tel. Sala Reunião')) endereco_secretaria = models.CharField( - max_length=100, - blank=True, + max_length=100, blank=True, verbose_name=_('Endereço Secretaria')) telefone_secretaria = models.CharField( - max_length=15, - blank=True, + max_length=15, blank=True, verbose_name=_('Tel. Secretaria')) fax_secretaria = models.CharField( max_length=15, blank=True, verbose_name=_('Fax Secretaria')) agenda_reuniao = models.CharField( - max_length=100, - blank=True, + max_length=100, blank=True, verbose_name=_('Data/Hora Reunião')) local_reuniao = models.CharField( max_length=100, blank=True, verbose_name=_('Local Reunião')) @@ -83,7 +80,6 @@ class Comissao(models.Model): default=False, choices=YES_NO_CHOICES, verbose_name=_('Comissão Ativa?')) - autor = SaplGenericRelation(Autor, related_query_name='comissao_set', fields_search=( @@ -170,8 +166,7 @@ class Participacao(models.Model): # ComposicaoComissao null=True, verbose_name=_('Data Desligamento')) motivo_desligamento = models.CharField( - max_length=150, - blank=True, + max_length=150, blank=True, verbose_name=_('Motivo Desligamento')) observacao = models.CharField( max_length=150, blank=True, verbose_name=_('Observação')) @@ -182,3 +177,113 @@ class Participacao(models.Model): # ComposicaoComissao def __str__(self): return '%s : %s' % (self.cargo, self.parlamentar) + + +def get_comissao_media_path(instance, subpath, filename): + return './sapl/comissao/%s/%s/%s' % (instance.numero, subpath, filename) + + +def pauta_upload_path(instance, filename): + return texto_upload_path(instance, filename, subpath='pauta', pk_first=True) + + +def ata_upload_path(instance, filename): + return texto_upload_path(instance, filename, subpath='ata', pk_first=True) + + +def anexo_upload_path(instance, filename): + return texto_upload_path(instance, filename, subpath='anexo', pk_first=True) + + +class Reuniao(models.Model): + periodo = models. ForeignKey( + Periodo, + on_delete=models.PROTECT, + verbose_name=_('Periodo da Composicão da Comissão')) + comissao = models.ForeignKey( + Comissao, + on_delete=models.PROTECT, + verbose_name=_('Comissão')) + tipo = models.ForeignKey( + TipoComissao, + on_delete=models.PROTECT, + verbose_name=_('Tipo de Comissão')) + numero = models.PositiveIntegerField(verbose_name=_('Número')) + nome = models.CharField( + max_length=100, verbose_name=_('Nome da Reunião')) + tema = models.CharField( + max_length=100, verbose_name=_('Tema da Reunião')) + data = models.DateField(verbose_name=_('Data')) + hora_inicio = models.TimeField( + verbose_name=_('Horário de Início (hh:mm)')) + hora_fim = models.TimeField( + verbose_name=_('Horário de Término (hh:mm)')) + local_reuniao = models.CharField( + max_length=100, blank=True, verbose_name=_('Local da Reunião')) + observacao = models.TextField( + max_length=150, blank=True, verbose_name=_('Observação')) + url_audio = models.URLField( + max_length=150, blank=True, + verbose_name=_('URL do Arquivo de Áudio (Formatos MP3 / AAC)')) + url_video = models.URLField( + max_length=150, blank=True, + verbose_name=_('URL do Arquivo de Vídeo (Formatos MP4 / FLV / WebM)')) + upload_pauta = models.FileField( + blank=True, null=True, + upload_to=pauta_upload_path, + verbose_name=_('Pauta da Reunião'), + validators=[restringe_tipos_de_arquivo_txt]) + upload_ata = models.FileField( + blank=True, null=True, + upload_to=ata_upload_path, + verbose_name=_('Ata da Reunião'), + validators=[restringe_tipos_de_arquivo_txt]) + upload_anexo = models.FileField( + blank=True, null=True, + upload_to=anexo_upload_path, + verbose_name=_('Anexo da Reunião')) + + class Meta: + verbose_name = _('Reunião de Comissão') + verbose_name_plural = _('Reuniões de Comissão') + + def __str__(self): + return self.nome + + def delete(self, using=None, keep_parents=False): + if self.upload_pauta: + self.upload_pauta.delete() + + if self.upload_ata: + self.upload_ata.delete() + + if self.upload_anexo: + self.upload_anexo.delete() + + return models.Model.delete( + self, using=using, keep_parents=keep_parents) + + def save(self, force_insert=False, force_update=False, using=None, + update_fields=None): + + if not self.pk and (self.upload_pauta or self.upload_ata or + self.upload_anexo): + upload_pauta = self.upload_pauta + upload_ata = self.upload_ata + upload_anexo = self.upload_anexo + self.upload_pauta = None + self.upload_ata = None + self.upload_anexo = None + models.Model.save(self, force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) + + self.upload_pauta = upload_pauta + self.upload_ata = upload_ata + self.upload_anexo = upload_anexo + + return models.Model.save(self, force_insert=force_insert, + force_update=force_update, + using=using, + update_fields=update_fields) diff --git a/sapl/comissoes/urls.py b/sapl/comissoes/urls.py index 128cb7647..47fb0b059 100644 --- a/sapl/comissoes/urls.py +++ b/sapl/comissoes/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import include, url from sapl.comissoes.views import (CargoCrud, ComissaoCrud, ComposicaoCrud, MateriasTramitacaoListView, ParticipacaoCrud, - PeriodoComposicaoCrud, TipoComissaoCrud) + PeriodoComposicaoCrud, ReuniaoCrud, TipoComissaoCrud) from .apps import AppConfig @@ -10,6 +10,7 @@ app_name = AppConfig.name urlpatterns = [ url(r'^comissao/', include(ComissaoCrud.get_urls() + ComposicaoCrud.get_urls() + + ReuniaoCrud.get_urls() + ParticipacaoCrud.get_urls())), url(r'^comissao/(?P\d+)/materias-em-tramitacao$', diff --git a/sapl/comissoes/views.py b/sapl/comissoes/views.py index eb32b977a..0fd5a2c13 100644 --- a/sapl/comissoes/views.py +++ b/sapl/comissoes/views.py @@ -3,13 +3,23 @@ from django.core.urlresolvers import reverse from django.db.models import F from django.views.decorators.clickjacking import xframe_options_exempt from django.views.generic import ListView +from django.views.generic.base import RedirectView +from django.views.generic.detail import DetailView +from django.views.generic.edit import FormMixin + + +from sapl.base.models import AppConfig as AppsAppConfig +from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, + CrudAux, MasterDetailCrud, + PermissionRequiredForAppCrudMixin) from sapl.comissoes.forms import ParticipacaoCreateForm, ParticipacaoEditForm -from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud from sapl.materia.models import MateriaLegislativa, Tramitacao -from .forms import ComissaoForm +from .forms import ReuniaoForm, ComissaoForm + from .models import (CargoComissao, Comissao, Composicao, Participacao, - Periodo, TipoComissao) + Periodo, TipoComissao, Reuniao) +from sapl.comissoes.apps import AppConfig def pegar_url_composicao(pk): @@ -136,3 +146,44 @@ class MateriasTramitacaoListView(ListView): MateriasTramitacaoListView, self).get_context_data(**kwargs) context['object'] = Comissao.objects.get(id=self.kwargs['pk']) return context + +class ReuniaoCrud(MasterDetailCrud): + model = Reuniao + parent_field = 'comissao' + public = [RP_LIST, RP_DETAIL, ] + + class BaseMixin(MasterDetailCrud.BaseMixin): + list_field_names = ['nome', 'tema', 'comissao'] + + @property + def list_url(self): + return '' + + class ListView(MasterDetailCrud.ListView): + paginate_by = 10 + + class UpdateView(MasterDetailCrud.UpdateView): + form_class = ReuniaoForm + + def get_initial(self): + return {'comissao': self.object.comissao} + + + class CreateView(MasterDetailCrud.CreateView): + form_class = ReuniaoForm + + def get_initial(self): + comissao = Comissao.objects.get(id=self.kwargs['pk']) + + return {'comissao': comissao} + + + class DeleteView(MasterDetailCrud.DeleteView): + pass + + + class DetailView(MasterDetailCrud.DetailView): + + @xframe_options_exempt + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) diff --git a/sapl/crispy_layout_mixin.py b/sapl/crispy_layout_mixin.py index e582ba6c1..0adc1c679 100644 --- a/sapl/crispy_layout_mixin.py +++ b/sapl/crispy_layout_mixin.py @@ -96,7 +96,7 @@ def get_field_display(obj, fieldname): if value is None: display = '' - elif 'date' in str_type_from_value: + elif '.date' in str_type_from_value: display = formats.date_format(value, "SHORT_DATE_FORMAT") elif 'bool' in str_type_from_value: display = _('Sim') if value else _('Não') diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index a8a2baaa1..1eebd5c7d 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1263,7 +1263,6 @@ class ProposicaoForm(forms.ModelForm): not cd['texto_original'] and \ inst.texto_original: inst.texto_original.delete() - self.gerar_hash(inst, receber_recibo) return super().save(commit) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 19b9dedf3..bdc1ef4a3 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -289,9 +289,11 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, if numeracao == 'A': numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim numero = Protocolo.objects.filter( @@ -425,9 +427,11 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): if numeracao == 'A': numero = Protocolo.objects.filter( - ano=timezone.now().year).aggregate(Max('numero')) + ano=timezone.now().year, tipo=tipo).aggregate(Max('numero')) elif numeracao == 'L': - legislatura = Legislatura.objects.first() + legislatura = Legislatura.objects.filter( + data_inicio__year__lte=timezone.now().year, + data_fim__year__gte=timezone.now().year).first() data_inicio = legislatura.data_inicio data_fim = legislatura.data_fim numero = Protocolo.objects.filter( diff --git a/sapl/redireciona_urls/views.py b/sapl/redireciona_urls/views.py index 41d58db33..4f1480a13 100644 --- a/sapl/redireciona_urls/views.py +++ b/sapl/redireciona_urls/views.py @@ -31,6 +31,7 @@ parlamentar_mesa_diretora = (app_parlamentares + ':mesa_diretora') comissao_list = (app_comissoes + ':comissao_list') comissao_detail = (app_comissoes + ':comissao_detail') +reuniao_detail = (app_comissoes + ':reuniao_detail') materialegislativa_detail = (app_materia + ':materialegislativa_detail') materialegislativa_list = (app_materia + ':pesquisar_materia') @@ -633,3 +634,51 @@ class RedirecionaMateriasPorAnoAutorTipo(RedirectView): url = has_iframe(url, self.request) return url + +class RedirecionaReuniao(RedirectView): + permanent = True + + def get_redirect_url(self): + pk_reuniao = self.request.GET.get( + 'cod_comissao', + EMPTY_STRING) + url = EMPTY_STRING + if pk_reuniao: + kwargs = {'pk': pk_reuniao} + try: + url = reverse(reuniao_detail, kwargs=kwargs) + except NoReverseMatch: + raise UnknownUrlNameError(reuniao_detail) + + else: + try: + url = reverse(reuniao_list) + except NoReverseMatch: + raise UnknownUrlNameError(reuniao_list) + + year = self.request.GET.get( + 'ano_reuniao', + EMPTY_STRING) + month = self.request.GET.get( + 'mes_reuniao', + EMPTY_STRING) + day = self.request.GET.get( + 'dia_reuniao', + EMPTY_STRING) + tipo_reuniao = self.request.GET.get( + 'tip_reuniao', + EMPTY_STRING) + + # Remove zeros à esquerda + day = day.lstrip("0") + month = month.lstrip("0") + args = EMPTY_STRING + args += "?data_inicio__year=%s" % (year) + args += "&data_inicio__month=%s" % (month) + args += "&data_inicio__day=%s" % (day) + args += "&tipo=%s&salvar=Pesquisar" % (tipo_reuniao) + url = "%s%s" % (url, args) + + url = has_iframe(url, self.request) + + return url diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 415c7beca..65d6c0be2 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -89,6 +89,7 @@ rules_group_comissoes = { (comissoes.Composicao, __base__), (comissoes.Participacao, __base__), (materia.Relatoria, __base__), + (comissoes.Reuniao, __base__), ] } diff --git a/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html b/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html new file mode 100644 index 000000000..1fccf1268 --- /dev/null +++ b/sapl/templates/base/RelatorioDataFimPrazoTramitacao_filter.html @@ -0,0 +1,34 @@ +{% extends "crud/list.html" %} +{% load i18n %} +{% load crispy_forms_tags %} + +{% block base_content %} + {% if not show_results %} + {% crispy filter.form %} + {% endif %} + + {% if show_results %} +
+ {% trans 'Fazer nova pesquisa' %} +
+



+ + + + + + + + + {% for materia in object_list %} + + + + + {% endfor %} + +
MatériaEmenta
+ {{materia.tipo.descricao}} - {{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} + {{materia.ementa}}
+ {% endif %} +{% endblock base_content %} \ No newline at end of file diff --git a/sapl/templates/base/relatorios_list.html b/sapl/templates/base/relatorios_list.html index c7e47bd69..1bd0f5eda 100644 --- a/sapl/templates/base/relatorios_list.html +++ b/sapl/templates/base/relatorios_list.html @@ -36,6 +36,10 @@ Histórico de tramitações Histórico de tramitações por período e local informados. + + Tramitações por fim de prazo + Tramitações com fim de prazo no intervalo informado. +