Browse Source

impl crud de vinculodocadminmateria

pull/3586/head
LeandroJatai 3 years ago
parent
commit
ad9c8a9cdb
  1. 2
      sapl/crispy_layout_mixin.py
  2. 11
      sapl/crud/base.py
  3. 79
      sapl/protocoloadm/forms.py
  4. 23
      sapl/protocoloadm/migrations/0042_auto_20220805_1236.py
  5. 13
      sapl/protocoloadm/models.py
  6. 10
      sapl/protocoloadm/urls.py
  7. 186
      sapl/protocoloadm/views.py
  8. 3
      sapl/templates/materia/materialegislativa_detail.html
  9. 1
      sapl/templates/protocoloadm/documentoadministrativo_detail.html
  10. 16
      sapl/templates/protocoloadm/layouts.yaml
  11. 2
      sapl/templates/protocoloadm/subnav.yaml
  12. 38
      sapl/templates/protocoloadm/vinculodocadminmateria_form.html

2
sapl/crispy_layout_mixin.py

@ -170,7 +170,7 @@ def get_field_display(obj, fieldname):
display = '<div class="dont-break-out">{}</div>'.format(display)
else:
display = str(value)
return verbose_name, display
return verbose_name, display or '&nbsp;'
class CrispyLayoutFormMixin:

11
sapl/crud/base.py

@ -1119,12 +1119,15 @@ class MasterDetailCrud(Crud):
root_pk = self.kwargs['pk'] if 'pkk' not in self.request.GET\
else self.request.GET['pkk']
kwargs.setdefault('root_pk', root_pk)
context = super(CrudBaseMixin, self).get_context_data(**kwargs)
if parent_object:
context['title'] = '%s <small>(%s)</small>' % (
self.object, parent_object)
title = '%s <small>(%s)</small>' % (
self.object,
parent_object
) if parent_object else ''
context = super(CrudBaseMixin, self).get_context_data(**kwargs)
if 'title' not in context and title:
context['title'] = title
return context
class ListView(Crud.ListView):

79
sapl/protocoloadm/forms.py

@ -20,6 +20,7 @@ from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper,
from sapl.materia.models import (MateriaLegislativa,
TipoMateriaLegislativa,
UnidadeTramitacao)
from sapl.protocoloadm.models import VinculoDocAdminMateria
from sapl.utils import (AnoNumeroOrderingFilter, autor_label, autor_modal,
choice_anos_com_documentoadministrativo,
choice_anos_com_materias, timing,
@ -793,7 +794,7 @@ class TramitacaoAdmForm(ModelForm):
ip=tramitacao.ip,
ultima_edicao=tramitacao.ultima_edicao
))
## TODO: BULK UPDATE não envia Signal para Tramitacao
# TODO: BULK UPDATE não envia Signal para Tramitacao
TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao)
return tramitacao
@ -915,7 +916,7 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
da.tramitacao = False if nova_tram_principal.status.indicador == "F" else True
da.save()
## TODO: refatorar?
# TODO: refatorar?
return nova_tram_principal
@ -1694,7 +1695,7 @@ class TramitacaoEmLoteAdmForm(ModelForm):
ip=tramitacao.ip,
ultima_edicao=tramitacao.ultima_edicao
))
## TODO: BULK UPDATE não envia Signal para Tramitacao
# TODO: BULK UPDATE não envia Signal para Tramitacao
TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao)
return tramitacao
@ -1732,3 +1733,75 @@ class TramitacaoEmLoteAdmFilterSet(django_filters.FilterSet):
self.form.helper.layout = Layout(
Fieldset(_('Tramitação em Lote'),
row1, row2, form_actions(label=_('Pesquisar'))))
class VinculoDocAdminMateriaForm(ModelForm):
logger = logging.getLogger(__name__)
tipo = forms.ModelChoiceField(
label='Tipo',
required=True,
queryset=TipoMateriaLegislativa.objects.all(),
empty_label='Selecione',
)
numero = forms.IntegerField(label='Número', required=True)
ano = forms.CharField(label='Ano', required=True)
class Meta:
model = VinculoDocAdminMateria
fields = ['tipo', 'numero', 'ano', 'data_anexacao', 'data_desanexacao']
def __init__(self, *args, **kwargs):
return super().__init__(*args, **kwargs)
def clean(self):
super().clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
data_anexacao = cleaned_data['data_anexacao']
data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao
if data_anexacao > data_desanexacao:
self.logger.error(
"Data de anexação posterior à data de desanexação.")
raise ValidationError(
_("Data de anexação posterior à data de desanexação."))
try:
self.logger.info("Tentando obter objeto MateriaLegislativa (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
materia = MateriaLegislativa.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo'])
except ObjectDoesNotExist:
msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.'
.format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano']))
self.logger.warning(
"A matéria a ser anexada não existe no cadastro de matérias legislativas.")
raise ValidationError(msg)
if VinculoDocAdminMateria.objects.filter(
documento=self.instance.documento, materia=materia
).exclude(pk=self.instance.pk).exists():
self.logger.error(
"Matéria já se encontra vinculada a este documento.")
raise ValidationError(
_('Matéria já se encontra vinculada a este documento'))
cleaned_data['materia'] = materia
return cleaned_data
def save(self, commit=False):
anexada = super().save(commit)
anexada.materia = self.cleaned_data['materia']
anexada.save()
return anexada

23
sapl/protocoloadm/migrations/0042_auto_20220805_1236.py

@ -0,0 +1,23 @@
# Generated by Django 2.2.28 on 2022-08-05 15:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0081_auto_20220321_0934'),
('protocoloadm', '0041_auto_20220804_2239'),
]
operations = [
migrations.AlterField(
model_name='documentoadministrativo',
name='materiasvinculadas',
field=models.ManyToManyField(blank=True, related_name='docadmvinculados', through='protocoloadm.VinculoDocAdminMateria', to='materia.MateriaLegislativa'),
),
migrations.AlterUniqueTogether(
name='vinculodocadminmateria',
unique_together={('documento', 'materia')},
),
]

13
sapl/protocoloadm/models.py

@ -255,6 +255,14 @@ class DocumentoAdministrativo(models.Model):
'tipo': self.tipo, 'assunto': self.assunto
}
@property
def epigrafe(self):
return _('%(tipo)s - %(numero)s/%(ano)s') % {
'tipo': self.tipo,
'numero': self.numero,
'ano': self.ano
}
def delete(self, using=None, keep_parents=False):
texto_integral = self.texto_integral
result = super().delete(using=using, keep_parents=keep_parents)
@ -479,6 +487,11 @@ class VinculoDocAdminMateria(models.Model):
def __str__(self):
return f'Vinculo: {self.documento} - {self.materia}'
return _('Vinculo %(documento)s // %(materia)s') % {
'documento': self.documento.epigrafe,
'materia': self.materia
}
@reversion.register()
class AcompanhamentoDocumento(models.Model):

10
sapl/protocoloadm/urls.py

@ -25,7 +25,8 @@ from sapl.protocoloadm.views import (AcompanhamentoDocumentoView,
AnexadoCrud, DocumentoAnexadoEmLoteView,
PrimeiraTramitacaoEmLoteAdmView,
TramitacaoEmLoteAdmView,
apaga_protocolos_view)
apaga_protocolos_view,
VinculoDocAdminMateriaCrud)
from .apps import AppConfig
@ -34,16 +35,17 @@ app_name = AppConfig.name
urlpatterns_documento_administrativo = [
url(r'^docadm/',
include(DocumentoAdministrativoCrud.get_urls() +
AnexadoCrud.get_urls() +
AnexadoCrud.get_urls() +
TramitacaoAdmCrud.get_urls() +
DocumentoAcessorioAdministrativoCrud.get_urls())),
DocumentoAcessorioAdministrativoCrud.get_urls() +
VinculoDocAdminMateriaCrud.get_urls())),
url(r'^docadm/pesq-doc-adm',
PesquisarDocumentoAdministrativoView.as_view(), name='pesq_doc_adm'),
url(r'^docadm/texto_integral/(?P<pk>\d+)$', doc_texto_integral,
name='doc_texto_integral'),
url(r'^docadm/(?P<pk>\d+)/anexado_em_lote', DocumentoAnexadoEmLoteView.as_view(),
name='anexado_em_lote'),
]

186
sapl/protocoloadm/views.py

@ -35,7 +35,9 @@ from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination,
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao
from sapl.materia.views import gerar_pdf_impressos
from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo
from sapl.protocoloadm.forms import VinculoDocAdminMateriaForm
from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo,\
VinculoDocAdminMateria
from sapl.relatorios.views import relatorio_doc_administrativos
from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, lista_anexados,
@ -1126,7 +1128,7 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
context['object_list'] = []
else:
context['temp_object_list'] = context['object_list'].order_by(
'numero', '-ano')
'numero', '-ano')
context['object_list'] = []
for obj in context['temp_object_list']:
if not obj.pk == int(context['root_pk']):
@ -1155,7 +1157,6 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
if not ciclico:
context['object_list'].append(obj)
context['numero_res'] = len(context['object_list'])
@ -1300,7 +1301,6 @@ class TramitacaoAdmCrud(MasterDetailCrud):
return initial
class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView):
def get_queryset(self):
@ -1751,3 +1751,181 @@ def apaga_protocolos_view(request):
return JsonResponse({'type': 'success', 'msg': ''})
else:
return JsonResponse({'type': 'error', 'msg': 'Senha Incorreta'})
class VinculoDocAdminMateriaCrud(MasterDetailCrud):
model = VinculoDocAdminMateria
parent_field = 'documento'
help_topic = 'vinculodocadminmateria'
public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['data_anexacao', ('materia', 'materia__ementa')]
@property
def verbose_name(self):
return _('Vinculo')
@property
def verbose_name_plural(self):
return _('Vinculos')
@property
def title(self):
return self.object.documento.epigrafe
class CreateView(MasterDetailCrud.CreateView):
form_class = VinculoDocAdminMateriaForm
class UpdateView(MasterDetailCrud.UpdateView):
form_class = VinculoDocAdminMateriaForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = self.object.documento.epigrafe
return context
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial['tipo'] = self.object.materia.tipo.id
initial['numero'] = self.object.materia.numero
initial['ano'] = self.object.materia.ano
return initial
class DetailView(MasterDetailCrud.DetailView):
@property
def layout_key(self):
return 'VinculoDocAdminMateriaDetail'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = self.object.documento.epigrafe
return context
"""
class VinculoDocAdminMateriaEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AnexadaEmLoteFilterSet
template_name = 'materia/em_lote/anexada.html'
permission_required = ('materia.add_documentoacessorio',)
def get_context_data(self, **kwargs):
context = super(MateriaAnexadaEmLoteView,
self).get_context_data(**kwargs)
context['root_pk'] = self.kwargs['pk']
context['subnav_template_name'] = 'materia/subnav.yaml'
context['title'] = _('Matérias Anexadas em Lote')
# Verifica se os campos foram preenchidos
if not self.request.GET.get('tipo', " "):
msg = _('Por favor, selecione um tipo de matéria.')
messages.add_message(self.request, messages.ERROR, msg)
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
msg = _('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
msg = _('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
qr = self.request.GET.copy()
if not len(qr):
context['object_list'] = []
else:
context['object_list'] = context['object_list'].order_by(
'numero', '-ano')
principal = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
not_list = [self.kwargs['pk']] + \
[m for m in principal.materia_principal_set.all(
).values_list('materia_anexada_id', flat=True)]
context['object_list'] = context['object_list'].exclude(
pk__in=not_list)
context['temp_object_list'] = context['object_list']
context['object_list'] = []
for obj in context['temp_object_list']:
materia_anexada = obj
ciclico = False
anexadas_anexada = Anexada.objects.filter(
materia_principal=materia_anexada
)
while anexadas_anexada and not ciclico:
anexadas = []
for anexa in anexadas_anexada:
if principal == anexa.materia_anexada:
ciclico = True
else:
for a in Anexada.objects.filter(materia_principal=anexa.materia_anexada):
anexadas.append(a)
anexadas_anexada = anexadas
if not ciclico:
context['object_list'].append(obj)
context['numero_res'] = len(context['object_list'])
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
return context
def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id')
data_anexacao = datetime.strptime(
request.POST['data_anexacao'], "%d/%m/%Y").date()
if request.POST['data_desanexacao'] == '':
data_desanexacao = None
v_data_desanexacao = data_anexacao
else:
data_desanexacao = datetime.strptime(
request.POST['data_desanexacao'], "%d/%m/%Y").date()
v_data_desanexacao = data_desanexacao
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg)
if data_anexacao > v_data_desanexacao:
msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
if data_anexacao > v_data_desanexacao:
msg = _('Data de anexação posterior à data de desanexação.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
principal = MateriaLegislativa.objects.get(pk=kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in=marcadas):
anexada = Anexada()
anexada.materia_principal = principal
anexada.materia_anexada = materia
anexada.data_anexacao = data_anexacao
anexada.data_desanexacao = data_desanexacao
anexada.save()
msg = _('Matéria(s) anexada(s).')
messages.add_message(request, messages.SUCCESS, msg)
success_url = reverse('sapl.materia:anexada_list',
kwargs={'pk': kwargs['pk']})
return HttpResponseRedirect(success_url)
"""

3
sapl/templates/materia/materialegislativa_detail.html

@ -61,8 +61,9 @@
<strong>Data Anexação:</strong> {{vinculodocadmmateria.data_anexacao}} {% if vinculodocadmmateria.data_desanexacao %} - {{vinculodocadmmateria.data_desanexacao}}{% endif %}
<br><strong>Documento:</strong>
<a href="{% url 'sapl.protocoloadm:documentoadministrativo_detail' vinculodocadmmateria.documento.id %}">
{{ vinculodocadmmateria.documento }}
{{ vinculodocadmmateria.documento.epigrafe }}
</a>
<br>{{ vinculodocadmmateria.documento.assunto}}
{% if vinculodocadmmateria.documento.restrito %}
<small class="text-danger">
(Documento Restrito)

1
sapl/templates/protocoloadm/documentoadministrativo_detail.html

@ -17,6 +17,7 @@
<a href="{% url 'sapl.materia:materialegislativa_detail' vinculodocadmmateria.materia.id %}">
{{ vinculodocadmmateria.materia }}
</a>
<br>{{vinculodocadmmateria.materia.ementa}}
{% if not forloop.last %}<hr>{% endif %}
{% endfor %}
</div>

16
sapl/templates/protocoloadm/layouts.yaml

@ -5,9 +5,9 @@ TipoDocumentoAdministrativo:
DocumentoAdministrativo:
{% trans 'Identificação Básica' %}:
- tipo
- tipo
- numero complemento ano
- data protocolo
- data protocolo
- assunto
- interessado autor tramitacao
- texto_integral|urlize
@ -33,7 +33,7 @@ TramitacaoAdministrativo:
{% trans 'Tramitação' %}:
- data_tramitacao unidade_tramitacao_local
- unidade_tramitacao_destino data_encaminhamento data_fim_prazo
- status urgente
- status urgente
- texto
Anexado:
@ -62,3 +62,13 @@ Protocolo:
- assunto_ementa
- autor
- observacao
VinculoDocAdminMateria:
{% trans 'Matéria Vinculada' %}:
- tipo numero ano
- data_anexacao data_desanexacao
VinculoDocAdminMateriaDetail:
{% trans 'Matéria Vinculada' %}:
- materia|fk_urlize_for_detail data_anexacao:3 data_desanexacao:3
- documento

2
sapl/templates/protocoloadm/subnav.yaml

@ -7,3 +7,5 @@
url: tramitacaoadministrativo_list
- title: {% trans 'Documento Acessório' %}
url: documentoacessorioadministrativo_list
- title: {% trans 'Matérias Vinculadas' %}
url: vinculodocadminmateria_list

38
sapl/templates/protocoloadm/vinculodocadminmateria_form.html

@ -0,0 +1,38 @@
{% extends "crud/form.html" %}
{% load i18n %}
{% block extra_js %}
<script language="Javascript">
// document.getElementById("id_observacao").readOnly = true;
function recuperar_materia() {
var tipo_materia = $("#id_tipo").val()
var numero_materia = $("#id_numero").val()
var ano_materia = $("#id_ano").val()
if (tipo_materia && numero_materia && ano_materia){
$.get("/sessao/recuperar-materia",
{ tipo_materia: tipo_materia, numero_materia: numero_materia, ano_materia: ano_materia },
function(data, status) {
if ($(".ementa-materia").length === 0){
$("#div_id_tipo").closest('.row').after($('<div class="row"/>').append($('<div class="col-12"/>').append(
$('<div class="alert alert-info ementa-materia"/>').html(data.ementa)
)))
}
else {
$('.ementa-materia').html(data.ementa)
}
});
}
}
var fields = ["#id_tipo", "#id_numero", "#id_ano"];
for (i = 0; i < fields.length; i++){
$(fields[i]).change(function() {
recuperar_materia();
});
}
recuperar_materia();
$(document).ready( function() {
});
</script>
{% endblock %}
Loading…
Cancel
Save