Browse Source

Adicionar Adicionar Anexado no mód. Doc. Adm.

Alterações iniciais - Anexados em Lote
pull/2630/head
João Rodrigues 7 years ago
committed by João Matheus
parent
commit
9ac5b34109
  1. 4
      sapl/materia/forms.py
  2. 2
      sapl/materia/views.py
  3. 98
      sapl/protocoloadm/forms.py
  4. 35
      sapl/protocoloadm/migrations/0018_auto_20190314_1532.py
  5. 41
      sapl/protocoloadm/models.py
  6. 7
      sapl/protocoloadm/urls.py
  7. 102
      sapl/protocoloadm/views.py
  8. 1
      sapl/rules/map_rules.py
  9. 13
      sapl/templates/protocoloadm/anexado_list.html
  10. 13
      sapl/templates/protocoloadm/layouts.yaml
  11. 2
      sapl/templates/protocoloadm/subnav.yaml

4
sapl/materia/forms.py

@ -798,8 +798,8 @@ class AnexadaForm(ModelForm):
ano=cleaned_data['ano'], ano=cleaned_data['ano'],
tipo=cleaned_data['tipo']) tipo=cleaned_data['tipo'])
except ObjectDoesNotExist: except ObjectDoesNotExist:
msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.' msg = _('A Matéria Legislativa a ser anexada (numero={}, ano={}, tipo={}) não existe no cadastro'
.format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano'])) ' de matérias legislativas.'.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
self.logger.error("A matéria a ser anexada não existe no cadastro" self.logger.error("A matéria a ser anexada não existe no cadastro"
" de matérias legislativas.") " de matérias legislativas.")
raise ValidationError(msg) raise ValidationError(msg)

2
sapl/materia/views.py

@ -2108,7 +2108,7 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
anexada.data_desanexacao = data_desanexacao anexada.data_desanexacao = data_desanexacao
anexada.save() anexada.save()
msg = _('Materia(s) anexada(s).') msg = _('Matéria(s) anexada(s).')
messages.add_message(request, messages.SUCCESS, msg) messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)

98
sapl/protocoloadm/forms.py

@ -29,7 +29,7 @@ from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter,
from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo, DocumentoAdministrativo,
Protocolo, TipoDocumentoAdministrativo, Protocolo, TipoDocumentoAdministrativo,
TramitacaoAdministrativo) TramitacaoAdministrativo, Anexado)
TIPOS_PROTOCOLO = [('0', 'Recebido'), ('1', 'Enviado'), TIPOS_PROTOCOLO = [('0', 'Recebido'), ('1', 'Enviado'),
@ -781,6 +781,102 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm):
return self.cleaned_data return self.cleaned_data
class AnexadoForm(ModelForm):
logger = logging.getLogger(__name__)
tipo = forms.ModelChoiceField(
label='Tipo',
required=True,
queryset=TipoDocumentoAdministrativo.objects.all(),
empty_label='Selecione'
)
numero = forms.CharField(label='Número', required=True)
ano = forms.CharField(label='Ano', required=True)
def __init__(self, *args, **kwargs):
return super(AnexadoForm, self).__init__(*args, **kwargs)
def clean(self):
super(AnexadoForm, self).clean()
if not self.is_valid():
return self.cleaned_data
cleaned_data = self.cleaned_data
try:
self.logger.info(
"Tentando obter objeto DocumentoAdministrativo (numero={}, ano={}, tipo={})."
.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo'])
)
documento_anexado = DocumentoAdministrativo.objects.get(
numero=cleaned_data['numero'],
ano=cleaned_data['ano'],
tipo=cleaned_data['tipo']
)
except ObjectDoesNotExist:
msg = _('O Documento Administrativo a ser anexado (numero={}, ano={}, tipo={}) não existe no cadastro'
' de documentos administrativos.'.format(cleaned_data['numero'], cleaned_data['ano'], cleaned_data['tipo']))
self.logger.error("O documento a ser anexado não existe no cadastro"
" de documentos administrativos")
raise ValidationError(msg)
documento_principal = self.instance.documento_principal
if documento_principal == documento_anexado:
self.logger.error("O documento não pode ser anexado a si mesmo.")
raise ValidationError(_("O documento não pode ser anexado a si mesmo"))
is_anexado = Anexado.objects.filter(documento_principal=documento_principal,
documento_anexado=documento_anexado
).exists()
if is_anexado:
self.logger.error("Documento já se encontra anexado.")
raise ValidationError(_('Documento já se encontra anexado'))
cleaned_data['documento_anexado'] = documento_anexado
return cleaned_data
def save(self, commit=False):
anexado = super(AnexadoForm, self).save(commit)
anexado.documento_anexado = self.cleaned_data['documento_anexado']
anexado.save()
return anexado
class Meta:
model = Anexado
fields = ['tipo', 'numero', 'ano', 'data_anexacao', 'data_desanexacao']
class AnexadoEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = DocumentoAdministrativo
fields = ['tipo', 'data']
def __init__(self, *args, **kwargs):
super(AnexadoEmLoteFilterSet, self).__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Documento'
self.filters['data'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data'].required = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Documentos'),
row1, row2, form_actions(label='Pesquisar'))
)
class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm): class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

35
sapl/protocoloadm/migrations/0018_auto_20190314_1532.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-03-14 18:32
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('protocoloadm', '0017_merge_20190121_1552'),
]
operations = [
migrations.CreateModel(
name='Anexado',
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_anexado', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documento_anexado_set', to='protocoloadm.DocumentoAdministrativo', verbose_name='Documento Anexado')),
('documento_principal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documento_principal_set', to='protocoloadm.DocumentoAdministrativo', verbose_name='Documento Principal')),
],
options={
'verbose_name': 'Anexado',
'verbose_name_plural': 'Anexados',
},
),
migrations.AddField(
model_name='documentoadministrativo',
name='anexados',
field=models.ManyToManyField(blank=True, related_name='anexo_de', through='protocoloadm.Anexado', to='protocoloadm.DocumentoAdministrativo'),
),
]

41
sapl/protocoloadm/models.py

@ -170,6 +170,18 @@ class DocumentoAdministrativo(models.Model):
verbose_name=_('Acesso Restrito'), verbose_name=_('Acesso Restrito'),
blank=True) blank=True)
anexados = models.ManyToManyField(
'self',
blank=True,
through='Anexado',
symmetrical=False,
related_name='anexo_de',
through_fields=(
'documento_principal',
'documento_anexado'
)
)
class Meta: class Meta:
verbose_name = _('Documento Administrativo') verbose_name = _('Documento Administrativo')
verbose_name_plural = _('Documentos Administrativos') verbose_name_plural = _('Documentos Administrativos')
@ -317,6 +329,35 @@ class TramitacaoAdministrativo(models.Model):
} }
@reversion.register()
class Anexado(models.Model):
documento_principal = models.ForeignKey(
DocumentoAdministrativo, related_name='documento_principal_set',
on_delete = models.CASCADE,
verbose_name=_('Documento Principal')
)
documento_anexado = models.ForeignKey(
DocumentoAdministrativo, related_name='documento_anexado_set',
on_delete = models.CASCADE,
verbose_name=_('Documento Anexado')
)
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 = _('Anexado')
verbose_name_plural = _('Anexados')
def __str__(self):
return _('Principal: %(documento_principal)s'
' - Anexada: %(documento_anexado)s') % {
'documento_principal': self.documento_principal,
'documento_anexado': self.documento_anexado
}
@reversion.register() @reversion.register()
class AcompanhamentoDocumento(models.Model): class AcompanhamentoDocumento(models.Model):
usuario = models.CharField(max_length=50) usuario = models.CharField(max_length=50)

7
sapl/protocoloadm/urls.py

@ -21,7 +21,8 @@ from sapl.protocoloadm.views import (AcompanhamentoDocumentoView,
atualizar_numero_documento, atualizar_numero_documento,
doc_texto_integral, doc_texto_integral,
DesvincularDocumentoView, DesvincularDocumentoView,
DesvincularMateriaView) DesvincularMateriaView,
AnexadoCrud, DocumentoAnexadoEmLoteView)
from .apps import AppConfig from .apps import AppConfig
@ -30,6 +31,7 @@ app_name = AppConfig.name
urlpatterns_documento_administrativo = [ urlpatterns_documento_administrativo = [
url(r'^docadm/', url(r'^docadm/',
include(DocumentoAdministrativoCrud.get_urls() + include(DocumentoAdministrativoCrud.get_urls() +
AnexadoCrud.get_urls() +
TramitacaoAdmCrud.get_urls() + TramitacaoAdmCrud.get_urls() +
DocumentoAcessorioAdministrativoCrud.get_urls())), DocumentoAcessorioAdministrativoCrud.get_urls())),
@ -38,6 +40,9 @@ urlpatterns_documento_administrativo = [
url(r'^docadm/texto_integral/(?P<pk>\d+)$', doc_texto_integral, url(r'^docadm/texto_integral/(?P<pk>\d+)$', doc_texto_integral,
name='doc_texto_integral'), name='doc_texto_integral'),
url(r'^docadm/(?P<pk>\d+)/anexado_em_lote', DocumentoAnexadoEmLoteView.as_view(),
name='anexado_em_lote'),
] ]
urlpatterns_protocolo = [ urlpatterns_protocolo = [

102
sapl/protocoloadm/views.py

@ -17,7 +17,7 @@ from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, CreateView from django.views.generic import ListView, CreateView, UpdateView
from django.views.generic.base import RedirectView, TemplateView from django.views.generic.base import RedirectView, TemplateView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
@ -27,7 +27,8 @@ from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
from sapl.base.signals import tramitacao_signal from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination,
RP_LIST, RP_DETAIL)
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.materia.views import gerar_pdf_impressos from sapl.materia.views import gerar_pdf_impressos
from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.parlamentares.models import Legislatura, Parlamentar
@ -44,10 +45,11 @@ from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm,
TramitacaoAdmEditForm, TramitacaoAdmForm, TramitacaoAdmEditForm, TramitacaoAdmForm,
DesvincularDocumentoForm, DesvincularMateriaForm, DesvincularDocumentoForm, DesvincularMateriaForm,
filtra_tramitacao_adm_destino_and_status, filtra_tramitacao_adm_destino_and_status,
filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status) filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status,
AnexadoForm, AnexadoEmLoteFilterSet)
from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo, StatusTramitacaoAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo) TipoDocumentoAdministrativo, TramitacaoAdministrativo, Anexado)
TipoDocumentoAdministrativoCrud = CrudAux.build( TipoDocumentoAdministrativoCrud = CrudAux.build(
@ -941,6 +943,98 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
return self.render_to_response(context) return self.render_to_response(context)
class AnexadoCrud(MasterDetailCrud):
model = Anexado
parent_field = 'documento_principal'
help_topic = 'documento_anexado'
public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['documento_anexado', 'data_anexacao']
class CreateView(MasterDetailCrud.CreateView):
form_class = AnexadoForm
class UpdateView(MasterDetailCrud.UpdateView):
form_class = AnexadoForm
def get_initial(self):
initial = super(UpdateView, self).get_initial()
initial['tipo'] = self.object.documento_anexado.tipo.id
initial['numero'] = self.object.documento_anexado.numero
initial['ano'] = self.object.documento_anexado.ano
return initial
class DetailView(MasterDetailCrud.DetailView):
@property
def layout_key(self):
return 'AnexadoDetail'
class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AnexadoEmLoteFilterSet
template_name = 'protocoloadm/em_lote/anexado.html'
permission_required = ('protocoloadm.list_documentoadministrativo', ) ##d
def get_context_data(self, **kwargs):
context = super(
DocumentoAnexadoEmLoteView,self
).get_context_data(**kwargs)
context['root_pk'] = self.kwargs['pk']
context['subnav_template_name'] = 'protocoloadm/subnav.yaml'
context['title'] = _('Documentos Anexados em Lote')
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['object_List'] = context['object_list'].order_by(
'numero', '-ano'
)
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):
marcados = request.POST.getlist('documento_id')
if len(marcados) == 0:
msg =_('Nenhum documento foi selecionado')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
data_anexacao = datetime.strptime(
request.POST['data_anexacao'], "%d/%m/%Y"
).date()
if request.POST['data_desanexacao'] == '':
data_desanexacao = None
else:
data_desanexacao = datetime.strptime(
request.POST['data_desanexacao'], "%d/%m/%Y"
).date()
principal = DocumentoAdministrativo.objects.get(pk = kwargs['pk'])
for documento in DocumentoAdministrativo.objects.filter(id__in = marcados):
anexado = Anexado()
anexado.documento_principal = principal
anexado.documento_anexado = documento
anexado.data_anexacao = data_anexacao
anexado.data_desanexacao = data_desanexacao
anexado.save()
msg = _('Documento(s) anexado(s).')
messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs)
class TramitacaoAdmCrud(MasterDetailCrud): class TramitacaoAdmCrud(MasterDetailCrud):
model = TramitacaoAdministrativo model = TramitacaoAdministrativo
parent_field = 'documento' parent_field = 'documento'

1
sapl/rules/map_rules.py

@ -60,6 +60,7 @@ rules_group_administrativo = {
'can_access_impressos'], __perms_publicas__), 'can_access_impressos'], __perms_publicas__),
# TODO: tratar em sapl.api a questão de ostencivo e restritivo # TODO: tratar em sapl.api a questão de ostencivo e restritivo
(protocoloadm.DocumentoAdministrativo, __base__, set()), (protocoloadm.DocumentoAdministrativo, __base__, set()),
(protocoloadm.Anexado, __base__, set()),
(protocoloadm.DocumentoAcessorioAdministrativo, __base__, set()), (protocoloadm.DocumentoAcessorioAdministrativo, __base__, set()),
(protocoloadm.TramitacaoAdministrativo, __base__, set()), (protocoloadm.TramitacaoAdministrativo, __base__, set()),
] ]

13
sapl/templates/protocoloadm/anexado_list.html

@ -0,0 +1,13 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load common_tags %}
{% block more_buttons %}
{% if perms|get_add_perm:view %}
<a href="{% url 'sapl.protocoloadm:anexado_em_lote' root_pk %}" class="btn btn-outline-primary">
{% trans "Adicionar Anexado em Lote" %}
</a>
{% endif %}
{% endblock more_buttons %}

13
sapl/templates/protocoloadm/layouts.yaml

@ -10,6 +10,8 @@ DocumentoAdministrativo:
- assunto - assunto
- interessado tramitacao - interessado tramitacao
- texto_integral - texto_integral
- documento_anexado_set__documento_principal|m2m_urlize_for_detail
- documento_principal_set__documento_anexado|m2m_urlize_for_detail
{% trans 'Outras Informações' %}: {% trans 'Outras Informações' %}:
- numero_externo - numero_externo
- dias_prazo data_fim_prazo - dias_prazo data_fim_prazo
@ -33,6 +35,17 @@ TramitacaoAdministrativo:
- data_encaminhamento data_fim_prazo - data_encaminhamento data_fim_prazo
- texto - texto
Anexado:
{% trans 'Documento Anexado' %}:
- tipo numero ano
- data_anexacao data_desanexacao
AnexadoDetail:
{% trans 'Documento Anexado' %}:
- documento_principal|fk_urlize_for_detail
- documento_anexado|fk_urlize_for_detail
- data_anexacao data_desanexacao
Protocolo: Protocolo:
{% trans 'Indentificação Documento' %}: {% trans 'Indentificação Documento' %}:
- tipo_protocolo - tipo_protocolo

2
sapl/templates/protocoloadm/subnav.yaml

@ -1,6 +1,8 @@
{% load i18n common_tags %} {% load i18n common_tags %}
- title: {% trans 'Início' %} - title: {% trans 'Início' %}
url: documentoadministrativo_detail url: documentoadministrativo_detail
- title: {% trans 'Anexado' %}
url: anexado_list
- title: {% trans 'Tramitação' %} - title: {% trans 'Tramitação' %}
url: tramitacaoadministrativo_list url: tramitacaoadministrativo_list
- title: {% trans 'Documento Acessório' %} - title: {% trans 'Documento Acessório' %}

Loading…
Cancel
Save