Browse Source

Histórico de Proposições (#3358)

* Fixes #3356

Co-authored-by: eribeiro <edwardr@senado.leg.br>
pull/3369/head
Edward 4 years ago
committed by GitHub
parent
commit
028e48e8b1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      sapl/materia/forms.py
  2. 34
      sapl/materia/migrations/0078_historicoproposicao.py
  3. 45
      sapl/materia/models.py
  4. 4
      sapl/materia/urls.py
  5. 47
      sapl/materia/views.py
  6. 2
      sapl/rules/map_rules.py
  7. 44
      sapl/templates/materia/historico_proposicao.html
  8. 12
      sapl/templates/materia/proposicao_list.html
  9. 2
      sapl/templates/materia/subnav_prop.yaml

29
sapl/materia/forms.py

@ -29,7 +29,7 @@ from sapl.materia.models import (AssuntoMateria, MateriaAssunto,
MateriaLegislativa, Orgao,
RegimeTramitacao, StatusTramitacao,
TipoDocumento, TipoProposicao,
ConfigEtiquetaMateriaLegislativa)
ConfigEtiquetaMateriaLegislativa, HistoricoProposicao)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
from sapl.parlamentares.models import Legislatura, Partido
@ -2084,7 +2084,13 @@ class DevolverProposicaoForm(forms.ModelForm):
fields = [
'justificativa_devolucao',
'observacao',
'user',
'ip'
]
widgets = {
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
@ -2139,6 +2145,13 @@ class DevolverProposicaoForm(forms.ModelForm):
ta.editing_locked = False
ta.save()
observacao = self.instance.justificativa_devolucao
HistoricoProposicao.objects.create(proposicao=self.instance,
status='D',
user=self.initial['user'],
ip=self.initial['ip'],
observacao=observacao)
self.instance.results = {
'messages': {
'success': [_('Devolução efetuada com sucesso.'), ]
@ -2181,13 +2194,17 @@ class ConfirmarProposicaoForm(ProposicaoForm):
'observacao',
'gerar_protocolo',
'numero_de_paginas',
'numero_materia_futuro'
'numero_materia_futuro',
'user',
'ip'
]
widgets = {
'descricao': widgets.Textarea(
attrs={'readonly': 'readonly', 'rows': 4}),
'data_envio': widgets.DateTimeInput(
attrs={'readonly': 'readonly'}),
'user': forms.HiddenInput(),
'ip': forms.HiddenInput(),
}
def __init__(self, *args, **kwargs):
@ -2395,6 +2412,12 @@ class ConfirmarProposicaoForm(ProposicaoForm):
proposicao = self.instance
conteudo_gerado = None
HistoricoProposicao.objects.create(proposicao=proposicao,
status='R',
user=self.initial['user'],
ip=self.initial['ip'],
)
if self.instance.tipo.content_type.model_class(
) == TipoMateriaLegislativa:
@ -2591,6 +2614,8 @@ class ConfirmarProposicaoForm(ProposicaoForm):
protocolo.tipo_processo = '0'
protocolo.save()
HistoricoProposicao.objects.create(proposicao=proposicao,
status='E')
self.instance.results['messages']['success'].append(_(
'Protocolo realizado com sucesso'))

34
sapl/materia/migrations/0078_historicoproposicao.py

@ -0,0 +1,34 @@
# Generated by Django 2.2.13 on 2021-03-02 17:17
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('materia', '0077_auto_20210209_1047'),
]
operations = [
migrations.CreateModel(
name='HistoricoProposicao',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.CharField(choices=[('E', 'Enviada'), ('R', 'Recebida'), ('T', 'Retornada'), ('D', 'Devolvida')], db_index=True, max_length=1, verbose_name='Status de Proposição')),
('data_hora', models.DateTimeField(blank=True, db_index=True, default=django.utils.timezone.now, null=True, verbose_name='Data/Hora')),
('observacao', models.CharField(blank=True, max_length=200, verbose_name='Observação')),
('ip', models.CharField(blank=True, default='', max_length=60, verbose_name='IP')),
('proposicao', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='materia.Proposicao', verbose_name='Proposição')),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Usuário')),
],
options={
'verbose_name': 'Histórico de Proposição',
'verbose_name_plural': 'Histórico de Proposições',
'ordering': ('-data_hora', '-proposicao'),
},
),
]

45
sapl/materia/models.py

@ -1025,6 +1025,51 @@ class Proposicao(models.Model):
update_fields=update_fields)
class HistoricoProposicao(models.Model):
STATUS_PROPOSICAO = Choices(('E', 'ENVIADA', _('Enviada')),
('R', 'RECEBIDA', _('Recebida')),
('T', 'RETORNADA', _('Retornada')),
('D', 'DEVOLVIDA', _('Devolvida')))
proposicao = models.ForeignKey(Proposicao,
verbose_name=_('Proposição'),
db_index=True,
on_delete=models.CASCADE)
status = models.CharField(max_length=1,
verbose_name=_('Status de Proposição'),
db_index=True,
choices=STATUS_PROPOSICAO)
data_hora = models.DateTimeField(null=True,
blank=True,
default=timezone.now,
db_index=True,
verbose_name=_('Data/Hora'))
observacao = models.CharField(max_length=200,
blank=True,
verbose_name=_('Observação'))
user = models.ForeignKey(get_settings_auth_user_model(),
verbose_name=_('Usuário'),
on_delete=models.PROTECT,
null=True,
blank=True)
ip = models.CharField(verbose_name=_('IP'),
max_length=60,
blank=True,
default='')
@property
def status_descricao(self):
return self.STATUS_PROPOSICAO[self.status]
class Meta:
verbose_name = _('Histórico de Proposição')
verbose_name_plural = _('Histórico de Proposições')
ordering = ('-data_hora', '-proposicao')
def __str__(self):
return f'{self.data_hora} - {self.STATUS_PROPOSICAO[self.status]} - {str(self.proposicao)}'
@reversion.register()
class StatusTramitacao(models.Model):
INDICADOR_CHOICES = Choices(('F', 'fim', _('Fim')),

4
sapl/materia/urls.py

@ -31,7 +31,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
DespachoInicialMultiCreateView,
get_zip_docacessorios, get_pdf_docacessorios,
configEtiquetaMateriaLegislativaCrud,
PesquisarStatusTramitacaoView)
PesquisarStatusTramitacaoView, HistoricoProposicaoView)
from sapl.norma.views import NormaPesquisaSimplesView
from sapl.protocoloadm.views import (
FichaPesquisaAdmView, FichaSelecionaAdmView
@ -156,6 +156,8 @@ urlpatterns_proposicao = [
name='proposicao_texto'),
url(r'^proposicao/(?P<pk>\d+)/retornar', RetornarProposicao.as_view(),
name='retornar-proposicao'),
url(r'^proposicao/historico', HistoricoProposicaoView.as_view(),
name='historico-proposicao'),
]

47
sapl/materia/views.py

@ -75,7 +75,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, De
DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao,
Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa)
Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa, HistoricoProposicao)
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@ -680,6 +680,12 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
form_class = ConfirmarProposicaoForm, DevolverProposicaoForm
logger = logging.getLogger(__name__)
def get_initial(self):
initial = super().get_initial()
initial['ip'] = get_client_ip(self.request)
initial['user'] = self.request.user
return initial
def get_success_url(self):
msgs = self.object.results['messages']
@ -897,6 +903,11 @@ class ProposicaoCrud(Crud):
p.data_devolucao = None
p.data_envio = timezone.now()
p.save()
HistoricoProposicao.objects.create(
proposicao=p,
status='E',
ip=get_client_ip(self.request),
user=self.request.user)
messages.success(request, _(
'Proposição enviada com sucesso.'))
@ -939,6 +950,12 @@ class ProposicaoCrud(Crud):
else:
p.data_envio = None
p.save()
HistoricoProposicao.objects.create(
proposicao=p,
status='T',
ip=get_client_ip(self.request),
user=self.request.user)
if p.texto_articulado.exists():
ta = p.texto_articulado.first()
ta.privacidade = STATUS_TA_PRIVATE
@ -1216,6 +1233,34 @@ class ReciboProposicaoView(TemplateView):
kwargs={'pk': proposicao.pk}))
class HistoricoProposicaoView(PermissionRequiredMixin, ListView):
logger = logging.getLogger(__name__)
template_name = "materia/historico_proposicao.html"
ordering = ['-data_hora']
paginate_by = 10
model = HistoricoProposicao
permission_required = ('materia.detail_proposicao', )
def get_queryset(self):
qs = super().get_queryset()
user = self.request.user
if not user.is_superuser:
autores = Autor.objects.filter(user=user)
qs = qs.filter(proposicao__autor__in=autores)
return qs
def get_context_data(self, **kwargs):
context = super(HistoricoProposicaoView, self).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context['NO_ENTRIES_MSG'] = 'Nenhuma proposição'
if self.request.user.is_superuser:
context['subnav_template_name'] = 'materia/subnav_prop.yaml'
return context
class RelatoriaCrud(MasterDetailCrud):
model = Relatoria
parent_field = 'materia'

2
sapl/rules/map_rules.py

@ -95,6 +95,7 @@ rules_group_protocolo = {
(materia.Proposicao, ['detail_proposicao_enviada',
'detail_proposicao_devolvida',
'detail_proposicao_incorporada'], set()), # TODO: tratar em sapl.api questão de que proposições incorporadas serem públicas
(materia.HistoricoProposicao, __base__, set()),
(compilacao.TextoArticulado, [
'view_restricted_textoarticulado'], __perms_publicas__)
]
@ -203,6 +204,7 @@ rules_group_autor = {
'group': SAPL_GROUP_AUTOR,
'rules': [
(materia.Proposicao, __base__, set()),
(materia.HistoricoProposicao, __base__, set()),
(compilacao.Dispositivo, __base__ + [
'change_your_dispositivo_edicao_dinamica',
], __perms_publicas__)

44
sapl/templates/materia/historico_proposicao.html

@ -0,0 +1,44 @@
{% extends "base.html" %}
{% load i18n %}
{% load tz %}
{% block base_content %}
<fieldset>
<legend>Histórico de Proposições</legend>
{% if not object_list %}
<p>{{ NO_ENTRIES_MSG }}</p>
{% else %}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Data/Hora</th>
<th>Status</th>
<th>Operador</th>
<th>Proposição</th>
<th>Descrição</th>
<th>Autor</th>
<th>Observação</th>
</tr>
</thead>
<tbody>
{% for hist in object_list %}
<tr>
<td>{{ hist.data_hora|localtime|date:"d/m/Y H:i:s" }}</td>
<td>{{ hist.status_descricao}}</td>
<td>{{ hist.user }}</td>
<td>
<a href="{% url 'sapl.materia:proposicao_detail' hist.proposicao.pk %}">
{{ hist.proposicao.numero_proposicao }}/{{ hist.proposicao.ano }}
</a>
</td>
<td>{{ hist.proposicao.descricao }}</td>
<td>{{ hist.proposicao.autor }}</td>
<td>{{ hist.observacao }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</fieldset>
{% include 'paginacao.html'%}
{% endblock %}

12
sapl/templates/materia/proposicao_list.html

@ -0,0 +1,12 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% block base_content %}
{% block sub_actions %}
<div class="actions btn-group btn-group-sm" role="group">
<a href="{% url 'sapl.materia:historico-proposicao' %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Histórico de {{ verbose_name }} {% endblocktrans %}
</a>
</div>
{% endblock sub_actions %}
{{ block.super }}
{% endblock %}

2
sapl/templates/materia/subnav_prop.yaml

@ -7,3 +7,5 @@
url: proposicao-devolvida
- title: {% trans 'Proposições Incorporadas' %}
url: proposicao-recebida
- title: {% trans 'Histórico Proposições' %}
url: historico-proposicao
Loading…
Cancel
Save