Browse Source

Merge branch '3.1.x' into 2712-partidos-errados-extrato-e-resumo

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

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:

7
sapl/base/views.py

@ -1081,9 +1081,7 @@ class ListarBancadaComissaoAutorExternoView(PermissionRequiredMixin, ListView):
def autores_duplicados(): def autores_duplicados():
return [autor.values() for autor in Autor.objects.values( return [autor for autor in Autor.objects.values('nome').annotate(count=Count('nome')).filter(count__gt=1)]
'nome', 'tipo__descricao').order_by(
"nome").annotate(count=Count('nome')).filter(count__gt=1)]
class ListarAutoresDuplicadosView(PermissionRequiredMixin, ListView): class ListarAutoresDuplicadosView(PermissionRequiredMixin, ListView):
@ -1097,8 +1095,7 @@ class ListarAutoresDuplicadosView(PermissionRequiredMixin, ListView):
return autores_duplicados() return autores_duplicados()
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super( context = super().get_context_data(**kwargs)
ListarAutoresDuplicadosView, self).get_context_data(**kwargs)
paginator = context['paginator'] paginator = context['paginator']
page_obj = context['page_obj'] page_obj = context['page_obj']
context['page_range'] = make_pagination( context['page_range'] = make_pagination(

26
sapl/materia/forms.py

@ -817,6 +817,26 @@ class AnexadaForm(ModelForm):
if is_anexada: if is_anexada:
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
@ -1741,7 +1761,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(
@ -1807,6 +1827,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)
@ -2108,9 +2136,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 = [

150
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'
@ -1232,8 +1370,8 @@ class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
self.messages.add_message(self.request, messages.INFO, mensagem) self.messages.add_message(self.request, messages.INFO, mensagem)
return self.render_to_response(context) return self.render_to_response(context)
if len(documento.assunto) > 301: if len(documento.assunto) > 201:
documento.assunto = documento.assunto[0:300] + '[...]' documento.assunto = documento.assunto[0:200] + '[...]'
context['documento'] = documento context['documento'] = documento
return gerar_pdf_impressos(self.request, context, return gerar_pdf_impressos(self.request, context,

3
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()),
] ]
@ -118,6 +119,8 @@ rules_group_materia = {
(materia.Autoria, __base__, __perms_publicas__), (materia.Autoria, __base__, __perms_publicas__),
(materia.DespachoInicial, __base__, __perms_publicas__), (materia.DespachoInicial, __base__, __perms_publicas__),
(materia.DocumentoAcessorio, __base__, __perms_publicas__), (materia.DocumentoAcessorio, __base__, __perms_publicas__),
(materia.MateriaAssunto, __base__, __perms_publicas__),
(materia.AssuntoMateria, __base__, __perms_publicas__),
(materia.MateriaLegislativa, __base__ + (materia.MateriaLegislativa, __base__ +
['can_access_impressos'], __perms_publicas__), ['can_access_impressos'], __perms_publicas__),

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

8
sapl/templates/base/autores_duplicados.html

@ -11,16 +11,14 @@
<thead> <thead>
<tr> <tr>
<th>Autor</th> <th>Autor</th>
<th>Tipo de Autor</th>
<th>Quantidade</th> <th>Quantidade</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for autor, tipo, quantidade in autores_duplicados %} {% for autor in autores_duplicados %}
<tr> <tr>
<td>{{ autor }}</td> <td>{{ autor.nome }}</td>
<td>{{ tipo }}</td> <td>{{ autor.count }}</td>
<td>{{ quantidade }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

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);
} }
}); });

27
scripts/check_commits.py

@ -0,0 +1,27 @@
import requests
branch_master = requests.get('https://api.github.com/repos/interlegis/sapl/commits?per_page=100&sha=master')
branch_master = branch_master.json()
commits_master = [e['commit']['message'] for e in branch_master]
branch_3_1_x = requests.get('https://api.github.com/repos/interlegis/sapl/commits?per_page=70&sha=3.1.x')
branch_3_1_x = branch_3_1_x.json()
commits_3_1_x = [(e['commit']['message'], {'sha':e['sha'], 'data':e['commit']['author']['date']}) for e in branch_3_1_x]
print("\nCommits que estão em 3.1.x, mas não em master:\n")
# retira os \r para evitar bugs
commits_master = [commit.replace('\r', '') for commit in commits_master]
for c, s in commits_3_1_x:
# retira os \r para evitar bugs
c = c.replace('\r', '')
if c not in commits_master:
print('---------------------------------------------------------------------')
print('Data: ' + s['data'][:10])
print(s['sha'][:7] + '-> ' + c)
print('---------------------------------------------------------------------')
Loading…
Cancel
Save