Browse Source

Impl Issue #3326 criando vínculo entre matérias e docs adms (#3586)

* cria model VinculoDocAdminMateria

* impl display em detailview de matéria e documentos

* add unique_together a VinculoDocAdminMateria

* impl crud de vinculodocadminmateria

* impl vinculo em lote de docadm com matérias
pull/3588/head
LeandroJataí 2 years ago
committed by GitHub
parent
commit
63ad0dfae5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      sapl/crispy_layout_mixin.py
  2. 11
      sapl/crud/base.py
  3. 104
      sapl/protocoloadm/forms.py
  4. 35
      sapl/protocoloadm/migrations/0041_auto_20220804_2239.py
  5. 23
      sapl/protocoloadm/migrations/0042_auto_20220805_1236.py
  6. 61
      sapl/protocoloadm/models.py
  7. 9
      sapl/protocoloadm/urls.py
  8. 158
      sapl/protocoloadm/views.py
  9. 35
      sapl/templates/materia/materialegislativa_detail.html
  10. 24
      sapl/templates/protocoloadm/documentoadministrativo_detail.html
  11. 74
      sapl/templates/protocoloadm/em_lote/vinculodocadminmateria.html
  12. 10
      sapl/templates/protocoloadm/layouts.yaml
  13. 2
      sapl/templates/protocoloadm/subnav.yaml
  14. 38
      sapl/templates/protocoloadm/vinculodocadminmateria_form.html
  15. 14
      sapl/templates/protocoloadm/vinculodocadminmateria_list.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):

104
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,100 @@ 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):
vinculo = super().save(commit)
vinculo.materia = self.cleaned_data['materia']
vinculo.save()
return vinculo
class VinculoDocAdminMateriaEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['data_apresentacao'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Matérias'),
row1, row2, form_actions(label='Pesquisar')))

35
sapl/protocoloadm/migrations/0041_auto_20220804_2239.py

@ -0,0 +1,35 @@
# Generated by Django 2.2.28 on 2022-08-05 01:39
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('materia', '0081_auto_20220321_0934'),
('protocoloadm', '0040_auto_20220321_0934'),
]
operations = [
migrations.CreateModel(
name='VinculoDocAdminMateria',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('data_anexacao', models.DateField(verbose_name='Data Anexação')),
('data_desanexacao', models.DateField(blank=True, null=True, verbose_name='Data Desanexação')),
('documento', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materialegislativa_vinculada_set', to='protocoloadm.DocumentoAdministrativo', verbose_name='Documento Administrativo')),
('materia', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documentoadministrativo_vinculado_set', to='materia.MateriaLegislativa', verbose_name='Matéria Legislativa')),
],
options={
'verbose_name': 'Vinculo entre Documento Administrativo e Matéria Legislativa',
'verbose_name_plural': 'Vinculos entre Documento Administrativo e Matéria Legislativa',
'ordering': ('id',),
},
),
migrations.AddField(
model_name='documentoadministrativo',
name='materiasvinculadas',
field=models.ManyToManyField(blank=True, related_name='docadmsvinculados', through='protocoloadm.VinculoDocAdminMateria', to='materia.MateriaLegislativa'),
),
]

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')},
),
]

61
sapl/protocoloadm/models.py

@ -5,7 +5,8 @@ from model_utils import Choices
import reversion
from sapl.base.models import Autor
from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao
from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao,\
MateriaLegislativa
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path,
get_settings_auth_user_model,
OverwriteStorage)
@ -91,7 +92,8 @@ class Protocolo(models.Model):
blank=True
)
de_proposicao = models.BooleanField(default=False)
# Não foi utilizado auto_now_add=True em timestamp porque ele usa datetime.now que não é timezone aware.
# Não foi utilizado auto_now_add=True em timestamp porque ele usa
# datetime.now que não é timezone aware.
timestamp = models.DateTimeField(
null=True,
blank=True,
@ -214,6 +216,17 @@ class DocumentoAdministrativo(models.Model):
)
)
materiasvinculadas = models.ManyToManyField(
MateriaLegislativa,
blank=True,
through='VinculoDocAdminMateria',
related_name='docadmvinculados',
through_fields=(
'documento',
'materia'
)
)
user = models.ForeignKey(
get_settings_auth_user_model(),
verbose_name=_('Usuário'),
@ -242,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)
@ -436,6 +457,42 @@ class Anexado(models.Model):
}
@reversion.register()
class VinculoDocAdminMateria(models.Model):
documento = models.ForeignKey(
DocumentoAdministrativo, related_name='materialegislativa_vinculada_set',
on_delete=models.CASCADE,
verbose_name=_('Documento Administrativo')
)
materia = models.ForeignKey(
MateriaLegislativa, related_name='documentoadministrativo_vinculado_set',
on_delete=models.CASCADE,
verbose_name=_('Matéria Legislativa')
)
data_anexacao = models.DateField(verbose_name=_('Data Anexação'))
data_desanexacao = models.DateField(
blank=True, null=True, verbose_name=_('Data Desanexação')
)
class Meta:
verbose_name = _(
'Vinculo entre Documento Administrativo e Matéria Legislativa')
verbose_name_plural = _(
'Vinculos entre Documento Administrativo e Matéria Legislativa')
ordering = ('id',)
unique_together = (
('documento', 'materia'),
)
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):
usuario = models.CharField(max_length=50)

9
sapl/protocoloadm/urls.py

@ -25,7 +25,9 @@ from sapl.protocoloadm.views import (AcompanhamentoDocumentoView,
AnexadoCrud, DocumentoAnexadoEmLoteView,
PrimeiraTramitacaoEmLoteAdmView,
TramitacaoEmLoteAdmView,
apaga_protocolos_view)
apaga_protocolos_view,
VinculoDocAdminMateriaCrud,
VinculoDocAdminMateriaEmLoteView)
from .apps import AppConfig
@ -36,7 +38,8 @@ urlpatterns_documento_administrativo = [
include(DocumentoAdministrativoCrud.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'),
@ -46,6 +49,8 @@ urlpatterns_documento_administrativo = [
url(r'^docadm/(?P<pk>\d+)/anexado_em_lote', DocumentoAnexadoEmLoteView.as_view(),
name='anexado_em_lote'),
url(r'^docadm/(?P<pk>\d+)/vinculo-em-lote', VinculoDocAdminMateriaEmLoteView.as_view(),
name='vinculodocadminmateria_em_lote'),
]
urlpatterns_protocolo = [

158
sapl/protocoloadm/views.py

@ -35,7 +35,10 @@ 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,\
VinculoDocAdminMateriaEmLoteFilterSet
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,
@ -1156,7 +1159,6 @@ class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
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 ''
@ -1300,7 +1302,6 @@ class TramitacaoAdmCrud(MasterDetailCrud):
return initial
class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView):
def get_queryset(self):
@ -1751,3 +1752,154 @@ 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 = VinculoDocAdminMateriaEmLoteFilterSet
template_name = 'protocoloadm/em_lote/vinculodocadminmateria.html'
permission_required = ('protocoloadm.add_documentoadministrativo',)
def get_context_data(self, **kwargs):
context = super(VinculoDocAdminMateriaEmLoteView,
self).get_context_data(**kwargs)
context['root_pk'] = self.kwargs['pk']
context['subnav_template_name'] = 'protocoloadm/subnav.yaml'
context['title'] = _('Matérias Vinculadas 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')
documento = DocumentoAdministrativo.objects.get(
pk=self.kwargs['pk'])
not_list = [self.kwargs['pk']] + \
[m for m in documento.materiasvinculadas.values_list(
'id', flat=True)]
context['object_list'] = context['object_list'].exclude(
pk__in=not_list)
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)
documento = DocumentoAdministrativo.objects.get(pk=kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in=marcadas):
v = VinculoDocAdminMateria()
v.documento = documento
v.materia = materia
v.data_anexacao = data_anexacao
v.data_desanexacao = data_desanexacao
v.save()
msg = _('Matéria(s) vinculadas(s).')
messages.add_message(request, messages.SUCCESS, msg)
success_url = reverse('sapl.protocoloadm:vinculodocadminmateria_list',
kwargs={'pk': kwargs['pk']})
return HttpResponseRedirect(success_url)

35
sapl/templates/materia/materialegislativa_detail.html

@ -1,6 +1,5 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% load tz %}
{% load i18n tz common_tags %}
{% block sub_actions %}
{{ block.super }}
@ -48,6 +47,38 @@
{{ object.normajuridica_set.last }}</a>
</div>
{% endif %}
{% if object.docadmvinculados.all.exists %}
{% if "documentos_administrativos"|get_config_attr == 'O' or "documentos_administrativos"|get_config_attr == 'R' and not user.is_anonymous %}
<div class="row">
<div class="col-12">
<div id="div_id_docadmvinculados" class="form-group">
<p class="control-label">Documentos Administrativos Públicos Vinculados a Matéria</p>
<div class="controls">
<div class="form-control-static">
{% for vinculodocadmmateria in object.documentoadministrativo_vinculado_set.all %}
{% if not vinculodocadmmateria.documento.restrito or vinculodocadmmateria.documento.restrito and not user.is_anonymous %}
<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.epigrafe }}
</a>
<br>{{ vinculodocadmmateria.documento.assunto}}
{% if vinculodocadmmateria.documento.restrito %}
<small class="text-danger">
(Documento Restrito)
</small>
{% endif %}
{% endif %}
{% if not forloop.last %}<hr>{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% if object.audienciapublica_set.exists %}
<p class="control-label">&emsp; Audiência(s) Pública(s)</p>
<div class="actions btn-group btn-group-sm" role="group">

24
sapl/templates/protocoloadm/documentoadministrativo_detail.html

@ -3,6 +3,30 @@
{% block detail_content %}
{{ block.super }}
{% if documentoadministrativo.materiasvinculadas.all.exists %}
<div class="row">
<div class="col-12">
<div id="div_id_materiasvinculadas" class="form-group">
<p class="control-label">Matérias Legislativas Vinculadas</p>
<div class="controls">
<div class="form-control-static">
{% for vinculodocadmmateria in object.materialegislativa_vinculada_set.all %}
<strong>Data Anexação:</strong> {{vinculodocadmmateria.data_anexacao}} {% if vinculodocadmmateria.data_desanexacao %} - {{vinculodocadmmateria.data_desanexacao}}{% endif %}
<br><strong>Matéria:</strong>
<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>
</div>
</div>
</div>
{% endif %}
{% if user.is_superuser %}
<div class="row">
{% if documentoadministrativo.user %}

74
sapl/templates/protocoloadm/em_lote/vinculodocadminmateria.html

@ -0,0 +1,74 @@
{% extends "crud/detail.html" %}
{% load i18n crispy_forms_tags %}
{% block actions %}{% endblock %}
{% block detail_content %}
{% if not show_results %}
{% crispy filter.form %}
{% endif %}
{% if show_results %}
{% if numero_res > 0 %}
{% if numero_res == 1 %}
<h3 style="text-align: right;">{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3>
{% else %}
<h3 style="text-align: right;">Foram encontradas {{ numero_res }} matérias.</h3>
{% endif %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label>Data Anexação*</label><input type="text" name="data_anexacao" class="form-control dateinput" required="True">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>Data Desanexação</label><input type="text" name="data_desanexacao" class="form-control dateinput">
</div>
</div>
</div>
</fieldset>
<br />
<fieldset>
<legend>Matérias para Vincular em Lote</legend>
<table class="table table-striped table-hover">
<div class="controls">
<div class="checkbox">
<label for="id_check_all"><input type="checkbox" id="id_check_all" onchange="checkAll(this)" /> Marcar/Desmarcar Todos</label>
</div>
</div>
<thead><tr><th>Matéria</th></tr></thead>
<tbody>
{% for materia in object_list %}
<tr>
<td class="p-0">
<label for="mat_{{materia.id}}" class="d-flex w-100 p-3">
<input type="checkbox" id="mat_{{materia.id}}" name="materia_id" value="{{materia.id}}" {% if check %} checked {% endif %}/>
{{materia.tipo.sigla}} {{materia.numero}}/{{materia.ano}} - {{materia.tipo.descricao}}
</label>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
<input type="submit" value="Salvar" class="btn btn-primary"S>
</form>
{% else %}
<tr><td><h3 style="text-align: right;">Nenhuma matéria encontrada.</h3></td></tr>
{% endif %}
{% endif %}
{% endblock detail_content %}
{% block extra_js %}
<script language="JavaScript">
function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id');
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked;
}
}
</script>
{% endblock %}

10
sapl/templates/protocoloadm/layouts.yaml

@ -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 %}

14
sapl/templates/protocoloadm/vinculodocadminmateria_list.html

@ -0,0 +1,14 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load common_tags %}
{% block more_buttons %}
{% if perms|get_add_perm:view %}
<a href="{% url 'sapl.protocoloadm:vinculodocadminmateria_em_lote' root_pk %}" class="btn btn-outline-primary">
{% trans "Adicionar Vínculos em Lote" %}
</a>
{% endif %}
{% endblock more_buttons %}
Loading…
Cancel
Save