Browse Source

Merge branch '3.1.x' into 2719-data_amdata_d

pull/2721/head
Victor Fabre 7 years ago
committed by GitHub
parent
commit
cf4e1cdc98
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      sapl/api/views.py
  2. 26
      sapl/materia/forms.py
  3. 36
      sapl/materia/views.py
  4. 122
      sapl/protocoloadm/forms.py
  5. 35
      sapl/protocoloadm/migrations/0018_auto_20190314_1532.py
  6. 42
      sapl/protocoloadm/models.py
  7. 7
      sapl/protocoloadm/urls.py
  8. 146
      sapl/protocoloadm/views.py
  9. 1
      sapl/rules/map_rules.py
  10. 2
      sapl/sessao/migrations/0036_auto_20190412_1106.py
  11. 6
      sapl/templates/materia/em_lote/anexada.html
  12. 13
      sapl/templates/protocoloadm/anexado_list.html
  13. 5
      sapl/templates/protocoloadm/em_lote/anexado.html
  14. 13
      sapl/templates/protocoloadm/layouts.yaml
  15. 2
      sapl/templates/protocoloadm/subnav.yaml
  16. 98
      sapl/templates/sessao/painel.html

16
sapl/api/views.py

@ -26,7 +26,7 @@ from sapl.materia.models import Proposicao, TipoMateriaLegislativa,\
MateriaLegislativa, Tramitacao MateriaLegislativa, Tramitacao
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import DocumentoAdministrativo,\ from sapl.protocoloadm.models import DocumentoAdministrativo,\
DocumentoAcessorioAdministrativo, TramitacaoAdministrativo DocumentoAcessorioAdministrativo, TramitacaoAdministrativo, Anexado
from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao
from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria
@ -489,6 +489,20 @@ class _TramitacaoAdministrativoViewSet(BusinessRulesNotImplementedMixin):
return qs return qs
@customize(Anexado)
class _AnexadoViewSet(BusinessRulesNotImplementedMixin):
permission_classes = (
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission, )
def get_queryset(self):
qs = super().get_queryset()
if self.request.user.is_anonymous():
qs = qs.exclude(documento__restrito=True)
return qs
@customize(SessaoPlenaria) @customize(SessaoPlenaria)
class _SessaoPlenariaViewSet: class _SessaoPlenariaViewSet:

26
sapl/materia/forms.py

@ -825,6 +825,26 @@ class AnexadaForm(ModelForm):
self.logger.error("Matéria já se encontra anexada.") self.logger.error("Matéria já se encontra anexada.")
raise ValidationError(_('Matéria já se encontra anexada')) raise ValidationError(_('Matéria já se encontra anexada'))
ciclico = False
anexadas_anexada = Anexada.objects.filter(materia_principal=materia_anexada)
while anexadas_anexada and not ciclico:
anexadas = []
for anexa in anexadas_anexada:
if materia_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 ciclico:
self.logger.error("A matéria não pode ser anexada por uma de suas anexadas.")
raise ValidationError(_("A matéria não pode ser anexada por uma de suas anexadas."))
cleaned_data['materia_anexada'] = materia_anexada cleaned_data['materia_anexada'] = materia_anexada
return cleaned_data return cleaned_data
@ -1748,7 +1768,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
required=False, widget=widgets.TextInput( required=False, widget=widgets.TextInput(
attrs={'readonly': 'readonly'})) attrs={'readonly': 'readonly'}))
regime_tramitacao = forms.ModelChoiceField( regime_tramitacao = forms.ModelChoiceField(label="Regime de tramitação",
required=False, queryset=RegimeTramitacao.objects.all()) required=False, queryset=RegimeTramitacao.objects.all())
gerar_protocolo = forms.ChoiceField( gerar_protocolo = forms.ChoiceField(
@ -1814,6 +1834,10 @@ class ConfirmarProposicaoForm(ProposicaoForm):
# esta chamada isola o __init__ de ProposicaoForm # esta chamada isola o __init__ de ProposicaoForm
super(ProposicaoForm, self).__init__(*args, **kwargs) super(ProposicaoForm, self).__init__(*args, **kwargs)
if self.instance.tipo.content_type.model_class() ==\
TipoMateriaLegislativa:
self.fields['regime_tramitacao'].required = True
fields = [ fields = [
Fieldset( Fieldset(
_('Dados Básicos'), _('Dados Básicos'),

36
sapl/materia/views.py

@ -2070,11 +2070,39 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
qr = self.request.GET.copy() qr = self.request.GET.copy()
context['object_list'] = context['object_list'].order_by( context['object_list'] = context['object_list'].order_by(
'ano', 'numero') 'numero', '-ano')
principal = MateriaLegislativa.objects.get(pk=self.kwargs['pk']) principal = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
not_list = [self.kwargs['pk']] + \ not_list = [self.kwargs['pk']] + \
[m for m in principal.materia_principal_set.all().values_list('materia_anexada_id', flat=True)] [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['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['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr) context['show_results'] = show_results_filter_set(qr)
@ -2120,9 +2148,11 @@ 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)
sucess_url = reverse('sapl_index') + 'materia/' + kwargs['pk'] + '/anexada'
return HttpResponseRedirect(sucess_url)
class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):

122
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,126 @@ 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
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("A data de anexação não pode ser posterior a data de desanexação.")
raise ValidationError(_("A data de anexação não pode ser posterior a data de desanexação."))
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 {} {}/{} não existe no cadastro de documentos administrativos.'
.format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano']))
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
).exclude(pk=self.instance.pk).exists()
if is_anexado:
self.logger.error("Documento já se encontra anexado.")
raise ValidationError(_('Documento já se encontra anexado'))
ciclico = False
anexados_anexado = Anexado.objects.filter(documento_principal=documento_anexado)
while(anexados_anexado and not ciclico):
anexados = []
for anexo in anexados_anexado:
if documento_principal == anexo.documento_anexado:
ciclico = True
else:
for a in Anexado.objects.filter(documento_principal=anexo.documento_anexado):
anexados.append(a)
anexados_anexado = anexados
if ciclico:
self.logger.error("O documento não pode ser anexado por um de seus anexados.")
raise ValidationError(_('O documento não pode ser anexado por um de seus anexados'))
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)*'
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'),
),
]

42
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,36 @@ 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 _('Anexado: %(documento_anexado_tipo)s %(documento_anexado_numero)s'
'/%(documento_anexado_ano)s\n') % {
'documento_anexado_tipo': self.documento_anexado.tipo,
'documento_anexado_numero': self.documento_anexado.numero,
'documento_anexado_ano': self.documento_anexado.ano
}
@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 = [

146
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,142 @@ 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.add_anexado', )
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')
# Verifica se os campos foram preenchidos
if not self.request.GET.get('tipo', " "):
msg =_('Por favor, selecione um tipo de documento.')
messages.add_message(self.request, messages.ERROR, msg)
if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "):
msg =_('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
if not self.request.GET.get('data_0', " ") or not self.request.GET.get('data_1', " "):
msg =_('Por favor, preencha as datas.')
messages.add_message(self.request, messages.ERROR, msg)
return context
qr = self.request.GET.copy()
context['temp_object_list'] = context['object_list'].order_by(
'numero', '-ano'
)
context['object_list'] = []
for obj in context['temp_object_list']:
if not obj.pk == int(context['root_pk']):
documento_principal = DocumentoAdministrativo.objects.get(id=context['root_pk'])
documento_anexado = obj
is_anexado = Anexado.objects.filter(documento_principal=documento_principal,
documento_anexado=documento_anexado).exists()
if not is_anexado:
ciclico = False
anexados_anexado = Anexado.objects.filter(documento_principal=documento_anexado)
while anexados_anexado and not ciclico:
anexados = []
for anexo in anexados_anexado:
if documento_principal == anexo.documento_anexado:
ciclico = True
else:
for a in Anexado.objects.filter(documento_principal=anexo.documento_anexado):
anexados.append(a)
anexados_anexado = anexados
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):
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)
success_url = reverse('sapl_index') + 'docadm/' + kwargs['pk'] + '/anexado'
return HttpResponseRedirect(success_url)
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()),
] ]

2
sapl/sessao/migrations/0036_auto_20190410_0836.py → sapl/sessao/migrations/0036_auto_20190412_1106.py

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-04-10 11:36 # Generated by Django 1.11.20 on 2019-04-12 14:06
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

6
sapl/templates/materia/em_lote/anexada.html

@ -8,11 +8,11 @@
{% endif %} {% endif %}
{% if show_results %} {% if show_results %}
{% if object_list.count > 0 %} {% if numero_res > 0 %}
{% if object_list.count == 1 %} {% if numero_res == 1 %}
<h3 style="text-align: right;">{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3> <h3 style="text-align: right;">{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3>
{% else %} {% else %}
<h3 style="text-align: right;">{% blocktrans with object_list.count as total_materias %}Foram encontradas {{total_materias}} matérias.{% endblocktrans %}</h3> <h3 style="text-align: right;">Foram encontradas {{ numero_res }} matérias.</h3>
{% endif %} {% endif %}
<form method="POST" enctype="multipart/form-data"> <form method="POST" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}

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

5
sapl/templates/protocoloadm/em_lote/anexado.html

@ -54,7 +54,7 @@
<tr> <tr>
<td> <td>
<input type="checkbox" name="documento_id" value="{{documento.id}}" {% if check %} checked {% endif %}/> <input type="checkbox" name="documento_id" value="{{documento.id}}" {% if check %} checked {% endif %}/>
{{documento.tipo.sigla}} {{documento.numero}}/{{documento.ano}} - {{documento.tipo.descricao}} <a href="{% url 'sapl_index' %}docadm/{{documento.pk}}">{{documento.tipo.sigla}} {{documento.numero}}/{{documento.ano}} - {{documento.tipo.descricao}}</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -63,6 +63,7 @@
</fieldset> </fieldset>
<input type="submit" value="Salvar" class="btn btn-primary"S> <input type="submit" value="Salvar" class="btn btn-primary"S>
</form> </form>
<br/>
{% else %} {% else %}
<tr> <tr>
<td> <td>
@ -75,7 +76,7 @@
{% block extra_js %} {% block extra_js %}
<script language="JavaScript"> <script language="JavaScript">
function checkAll(elem) { function checkAll(elem) {
let checkboxes = document.getElementsByName('materia_id'); let checkboxes = document.getElementsByName('documento_id');
for (let i = 0; i < checkboxes.length; i++) { for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') if (checkboxes[i].type == 'checkbox')
checkboxes[i].checked = elem.checked; checkboxes[i].checked = elem.checked;

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

98
sapl/templates/sessao/painel.html

@ -116,11 +116,11 @@ $(function() {
} }
startTime(); startTime();
var audioAlertFinish = document.getElementById("audio");
$('#discurso').prop('disabled', true); $('#discurso').prop('disabled', false);
$('#aparte').prop('disabled', true); $('#aparte').prop('disabled', false);
$('#ordem').prop('disabled', true); $('#ordem').prop('disabled', false);
$('#consideracoes').prop('disabled', true); $('#consideracoes').prop('disabled', false);
$('#discurso').runner({ $('#discurso').runner({
autostart: false, autostart: false,
@ -130,16 +130,10 @@ $(function() {
milliseconds: false milliseconds: false
}).on('runnerFinish', function(eventObject, info){ }).on('runnerFinish', function(eventObject, info){
$.get('/painel/cronometro', { tipo: 'discurso', action: 'stop' } ); $.get('/painel/cronometro', { tipo: 'discurso', action: 'stop' } );
audioAlertFinish.play();
$('#discursoReset').show(); $('#discursoReset').show();
$('#discurso').runner('stop'); $('#discurso').runner('stop');
$('#discursoStart').text('Iniciar'); $('#discursoStart').text('Iniciar');
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
}); });
@ -152,12 +146,6 @@ $(function() {
$('#discursoReset').hide(); $('#discursoReset').hide();
$('#discurso').runner('start'); $('#discurso').runner('start');
$('#discursoStart').text('Parar'); $('#discursoStart').text('Parar');
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
} else { } else {
@ -166,12 +154,6 @@ $(function() {
$('#discursoReset').show(); $('#discursoReset').show();
$('#discurso').runner('stop'); $('#discurso').runner('stop');
$('#discursoStart').text('Iniciar'); $('#discursoStart').text('Iniciar');
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
} }
}); });
@ -191,16 +173,10 @@ $(function() {
milliseconds: false milliseconds: false
}).on('runnerFinish', function(eventObject, info){ }).on('runnerFinish', function(eventObject, info){
$.get('/painel/cronometro', { tipo: 'aparte', action: 'stop' } ); $.get('/painel/cronometro', { tipo: 'aparte', action: 'stop' } );
audioAlertFinish.play();
$('#aparteReset').show(); $('#aparteReset').show();
$('#aparte').runner('stop'); $('#aparte').runner('stop');
$('#aparteStart').text('Iniciar'); $('#aparteStart').text('Iniciar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
}); });
@ -212,12 +188,7 @@ $(function() {
$('#aparteReset').hide(); $('#aparteReset').hide();
$('#aparte').runner('start'); $('#aparte').runner('start');
$('#aparteStart').text('Parar'); $('#aparteStart').text('Parar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
} else { } else {
$.get('/painel/cronometro', { tipo: 'aparte', action: 'stop' } ); $.get('/painel/cronometro', { tipo: 'aparte', action: 'stop' } );
@ -225,12 +196,7 @@ $(function() {
$('#aparteReset').show(); $('#aparteReset').show();
$('#aparte').runner('stop'); $('#aparte').runner('stop');
$('#aparteStart').text('Iniciar'); $('#aparteStart').text('Iniciar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
} }
}); });
@ -250,16 +216,11 @@ $(function() {
milliseconds: false milliseconds: false
}).on('runnerFinish', function(eventObject, info){ }).on('runnerFinish', function(eventObject, info){
$.get('/painel/cronometro', { tipo: 'ordem', action: 'stop' } ); $.get('/painel/cronometro', { tipo: 'ordem', action: 'stop' } );
audioAlertFinish.play();
$('#ordemReset').show(); $('#ordemReset').show();
$('#ordem').runner('stop'); $('#ordem').runner('stop');
$('#ordemStart').text('Iniciar'); $('#ordemStart').text('Iniciar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
}); });
$('#ordemStart').click(function() { $('#ordemStart').click(function() {
@ -270,12 +231,7 @@ $(function() {
$('#ordemReset').hide(); $('#ordemReset').hide();
$('#ordem').runner('start'); $('#ordem').runner('start');
$('#ordemStart').text('Parar'); $('#ordemStart').text('Parar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
} else { } else {
@ -284,12 +240,7 @@ $(function() {
$('#ordemReset').show(); $('#ordemReset').show();
$('#ordem').runner('stop'); $('#ordem').runner('stop');
$('#ordemStart').text('Iniciar'); $('#ordemStart').text('Iniciar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
$('#consideracoesStart').prop('disabled', false);
$('#consideracoesReset').prop('disabled', false);
} }
}); });
@ -309,16 +260,11 @@ $(function() {
milliseconds: false milliseconds: false
}).on('runnerFinish', function(eventObject, info){ }).on('runnerFinish', function(eventObject, info){
$.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } ); $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } );
audioAlertFinish.play();
$('#consideracoesReset').show(); $('#consideracoesReset').show();
$('#consideracoes').runner('stop'); $('#consideracoes').runner('stop');
$('#consideracoesStart').text('Iniciar'); $('#consideracoesStart').text('Iniciar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
}); });
@ -330,12 +276,7 @@ $(function() {
$('#consideracoesReset').hide(); $('#consideracoesReset').hide();
$('#consideracoes').runner('start'); $('#consideracoes').runner('start');
$('#consideracoesStart').text('Parar'); $('#consideracoesStart').text('Parar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
} else { } else {
$.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } ); $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } );
@ -343,12 +284,7 @@ $(function() {
$('#consideracoesReset').show(); $('#consideracoesReset').show();
$('#consideracoes').runner('stop'); $('#consideracoes').runner('stop');
$('#consideracoesStart').text('Iniciar'); $('#consideracoesStart').text('Iniciar');
$('#discursoStart').prop('disabled', false);
$('#discursoReset').prop('disabled', false);
$('#ordemStart').prop('disabled', false);
$('#ordemReset').prop('disabled', false);
$('#aparteStart').prop('disabled', false);
$('#aparteReset').prop('disabled', false);
} }
}); });

Loading…
Cancel
Save