diff --git a/Dockerfile b/Dockerfile
index d1a9ca29f..95782b591 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -40,7 +40,7 @@ COPY config/env_dockerfile /var/interlegis/sapl/sapl/.env
# compilescss - Precompile all occurrences of your SASS/SCSS files for the whole project into css files
-RUN python3 manage.py bower_install -- --allow-root --no-input && \
+RUN python3 manage.py bower_install --allow-root && \
python3 manage.py compilescss
RUN python3 manage.py collectstatic --noinput --clear
diff --git a/requirements/dev-requirements.txt b/requirements/dev-requirements.txt
index 49ded787e..dba8788b2 100644
--- a/requirements/dev-requirements.txt
+++ b/requirements/dev-requirements.txt
@@ -2,7 +2,7 @@
autopep8==1.2.4
beautifulsoup4==4.6.0
-django-debug-toolbar==1.5
+django-debug-toolbar==1.8
ipdb==0.10.1
pdbpp==0.9.2
pip-review==0.4
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 6d9d79d66..f93a0ee00 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -1,24 +1,21 @@
dj-database-url==0.4.1
django-haystack==2.6.0
-django>=1.9,<1.10
-# TODO O django-admin-bootstrapped 2.5.7 não inseriu a mudança que permite
-# a compatibilidade com Django 1.9+. A linha abaixo será mudada quando uma
-# nova versão do django-admin-bootstrapped for lançada
-git+git://github.com/django-admin-bootstrapped/django-admin-bootstrapped.git
+django>=1.10,<1.11
+git+git://github.com/rubgombar1/django-admin-bootstrapped.git
django-bootstrap3==7.0.1
-django-bower==5.1.0
+django-bower==5.2.0
django-braces==1.9.0
django-compressor==2.0
-django-crispy-forms==1.6.0
-django-extensions==1.6.7
-django-extra-views==0.8.0
+django-crispy-forms==1.6.1
+django-extensions==1.9.8
+django-extra-views==0.11.0
django-filter==0.15.3
django-floppyforms==1.6.2
-django-model-utils==2.5
-django-sass-processor==0.5.4
+django-model-utils==3.1.1
+django-sass-processor==0.5.8
djangorestframework==3.4.0
-drfdocs==0.0.11
-easy-thumbnails==2.3
+git+git://github.com/jasperlittle/django-rest-framework-docs
+easy-thumbnails==2.5
django-image-cropping==1.1.0
git+git://github.com/interlegis/trml2pdf.git
libsass==0.11.1
diff --git a/sapl/audiencia/forms.py b/sapl/audiencia/forms.py
old mode 100644
new mode 100755
index 9f55d3e6d..4bd265b72
--- a/sapl/audiencia/forms.py
+++ b/sapl/audiencia/forms.py
@@ -2,7 +2,11 @@ from django import forms
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import transaction
from django.utils.translation import ugettext_lazy as _
-from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
+from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica, AnexoAudienciaPublica
+from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
+
+from crispy_forms.helper import FormHelper
+from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.utils import timezone
@@ -102,3 +106,26 @@ class AudienciaForm(forms.ModelForm):
raise ValidationError(msg)
return cleaned_data
+
+
+class AnexoAudienciaPublicaForm(forms.ModelForm):
+
+ class Meta:
+ model = AnexoAudienciaPublica
+ fields = ['arquivo',
+ 'assunto']
+
+ def __init__(self, *args, **kwargs):
+
+ row1 = to_row(
+ [('arquivo', 4)])
+
+ row2 = to_row(
+ [('assunto', 12)])
+
+ self.helper = FormHelper()
+ self.helper.layout = SaplFormLayout(
+ Fieldset(_('Identificação Básica'),
+ row1, row2))
+ super(AnexoAudienciaPublicaForm, self).__init__(
+ *args, **kwargs)
diff --git a/sapl/audiencia/migrations/0007_anexoaudienciapublica.py b/sapl/audiencia/migrations/0007_anexoaudienciapublica.py
new file mode 100644
index 000000000..b322cc741
--- /dev/null
+++ b/sapl/audiencia/migrations/0007_anexoaudienciapublica.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.13 on 2018-10-17 20:27
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import sapl.utils
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('audiencia', '0006_auto_20180808_0856'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AnexoAudienciaPublica',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('nome', models.CharField(max_length=30, verbose_name='Nome')),
+ ('arquivo', models.FileField(blank=True, null=True, upload_to=sapl.utils.texto_upload_path, verbose_name='Arquivo')),
+ ('data', models.DateField(blank=True, null=True, verbose_name='Data')),
+ ('assunto', models.TextField(blank=True, verbose_name='Assunto')),
+ ('indexacao', models.TextField(blank=True)),
+ ('audiencia', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='audiencia.AudienciaPublica')),
+ ],
+ options={
+ 'verbose_name': 'Documento Acessório',
+ 'verbose_name_plural': 'Documentos Acessórios',
+ },
+ ),
+ ]
diff --git a/sapl/audiencia/migrations/0008_auto_20181023_1051.py b/sapl/audiencia/migrations/0008_auto_20181023_1051.py
new file mode 100644
index 000000000..70c491a4c
--- /dev/null
+++ b/sapl/audiencia/migrations/0008_auto_20181023_1051.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-10-23 13:51
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('audiencia', '0007_anexoaudienciapublica'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='anexoaudienciapublica',
+ options={'verbose_name': 'Anexo de Documento Acessório', 'verbose_name_plural': 'Anexo de Documentos Acessórios'},
+ ),
+ migrations.RemoveField(
+ model_name='anexoaudienciapublica',
+ name='nome',
+ ),
+ migrations.AlterField(
+ model_name='anexoaudienciapublica',
+ name='data',
+ field=models.DateField(auto_now=True, null=True),
+ ),
+ ]
diff --git a/sapl/audiencia/migrations/0009_remove_anexoaudienciapublica_indexacao.py b/sapl/audiencia/migrations/0009_remove_anexoaudienciapublica_indexacao.py
new file mode 100644
index 000000000..e35a7a2a7
--- /dev/null
+++ b/sapl/audiencia/migrations/0009_remove_anexoaudienciapublica_indexacao.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-10-23 13:55
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('audiencia', '0008_auto_20181023_1051'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='anexoaudienciapublica',
+ name='indexacao',
+ ),
+ ]
diff --git a/sapl/audiencia/models.py b/sapl/audiencia/models.py
old mode 100644
new mode 100755
index 477a442d9..684f27625
--- a/sapl/audiencia/models.py
+++ b/sapl/audiencia/models.py
@@ -1,5 +1,6 @@
import reversion
from django.db import models
+from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.materia.models import MateriaLegislativa
@@ -143,6 +144,51 @@ class AudienciaPublica(models.Model):
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)
+
+
+@reversion.register()
+class AnexoAudienciaPublica(models.Model):
+ audiencia = models.ForeignKey(AudienciaPublica,
+ on_delete=models.PROTECT)
+ arquivo = models.FileField(
+ blank=True,
+ null=True,
+ upload_to=texto_upload_path,
+ verbose_name=_('Arquivo'))
+ data = models.DateField(auto_now=timezone.now,blank=True, null=True)
+ assunto = models.TextField(
+ blank=True, verbose_name=_('Assunto'))
+
+ class Meta:
+ verbose_name = _('Anexo de Documento Acessório')
+ verbose_name_plural = _('Anexo de Documentos Acessórios')
+
+ def __str__(self):
+ return self.assunto
+
+ def delete(self, using=None, keep_parents=False):
+ if self.arquivo:
+ self.arquivo.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.arquivo:
+ arquivo = self.arquivo
+ self.arquivo = None
+ models.Model.save(self, force_insert=force_insert,
+ force_update=force_update,
+ using=using,
+ update_fields=update_fields)
+ self.arquivo = arquivo
+
return models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
diff --git a/sapl/audiencia/urls.py b/sapl/audiencia/urls.py
old mode 100644
new mode 100755
index ece3bf1fb..bdf02beca
--- a/sapl/audiencia/urls.py
+++ b/sapl/audiencia/urls.py
@@ -1,10 +1,11 @@
from django.conf.urls import include, url
-from sapl.audiencia.views import (index, AudienciaCrud)
+from sapl.audiencia.views import (index, AudienciaCrud,AnexoAudienciaPublicaCrud)
from .apps import AppConfig
app_name = AppConfig.name
urlpatterns = [
- url(r'^audiencia/', include(AudienciaCrud.get_urls())),
+ url(r'^audiencia/', include(AudienciaCrud.get_urls() +
+ AnexoAudienciaPublicaCrud.get_urls())),
]
\ No newline at end of file
diff --git a/sapl/audiencia/views.py b/sapl/audiencia/views.py
old mode 100644
new mode 100755
index 0a8da8af1..93d214683
--- a/sapl/audiencia/views.py
+++ b/sapl/audiencia/views.py
@@ -1,11 +1,13 @@
+import sapl
+
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import UpdateView
-from sapl.crud.base import RP_DETAIL, RP_LIST, Crud
+from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, MasterDetailCrud
-from .forms import AudienciaForm
-from .models import AudienciaPublica
+from .forms import AudienciaForm, AnexoAudienciaPublicaForm
+from .models import AudienciaPublica, AnexoAudienciaPublica
def index(request):
@@ -18,7 +20,7 @@ class AudienciaCrud(Crud):
class BaseMixin(Crud.BaseMixin):
list_field_names = ['numero', 'nome', 'tipo', 'materia',
- 'data']
+ 'data']
ordering = 'nome', 'numero', 'tipo', 'data'
class ListView(Crud.ListView):
@@ -69,4 +71,40 @@ class AudienciaCrud(Crud):
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
+
+class AudienciaPublicaMixin:
+
+ def has_permission(self):
+ app_config = sapl.base.models.AppConfig.objects.last()
+ if app_config and app_config.documentos_administrativos == 'O':
+ return True
+
+ return super().has_permission()
+
+
+class AnexoAudienciaPublicaCrud(MasterDetailCrud):
+ model = AnexoAudienciaPublica
+ parent_field = 'audiencia'
+ help_topic = 'numeracao_docsacess'
+
+ class BaseMixin(MasterDetailCrud.BaseMixin):
+ list_field_names = ['assunto']
+
+ class CreateView(MasterDetailCrud.CreateView):
+ form_class = AnexoAudienciaPublicaForm
+ layout_key = None
+
+ class UpdateView(MasterDetailCrud.UpdateView):
+ form_class = AnexoAudienciaPublicaForm
+
+ class ListView(AudienciaPublicaMixin, MasterDetailCrud.ListView):
+
+ def get_queryset(self):
+ qs = super(MasterDetailCrud.ListView, self).get_queryset()
+ kwargs = {self.crud.parent_field: self.kwargs['pk']}
+ return qs.filter(**kwargs).order_by('-data', '-id')
+
+ class DetailView(AudienciaPublicaMixin,
+ MasterDetailCrud.DetailView):
+ pass
\ No newline at end of file
diff --git a/sapl/base/tests/teststub_urls.py b/sapl/base/tests/teststub_urls.py
index 9796768f2..8b66d6586 100644
--- a/sapl/base/tests/teststub_urls.py
+++ b/sapl/base/tests/teststub_urls.py
@@ -1,11 +1,9 @@
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from django.views.generic.base import TemplateView
from sapl.urls import urlpatterns as original_patterns
-ptrn = patterns('',
- url(r'^zzzz$',
+ptrn = [url(r'^zzzz$',
TemplateView.as_view(
- template_name='index.html'), name='zzzz'))
-
+ template_name='index.html'), name='zzzz')]
urlpatterns = original_patterns + ptrn
diff --git a/sapl/comissoes/tests/test_comissoes.py b/sapl/comissoes/tests/test_comissoes.py
index 4d12ba810..d2f8b0bd1 100644
--- a/sapl/comissoes/tests/test_comissoes.py
+++ b/sapl/comissoes/tests/test_comissoes.py
@@ -74,6 +74,7 @@ def test_incluir_comissao_submit(admin_client):
'nome': 'Comissão Teste',
'sigla': 'CT',
'data_criacao': '2016-03-22',
+ 'unidade_deliberativa': True,
'salvar': 'salvar'},
follow=True)
assert response.status_code == 200
diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
index b244af69a..80ceff110 100644
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -1180,7 +1180,7 @@ class TipoProposicaoSelect(Select):
str(data_has_perfil),
force_text(option_label))
- def render_options(self, choices, selected_choices):
+ def render_options(self, selected_choices):
# Normalize to strings.
selected_choices = set(force_text(v) for v in selected_choices)
output = []
diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py
index 4d143922f..f8f5d5256 100644
--- a/sapl/rules/map_rules.py
+++ b/sapl/rules/map_rules.py
@@ -66,6 +66,7 @@ rules_group_audiencia = {
'rules': [
(audiencia.AudienciaPublica, __base__),
(audiencia.TipoAudienciaPublica, __base__),
+ (audiencia.AnexoAudienciaPublica, __base__),
]
}
diff --git a/sapl/sessao/forms.py b/sapl/sessao/forms.py
index b691ca968..9d3257333 100644
--- a/sapl/sessao/forms.py
+++ b/sapl/sessao/forms.py
@@ -431,7 +431,7 @@ class VotacaoForm(forms.Form):
class VotacaoNominalForm(forms.Form):
resultado_votacao = forms.ModelChoiceField(label='Resultado da Votação',
- required=True,
+ required=False,
queryset=TipoResultadoVotacao.objects.all())
diff --git a/sapl/sessao/migrations/0027_auto_20181023_1239.py b/sapl/sessao/migrations/0027_auto_20181023_1239.py
new file mode 100644
index 000000000..962ceaf01
--- /dev/null
+++ b/sapl/sessao/migrations/0027_auto_20181023_1239.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.8 on 2018-10-23 15:39
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sessao', '0026_auto_20181016_1944'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='sessaoplenaria',
+ name='finalizada',
+ field=models.NullBooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Sessão finalizada?'),
+ ),
+ migrations.AlterField(
+ model_name='sessaoplenaria',
+ name='iniciada',
+ field=models.NullBooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Sessão iniciada?'),
+ ),
+ ]
diff --git a/sapl/sessao/models.py b/sapl/sessao/models.py
index f1a9365a3..92d4c38b0 100644
--- a/sapl/sessao/models.py
+++ b/sapl/sessao/models.py
@@ -160,10 +160,12 @@ class SessaoPlenaria(models.Model):
verbose_name=_('Anexo da Sessão'))
iniciada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
- verbose_name=_('Sessão iniciada?'))
+ verbose_name=_('Sessão iniciada?'),
+ default=True)
finalizada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
- verbose_name=_('Sessão finalizada?'))
+ verbose_name=_('Sessão finalizada?'),
+ default=False)
interativa = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão interativa'))
diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py
index 4c471e4e9..1a3cda69a 100644
--- a/sapl/sessao/views.py
+++ b/sapl/sessao/views.py
@@ -119,7 +119,8 @@ def verifica_sessao_iniciada(request, spk):
if not sessao.iniciada or sessao.finalizada:
msg = _('Não é possível abrir matérias para votação. '
- 'Esta Sessão Plenária não foi iniciada ou está finalizada.')
+ 'Esta Sessão Plenária não foi iniciada ou está finalizada.'
+ ' Vá em "Abertura"->"Dados Básicos" e altere os valores dos campos necessários.')
messages.add_message(request, messages.INFO, msg)
return False
@@ -1900,9 +1901,6 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
except ObjectDoesNotExist:
raise Http404()
- if 'cancelar-votacao' in request.POST:
- fechar_votacao_materia(materia_votacao)
- return self.form_valid(form)
if form.is_valid():
votos_sim = 0
@@ -1910,6 +1908,21 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
abstencoes = 0
nao_votou = 0
+ if 'cancelar-votacao' in request.POST:
+ fechar_votacao_materia(materia_votacao)
+ if self.ordem:
+ return HttpResponseRedirect(reverse(
+ 'sapl.sessao:ordemdia_list', kwargs={'pk': kwargs['pk']}))
+ else:
+ return HttpResponseRedirect(reverse(
+ 'sapl.sessao:expedientemateria_list',
+ kwargs={'pk': kwargs['pk']}))
+ else:
+ if form.cleaned_data['resultado_votacao'] == None:
+ form.add_error(None, 'Não é possível finalizar a votação sem '
+ 'nenhum resultado da votação')
+ return self.form_invalid(form)
+
for votos in request.POST.getlist('voto_parlamentar'):
v = votos.split(':')
voto = v[0]
diff --git a/sapl/settings.py b/sapl/settings.py
index 7413ecb81..6cc34401e 100644
--- a/sapl/settings.py
+++ b/sapl/settings.py
@@ -115,11 +115,7 @@ HAYSTACK_CONNECTIONS = {
},
}
-
-if DEBUG:
- INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)
-
-MIDDLEWARE_CLASSES = (
+MIDDLEWARE = [
'reversion.middleware.RevisionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
@@ -130,8 +126,13 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware',
- # 'speedinfo.middleware.ProfilerMiddleware', # Bug na versão 1.9
-)
+ 'speedinfo.middleware.ProfilerMiddleware',
+]
+if DEBUG:
+ INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)
+ MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware', ]
+ INTERNAL_IPS = ('127.0.0.1')
+
CACHES = {
'default': {
diff --git a/sapl/templates/audiencia/layouts.yaml b/sapl/templates/audiencia/layouts.yaml
index 90433db63..8e93b9f3a 100644
--- a/sapl/templates/audiencia/layouts.yaml
+++ b/sapl/templates/audiencia/layouts.yaml
@@ -21,4 +21,9 @@ AudienciaPublicaDetail:
- url_audio url_video
- upload_pauta upload_ata upload_anexo
- observacao
- - audiencia_cancelada
\ No newline at end of file
+ - audiencia_cancelada
+
+AnexoAudienciaPublica:
+ {% trans 'Documento Acessório' %}:
+ - assunto
+ - arquivo
\ No newline at end of file
diff --git a/sapl/templates/audiencia/subnav.yaml b/sapl/templates/audiencia/subnav.yaml
new file mode 100644
index 000000000..e6dce83bf
--- /dev/null
+++ b/sapl/templates/audiencia/subnav.yaml
@@ -0,0 +1,5 @@
+{% load i18n common_tags %}
+- title: {% trans 'Início' %}
+ url: audienciapublica_detail
+- title: {% trans 'Documento Acessório' %}
+ url: anexoaudienciapublica_list
\ No newline at end of file
diff --git a/sapl/templates/materia/impressos/ficha_pdf.html b/sapl/templates/materia/impressos/ficha_pdf.html
index 07ad4092a..faa7163e2 100644
--- a/sapl/templates/materia/impressos/ficha_pdf.html
+++ b/sapl/templates/materia/impressos/ficha_pdf.html
@@ -70,7 +70,7 @@ body
PROCESSO Nº {{ materia.numeracao_set.first.numero_materia }} / {{ materia.numeracao_set.first.ano_materia }}
{% else %}
- PROCESSO Nº: {{ materia.numero }}
+ PROCESSO Nº: {{ materia.numero }} / {{materia.ano}}
{% endif %}
@@ -96,6 +96,14 @@ body
Autor: {{materia.autoria_set.first.autor.nome}}
+ {% if materia.numero_protocolo%}
+
|
+
+ Protocolo: {{materia.numero_protocolo}} / {{materia.ano}} + |
+