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

4
sapl/materia/urls.py

@ -31,7 +31,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
DespachoInicialMultiCreateView, DespachoInicialMultiCreateView,
get_zip_docacessorios, get_pdf_docacessorios, get_zip_docacessorios, get_pdf_docacessorios,
configEtiquetaMateriaLegislativaCrud, configEtiquetaMateriaLegislativaCrud,
PesquisarStatusTramitacaoView) PesquisarStatusTramitacaoView, HistoricoProposicaoView)
from sapl.norma.views import NormaPesquisaSimplesView from sapl.norma.views import NormaPesquisaSimplesView
from sapl.protocoloadm.views import ( from sapl.protocoloadm.views import (
FichaPesquisaAdmView, FichaSelecionaAdmView FichaPesquisaAdmView, FichaSelecionaAdmView
@ -156,6 +156,8 @@ urlpatterns_proposicao = [
name='proposicao_texto'), name='proposicao_texto'),
url(r'^proposicao/(?P<pk>\d+)/retornar', RetornarProposicao.as_view(), url(r'^proposicao/(?P<pk>\d+)/retornar', RetornarProposicao.as_view(),
name='retornar-proposicao'), 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, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao,
Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao, Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa) Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa, HistoricoProposicao)
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@ -680,6 +680,12 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
form_class = ConfirmarProposicaoForm, DevolverProposicaoForm form_class = ConfirmarProposicaoForm, DevolverProposicaoForm
logger = logging.getLogger(__name__) 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): def get_success_url(self):
msgs = self.object.results['messages'] msgs = self.object.results['messages']
@ -897,6 +903,11 @@ class ProposicaoCrud(Crud):
p.data_devolucao = None p.data_devolucao = None
p.data_envio = timezone.now() p.data_envio = timezone.now()
p.save() p.save()
HistoricoProposicao.objects.create(
proposicao=p,
status='E',
ip=get_client_ip(self.request),
user=self.request.user)
messages.success(request, _( messages.success(request, _(
'Proposição enviada com sucesso.')) 'Proposição enviada com sucesso.'))
@ -939,6 +950,12 @@ class ProposicaoCrud(Crud):
else: else:
p.data_envio = None p.data_envio = None
p.save() p.save()
HistoricoProposicao.objects.create(
proposicao=p,
status='T',
ip=get_client_ip(self.request),
user=self.request.user)
if p.texto_articulado.exists(): if p.texto_articulado.exists():
ta = p.texto_articulado.first() ta = p.texto_articulado.first()
ta.privacidade = STATUS_TA_PRIVATE ta.privacidade = STATUS_TA_PRIVATE
@ -1216,6 +1233,34 @@ class ReciboProposicaoView(TemplateView):
kwargs={'pk': proposicao.pk})) 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): class RelatoriaCrud(MasterDetailCrud):
model = Relatoria model = Relatoria
parent_field = 'materia' parent_field = 'materia'

2
sapl/rules/map_rules.py

@ -95,6 +95,7 @@ rules_group_protocolo = {
(materia.Proposicao, ['detail_proposicao_enviada', (materia.Proposicao, ['detail_proposicao_enviada',
'detail_proposicao_devolvida', 'detail_proposicao_devolvida',
'detail_proposicao_incorporada'], set()), # TODO: tratar em sapl.api questão de que proposições incorporadas serem públicas '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, [ (compilacao.TextoArticulado, [
'view_restricted_textoarticulado'], __perms_publicas__) 'view_restricted_textoarticulado'], __perms_publicas__)
] ]
@ -203,6 +204,7 @@ rules_group_autor = {
'group': SAPL_GROUP_AUTOR, 'group': SAPL_GROUP_AUTOR,
'rules': [ 'rules': [
(materia.Proposicao, __base__, set()), (materia.Proposicao, __base__, set()),
(materia.HistoricoProposicao, __base__, set()),
(compilacao.Dispositivo, __base__ + [ (compilacao.Dispositivo, __base__ + [
'change_your_dispositivo_edicao_dinamica', 'change_your_dispositivo_edicao_dinamica',
], __perms_publicas__) ], __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 url: proposicao-devolvida
- title: {% trans 'Proposições Incorporadas' %} - title: {% trans 'Proposições Incorporadas' %}
url: proposicao-recebida url: proposicao-recebida
- title: {% trans 'Histórico Proposições' %}
url: historico-proposicao
Loading…
Cancel
Save