diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py
index 0ba1ca7f0..b9a11ac92 100644
--- a/sapl/materia/forms.py
+++ b/sapl/materia/forms.py
@@ -1597,7 +1597,8 @@ class TipoProposicaoForm(ModelForm):
'content_type',
'tipo_conteudo_related_radio',
'tipo_conteudo_related',
- 'perfis']
+ 'perfis',
+ 'dispensa_protocolo']
widgets = {'tipo_conteudo_related': forms.HiddenInput(),
'perfis': widgets.CheckboxSelectMultiple()}
@@ -1612,6 +1613,7 @@ class TipoProposicaoForm(ModelForm):
Row(
to_column(('descricao', 12)),
to_column(('perfis', 12)),
+ to_column(('dispensa_protocolo', 12)),
),
5
)
diff --git a/sapl/materia/migrations/0097_add_dispensa_protocolo_tipoproposicao.py b/sapl/materia/migrations/0097_add_dispensa_protocolo_tipoproposicao.py
new file mode 100644
index 000000000..44cbcec1d
--- /dev/null
+++ b/sapl/materia/migrations/0097_add_dispensa_protocolo_tipoproposicao.py
@@ -0,0 +1,19 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('materia', '0096_add_permite_remover_assinatura_e_permissoes'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='tipoproposicao',
+ name='dispensa_protocolo',
+ field=models.BooleanField(
+ default=False,
+ help_text='Quando marcado, proposições deste tipo não são enviadas ao Protocolo e não se tornam Matéria Legislativa. Ficam restritas ao gabinete do autor. Use para documentos de uso próprio do gabinete, como Ofícios, que não precisam de validação da Casa.',
+ verbose_name='Documento de gabinete'),
+ ),
+ ]
diff --git a/sapl/materia/models.py b/sapl/materia/models.py
index 0d490ded0..1ac78ce2b 100644
--- a/sapl/materia/models.py
+++ b/sapl/materia/models.py
@@ -71,6 +71,15 @@ class TipoProposicao(models.Model):
menos um Perfil Estrutural de Texto Articulado.
"""))
+ dispensa_protocolo = models.BooleanField(
+ default=False,
+ verbose_name=_('Documento de gabinete'),
+ help_text=_('Quando marcado, proposições deste tipo não são enviadas '
+ 'ao Protocolo e não se tornam Matéria Legislativa. Ficam '
+ 'restritas ao gabinete do autor. Use para documentos de '
+ 'uso próprio do gabinete, como Ofícios, que não precisam '
+ 'de validação da Casa.'))
+
class Meta:
verbose_name = _('Tipo de Proposição')
verbose_name_plural = _('Tipos de Proposições')
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
index d621006ee..9430ca909 100644
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -483,7 +483,8 @@ class TipoProposicaoCrud(CrudAux):
class BaseMixin(CrudAux.BaseMixin):
list_field_names = [
- "descricao", "content_type", 'tipo_conteudo_related']
+ "descricao", "content_type", 'tipo_conteudo_related',
+ 'dispensa_protocolo']
class CreateView(CrudAux.CreateView):
form_class = TipoProposicaoForm
@@ -1033,6 +1034,13 @@ class UnidadeTramitacaoCrud(CrudAux):
form_class = UnidadeTramitacaoForm
+# Tipos de proposição marcados como "Documento de gabinete" não saem do
+# gabinete do autor: não vão ao Protocolo nem ao Setor Legislativo.
+MSG_DISPENSA_PROTOCOLO = _(
+ 'Este é um documento de gabinete e não passa pelo Protocolo. '
+ 'Ele fica restrito ao seu gabinete.')
+
+
class ProposicaoCrud(Crud):
model = Proposicao
help_topic = 'proposicao'
@@ -1118,7 +1126,9 @@ class ProposicaoCrud(Crud):
msg_error = ''
if p and p.autor.operadores.filter(id=request.user.id).exists():
if action == 'send':
- if p.data_envio and p.data_recebimento:
+ if p.tipo and p.tipo.dispensa_protocolo:
+ msg_error = MSG_DISPENSA_PROTOCOLO
+ elif p.data_envio and p.data_recebimento:
msg_error = _('Proposição já foi enviada e recebida.')
elif p.data_envio:
msg_error = _('Proposição já foi enviada.')
@@ -1214,7 +1224,9 @@ class ProposicaoCrud(Crud):
elif action == 'send_setor':
app_config = sapl.base.models.AppConfig.objects.all().last()
- if not app_config or not app_config.revisao_setor_legislativo:
+ if p.tipo and p.tipo.dispensa_protocolo:
+ msg_error = MSG_DISPENSA_PROTOCOLO
+ elif not app_config or not app_config.revisao_setor_legislativo:
msg_error = _('Revisão pelo Setor Legislativo não está habilitada.')
elif p.data_envio:
msg_error = _('Proposição já foi enviada ao protocolo.')
@@ -1469,7 +1481,12 @@ class ProposicaoCrud(Crud):
status_filter = self.request.GET.get('status', '')
if status_filter == 'elaboracao':
- qs = qs.filter(data_envio__isnull=True, cancelado=False)
+ qs = qs.filter(
+ data_envio__isnull=True, cancelado=False
+ ).exclude(tipo__dispensa_protocolo=True)
+ elif status_filter == 'gabinete':
+ qs = qs.filter(tipo__dispensa_protocolo=True,
+ data_envio__isnull=True, cancelado=False)
elif status_filter == 'aguardando':
qs = qs.filter(data_envio__isnull=False, data_recebimento__isnull=True, data_devolucao__isnull=True, cancelado=False)
elif status_filter == 'incorporada':
@@ -1486,7 +1503,8 @@ class ProposicaoCrud(Crud):
qs_base = super().get_queryset()
stats = {
'total': qs_base.count(),
- 'elaboracao': qs_base.filter(data_envio__isnull=True, cancelado=False).count(),
+ 'elaboracao': qs_base.filter(data_envio__isnull=True, cancelado=False).exclude(tipo__dispensa_protocolo=True).count(),
+ 'gabinete': qs_base.filter(tipo__dispensa_protocolo=True, data_envio__isnull=True, cancelado=False).count(),
'aguardando': qs_base.filter(data_envio__isnull=False, data_recebimento__isnull=True, data_devolucao__isnull=True, cancelado=False).count(),
'incorporada': qs_base.filter(data_recebimento__isnull=False, cancelado=False).count(),
'devolvida': qs_base.filter(data_devolucao__isnull=False, cancelado=False).count(),
@@ -1521,6 +1539,10 @@ class ProposicaoCrud(Crud):
status = 'aguardando'
status_label = 'Aguardando Recebimento'
status_icon = 'fa-clock-o'
+ elif obj.tipo and obj.tipo.dispensa_protocolo:
+ status = 'gabinete'
+ status_label = 'Documento de Gabinete'
+ status_icon = 'fa-briefcase'
else:
status = 'elaboracao'
status_label = 'Em Elaboração'
diff --git a/sapl/templates/materia/proposicao_detail.html b/sapl/templates/materia/proposicao_detail.html
index a84a23e63..ad7bfb789 100644
--- a/sapl/templates/materia/proposicao_detail.html
+++ b/sapl/templates/materia/proposicao_detail.html
@@ -351,7 +351,13 @@
{% trans "Editar Documento" %}
- {% if object.texto_original or object.texto_articulado.exists %}
+ {% if object.tipo.dispensa_protocolo %}
+ {# Documento de gabinete: não vai ao Protocolo nem ao Setor Legislativo #}
+
+
+ {% trans "Documento de gabinete — não passa pelo Protocolo" %}
+
+ {% elif object.texto_original or object.texto_articulado.exists %}
{% trans "Enviar Proposição" %}
diff --git a/sapl/templates/materia/proposicao_list.html b/sapl/templates/materia/proposicao_list.html
index b42372ddf..b40fd85b1 100644
--- a/sapl/templates/materia/proposicao_list.html
+++ b/sapl/templates/materia/proposicao_list.html
@@ -213,6 +213,9 @@
{{ stats.elaboracao|default:"0" }} em elaboração
+
+ {{ stats.gabinete|default:"0" }} de gabinete
+
{{ stats.aguardando|default:"0" }} enviadas