mirror of https://github.com/interlegis/sapl.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2656 lines
104 KiB
2656 lines
104 KiB
from datetime import datetime
|
|
import itertools
|
|
import logging
|
|
import os
|
|
from random import choice
|
|
import shutil
|
|
from string import ascii_letters, digits
|
|
import tempfile
|
|
|
|
from crispy_forms.layout import HTML
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.auth.decorators import permission_required
|
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
|
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError
|
|
from django.core.urlresolvers import reverse
|
|
from django.db.models import Max, Q
|
|
from django.http import HttpResponse, JsonResponse
|
|
from django.http.response import Http404, HttpResponseRedirect
|
|
from django.shortcuts import get_object_or_404, redirect
|
|
from django.template import RequestContext, loader
|
|
from django.utils import formats, timezone
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.generic import ListView, TemplateView, CreateView, UpdateView
|
|
from django.views.generic.base import RedirectView
|
|
from django.views.generic.edit import FormView
|
|
from django_filters.views import FilterView
|
|
import weasyprint
|
|
import weasyprint
|
|
|
|
import sapl
|
|
from sapl.base.email_utils import do_envia_email_confirmacao
|
|
from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig
|
|
from sapl.base.signals import tramitacao_signal
|
|
from sapl.comissoes.models import Comissao, Participacao, Composicao
|
|
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT,
|
|
STATUS_TA_PRIVATE)
|
|
from sapl.compilacao.views import IntegracaoTaView
|
|
from sapl.crispy_layout_mixin import SaplFormHelper
|
|
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions
|
|
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
|
|
MasterDetailCrud,
|
|
PermissionRequiredForAppCrudMixin, make_pagination)
|
|
from sapl.materia.forms import (AnexadaForm, AutoriaForm,
|
|
AutoriaMultiCreateForm,
|
|
ConfirmarProposicaoForm,
|
|
DevolverProposicaoForm, LegislacaoCitadaForm,
|
|
OrgaoForm, ProposicaoForm, TipoProposicaoForm,
|
|
TramitacaoForm, TramitacaoUpdateForm, MateriaPesquisaSimplesForm,
|
|
DespachoInicialCreateForm)
|
|
from sapl.norma.models import LegislacaoCitada
|
|
from sapl.parlamentares.models import Legislatura
|
|
from sapl.protocoloadm.models import Protocolo
|
|
from sapl.settings import MEDIA_ROOT
|
|
from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO,
|
|
gerar_hash_arquivo, get_base_url, get_client_ip,
|
|
get_mime_type_from_file_extension, montar_row_autor,
|
|
show_results_filter_set, mail_service_configured, lista_anexados)
|
|
|
|
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
|
|
AnexadaEmLoteFilterSet,
|
|
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
|
|
DocumentoAcessorioForm, EtiquetaPesquisaForm,
|
|
FichaPesquisaForm, FichaSelecionaForm, MateriaAssuntoForm,
|
|
MateriaLegislativaFilterSet, MateriaLegislativaForm,
|
|
MateriaSimplificadaForm, PrimeiraTramitacaoEmLoteFilterSet,
|
|
ReceberProposicaoForm, RelatoriaForm,
|
|
TramitacaoEmLoteFilterSet, UnidadeTramitacaoForm,
|
|
filtra_tramitacao_destino,
|
|
filtra_tramitacao_destino_and_status,
|
|
filtra_tramitacao_status,
|
|
ExcluirTramitacaoEmLote, compara_tramitacoes_mat,
|
|
TramitacaoEmLoteForm)
|
|
from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
|
|
DespachoInicial, DocumentoAcessorio, MateriaAssunto,
|
|
MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao,
|
|
RegimeTramitacao, Relatoria, StatusTramitacao,
|
|
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
|
|
TipoProposicao, Tramitacao, UnidadeTramitacao)
|
|
|
|
|
|
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
|
|
|
|
OrigemCrud = CrudAux.build(Origem, '')
|
|
|
|
RegimeTramitacaoCrud = CrudAux.build(
|
|
RegimeTramitacao, 'regime_tramitacao')
|
|
|
|
TipoDocumentoCrud = CrudAux.build(
|
|
TipoDocumento, 'tipo_documento')
|
|
|
|
TipoFimRelatoriaCrud = CrudAux.build(
|
|
TipoFimRelatoria, 'fim_relatoria')
|
|
|
|
|
|
def autores_ja_adicionados(materia_pk):
|
|
autorias = Autoria.objects.filter(materia_id=materia_pk).values_list(
|
|
'autor_id', flat=True)
|
|
return autorias
|
|
|
|
|
|
def proposicao_texto(request, pk):
|
|
logger = logging.getLogger(__name__)
|
|
username = request.user.username
|
|
logger.debug('user=' + username +
|
|
'. Tentando obter objeto Proposicao com pk = {}.'.format(pk))
|
|
proposicao = Proposicao.objects.get(pk=pk)
|
|
|
|
if proposicao.texto_original:
|
|
if (not proposicao.data_recebimento and
|
|
proposicao.autor.user_id != request.user.id):
|
|
logger.error("user=" + username + ". Usuário ({}) não tem permissão para acessar o texto original."
|
|
.format(request.user.id))
|
|
messages.error(request, _(
|
|
'Você não tem permissão para acessar o texto original.'))
|
|
return redirect(reverse('sapl.materia:proposicao_detail',
|
|
kwargs={'pk': pk}))
|
|
|
|
arquivo = proposicao.texto_original
|
|
|
|
mime = get_mime_type_from_file_extension(arquivo.name)
|
|
|
|
with open(arquivo.path, 'rb') as f:
|
|
data = f.read()
|
|
|
|
response = HttpResponse(data, content_type='%s' % mime)
|
|
response['Content-Disposition'] = (
|
|
'inline; filename="%s"' % arquivo.name.split('/')[-1])
|
|
return response
|
|
logger.error('user=' + username +
|
|
'. Objeto Proposicao com pk={} não encontrado.'.format(pk))
|
|
raise Http404
|
|
|
|
|
|
class AdicionarVariasAutorias(PermissionRequiredForAppCrudMixin, FilterView):
|
|
app_label = sapl.materia.apps.AppConfig.label
|
|
filterset_class = AdicionarVariasAutoriasFilterSet
|
|
template_name = 'materia/adicionar_varias_autorias.html'
|
|
model = Autor
|
|
|
|
def get_filterset_kwargs(self, filterset_class):
|
|
super(AdicionarVariasAutorias, self).get_filterset_kwargs(
|
|
filterset_class)
|
|
kwargs = {'data': self.request.GET or None}
|
|
|
|
qs = self.get_queryset()
|
|
qs = qs.exclude(
|
|
id__in=autores_ja_adicionados(self.kwargs['pk'])).distinct()
|
|
|
|
kwargs.update({'queryset': qs})
|
|
return kwargs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(AdicionarVariasAutorias, self).get_context_data(
|
|
**kwargs)
|
|
|
|
context['title'] = _('Pesquisar Autores')
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
|
|
context['show_results'] = show_results_filter_set(qr)
|
|
|
|
context['pk_materia'] = self.kwargs['pk']
|
|
return context
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
marcados = request.POST.getlist('autor_id')
|
|
|
|
for m in marcados:
|
|
Autoria.objects.create(
|
|
materia_id=self.kwargs['pk'],
|
|
autor_id=m
|
|
)
|
|
|
|
return HttpResponseRedirect(
|
|
reverse('sapl.materia:autoria_list',
|
|
kwargs={'pk': self.kwargs['pk']}))
|
|
|
|
|
|
class CriarProtocoloMateriaView(CreateView):
|
|
template_name = "crud/form.html"
|
|
form_class = MateriaSimplificadaForm
|
|
form_valid_message = _('Matéria cadastrada com sucesso!')
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_success_url(self, materia):
|
|
return reverse('sapl.materia:materialegislativa_detail', kwargs={
|
|
'pk': materia.pk})
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(
|
|
CriarProtocoloMateriaView, self).get_context_data(**kwargs)
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
self.logger.debug("user=" + username +
|
|
". Tentando obter objeto Protocolo.")
|
|
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
|
|
except ObjectDoesNotExist as e:
|
|
self.logger.error(
|
|
"user=" + username + ". Objeto Protocolo com pk={} não encontrado. ".format(self.kwargs['pk']) + str(e))
|
|
raise Http404()
|
|
|
|
numero = 1
|
|
try:
|
|
self.logger.debug("user=" + username +
|
|
". Tentando obter materias do último ano.")
|
|
materias_ano = MateriaLegislativa.objects.filter(
|
|
ano=protocolo.ano,
|
|
tipo=protocolo.tipo_materia).latest('numero')
|
|
numero = materias_ano.numero + 1
|
|
except ObjectDoesNotExist:
|
|
self.logger.error("user=" + username + ". Não foram encontradas matérias no último ano ({}). "
|
|
"Definido 1 como padrão.".format(protocolo.ano))
|
|
pass # numero ficou com o valor padrão 1 acima
|
|
|
|
context['form'].fields['tipo'].initial = protocolo.tipo_materia
|
|
context['form'].fields['numero'].initial = numero
|
|
context['form'].fields['ano'].initial = protocolo.ano
|
|
if protocolo:
|
|
if protocolo.timestamp:
|
|
context['form'].fields['data_apresentacao'].initial = protocolo.timestamp.date(
|
|
)
|
|
elif protocolo.timestamp_data_hora_manual:
|
|
context['form'].fields['data_apresentacao'].initial = protocolo.timestamp_data_hora_manual.date()
|
|
elif protocolo.data:
|
|
context['form'].fields['data_apresentacao'].initial = protocolo.data
|
|
context['form'].fields['numero_protocolo'].initial = protocolo.numero
|
|
context['form'].fields['ementa'].initial = protocolo.assunto_ementa
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
materia = form.save()
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
self.logger.info(
|
|
"user=" + username + ". Tentando obter objeto Procolo com pk={}.".format(self.kwargs['pk']))
|
|
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
|
|
except ObjectDoesNotExist:
|
|
self.logger.error(
|
|
'user=' + username + '. Objeto Protocolo com pk={} não encontrado.'.format(self.kwargs['pk']))
|
|
raise Http404()
|
|
|
|
if protocolo.autor:
|
|
Autoria.objects.create(
|
|
materia=materia,
|
|
autor=protocolo.autor,
|
|
primeiro_autor=True)
|
|
|
|
return redirect(self.get_success_url(materia))
|
|
|
|
|
|
class MateriaTaView(IntegracaoTaView):
|
|
model = MateriaLegislativa
|
|
model_type_foreignkey = TipoMateriaLegislativa
|
|
map_fields = {
|
|
'data': 'data_apresentacao',
|
|
'ementa': 'ementa',
|
|
'observacao': None,
|
|
'numero': 'numero',
|
|
'ano': 'ano',
|
|
'tipo': 'tipo',
|
|
}
|
|
map_funcs = {
|
|
'publicacao_func': False,
|
|
}
|
|
ta_values = {
|
|
'editable_only_by_owners': False,
|
|
'editing_locked': False,
|
|
}
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Para manter a app compilacao isolada das outras aplicações,
|
|
este get foi implementado para tratar uma prerrogativa externa
|
|
de usuário.
|
|
"""
|
|
if sapl.base.models.AppConfig.attr('texto_articulado_materia'):
|
|
return IntegracaoTaView.get(self, request, *args, **kwargs)
|
|
else:
|
|
return self.get_redirect_deactivated()
|
|
|
|
|
|
class ProposicaoTaView(IntegracaoTaView):
|
|
model = Proposicao
|
|
model_type_foreignkey = TipoProposicao
|
|
map_fields = {
|
|
'data': 'data_envio',
|
|
'ementa': 'descricao',
|
|
'observacao': None,
|
|
'numero': 'numero_proposicao',
|
|
'ano': 'ano',
|
|
'tipo': 'tipo',
|
|
}
|
|
map_funcs = {
|
|
'publicacao_func': False
|
|
}
|
|
ta_values = {
|
|
'editable_only_by_owners': True,
|
|
'editing_locked': False,
|
|
'privacidade': STATUS_TA_PRIVATE
|
|
}
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Para manter a app compilacao isolada das outras aplicações,
|
|
este get foi implementado para tratar uma prerrogativa externa
|
|
de usuário.
|
|
"""
|
|
if sapl.base.models.AppConfig.attr('texto_articulado_proposicao'):
|
|
|
|
proposicao = get_object_or_404(self.model, pk=kwargs['pk'])
|
|
|
|
if not proposicao.data_envio and\
|
|
request.user != proposicao.autor.user:
|
|
raise Http404()
|
|
|
|
return IntegracaoTaView.get(self, request, *args, **kwargs)
|
|
else:
|
|
return self.get_redirect_deactivated()
|
|
|
|
|
|
@permission_required('materia.detail_materialegislativa')
|
|
def recuperar_materia(request):
|
|
logger = logging.getLogger(__name__)
|
|
username = request.user.username
|
|
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo'])
|
|
ano = request.GET.get('ano', '')
|
|
|
|
numeracao = None
|
|
try:
|
|
logger.debug("user=" + username +
|
|
". Tentando obter numeração da matéria.")
|
|
numeracao = sapl.base.models.AppConfig.objects.last(
|
|
).sequencia_numeracao_protocolo
|
|
except AttributeError as e:
|
|
logger.error("user=" + username + ". " + str(e) +
|
|
" Numeracao da matéria definida como None.")
|
|
pass
|
|
|
|
if tipo.sequencia_numeracao:
|
|
numeracao = tipo.sequencia_numeracao
|
|
|
|
if numeracao == 'A':
|
|
numero = MateriaLegislativa.objects.filter(
|
|
ano=ano, tipo=tipo).aggregate(Max('numero'))
|
|
elif numeracao == 'L':
|
|
legislatura = Legislatura.objects.filter(
|
|
data_inicio__year__lte=ano,
|
|
data_fim__year__gte=ano).first()
|
|
data_inicio = legislatura.data_inicio
|
|
data_fim = legislatura.data_fim
|
|
numero = MateriaLegislativa.objects.filter(
|
|
data_apresentacao__gte=data_inicio,
|
|
data_apresentacao__lte=data_fim,
|
|
tipo=tipo).aggregate(
|
|
Max('numero'))
|
|
elif numeracao == 'U':
|
|
numero = MateriaLegislativa.objects.filter(
|
|
tipo=tipo).aggregate(Max('numero'))
|
|
|
|
if numeracao is None:
|
|
numero['numero__max'] = 0
|
|
|
|
max_numero = numero['numero__max'] + 1 if numero['numero__max'] else 1
|
|
|
|
response = JsonResponse({'numero': max_numero, 'ano': ano})
|
|
|
|
return response
|
|
|
|
|
|
StatusTramitacaoCrud = CrudAux.build(StatusTramitacao, 'status_tramitacao')
|
|
|
|
|
|
class OrgaoCrud(CrudAux):
|
|
model = Orgao
|
|
|
|
class CreateView(CrudAux.CreateView):
|
|
form_class = OrgaoForm
|
|
|
|
|
|
class TipoProposicaoCrud(CrudAux):
|
|
model = TipoProposicao
|
|
help_text = 'tipo_proposicao'
|
|
|
|
class BaseMixin(CrudAux.BaseMixin):
|
|
list_field_names = [
|
|
"descricao", "content_type", 'tipo_conteudo_related']
|
|
|
|
class CreateView(CrudAux.CreateView):
|
|
form_class = TipoProposicaoForm
|
|
layout_key = None
|
|
|
|
class UpdateView(CrudAux.UpdateView):
|
|
form_class = TipoProposicaoForm
|
|
layout_key = None
|
|
|
|
|
|
def criar_materia_proposicao(proposicao):
|
|
tipo_materia = TipoMateriaLegislativa.objects.get(
|
|
descricao=proposicao.tipo.descricao)
|
|
numero = MateriaLegislativa.objects.filter(
|
|
ano=timezone.now().year).order_by('numero').last().numero + 1
|
|
regime = RegimeTramitacao.objects.get(descricao='Normal')
|
|
|
|
return MateriaLegislativa.objects.create(
|
|
tipo=tipo_materia,
|
|
ano=timezone.now().year,
|
|
numero=numero,
|
|
data_apresentacao=timezone.now(),
|
|
regime_tramitacao=regime,
|
|
em_tramitacao=True,
|
|
ementa=proposicao.descricao,
|
|
texto_original=proposicao.texto_original
|
|
)
|
|
|
|
|
|
def criar_doc_proposicao(proposicao):
|
|
tipo_doc = TipoDocumento.objects.get(
|
|
descricao=proposicao.tipo.descricao)
|
|
if proposicao.autor is None:
|
|
autor = 'Desconhecido'
|
|
else:
|
|
autor = proposicao.autor
|
|
|
|
return DocumentoAcessorio.objects.create(
|
|
materia=proposicao.materia,
|
|
tipo=tipo_doc,
|
|
arquivo=proposicao.texto_original,
|
|
nome=proposicao.descricao,
|
|
data=proposicao.data_envio,
|
|
autor=autor
|
|
)
|
|
|
|
|
|
class ProposicaoDevolvida(PermissionRequiredMixin, ListView):
|
|
template_name = 'materia/prop_devolvidas_list.html'
|
|
model = Proposicao
|
|
ordering = ['data_envio']
|
|
paginate_by = 10
|
|
permission_required = ('materia.detail_proposicao_devolvida', )
|
|
|
|
def get_queryset(self):
|
|
return Proposicao.objects.filter(
|
|
data_envio__isnull=True,
|
|
data_recebimento__isnull=True,
|
|
data_devolucao__isnull=False)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ProposicaoDevolvida, self).get_context_data(**kwargs)
|
|
paginator = context['paginator']
|
|
page_obj = context['page_obj']
|
|
context['page_range'] = make_pagination(
|
|
page_obj.number, paginator.num_pages)
|
|
context['NO_ENTRIES_MSG'] = 'Nenhuma proposição devolvida.'
|
|
context['subnav_template_name'] = 'materia/subnav_prop.yaml'
|
|
return context
|
|
|
|
|
|
class ProposicaoPendente(PermissionRequiredMixin, ListView):
|
|
template_name = 'materia/prop_pendentes_list.html'
|
|
model = Proposicao
|
|
ordering = ['data_envio', 'autor', 'tipo', 'descricao']
|
|
paginate_by = 10
|
|
permission_required = ('materia.detail_proposicao_enviada', )
|
|
|
|
def get_queryset(self):
|
|
return Proposicao.objects.filter(
|
|
data_envio__isnull=False,
|
|
data_recebimento__isnull=True,
|
|
data_devolucao__isnull=True)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ProposicaoPendente, self).get_context_data(**kwargs)
|
|
context['object_list'] = Proposicao.objects.filter(
|
|
data_envio__isnull=False,
|
|
data_recebimento__isnull=True,
|
|
data_devolucao__isnull=True)
|
|
paginator = context['paginator']
|
|
page_obj = context['page_obj']
|
|
context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last()
|
|
context['page_range'] = make_pagination(
|
|
page_obj.number, paginator.num_pages)
|
|
context['NO_ENTRIES_MSG'] = 'Nenhuma proposição pendente.'
|
|
|
|
context['subnav_template_name'] = 'materia/subnav_prop.yaml'
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&o=' + qr['o']) if 'o' in qr.keys() else ''
|
|
return context
|
|
|
|
|
|
class ProposicaoRecebida(PermissionRequiredMixin, ListView):
|
|
template_name = 'materia/prop_recebidas_list.html'
|
|
model = Proposicao
|
|
|
|
paginate_by = 10
|
|
permission_required = 'materia.detail_proposicao_incorporada'
|
|
|
|
def get_queryset(self):
|
|
return Proposicao.objects.filter(
|
|
data_envio__isnull=False,
|
|
data_recebimento__isnull=False,
|
|
data_devolucao__isnull=True)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ProposicaoRecebida, self).get_context_data(**kwargs)
|
|
paginator = context['paginator']
|
|
page_obj = context['page_obj']
|
|
context['page_range'] = make_pagination(
|
|
page_obj.number, paginator.num_pages)
|
|
context['NO_ENTRIES_MSG'] = 'Nenhuma proposição recebida.'
|
|
context['subnav_template_name'] = 'materia/subnav_prop.yaml'
|
|
return context
|
|
|
|
|
|
class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView):
|
|
app_label = sapl.protocoloadm.apps.AppConfig.label
|
|
template_name = "crud/form.html"
|
|
form_class = ReceberProposicaoForm
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
|
|
form = ReceberProposicaoForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
try:
|
|
# A ultima parte do código deve ser a pk da Proposicao
|
|
cod_hash = form.cleaned_data["cod_hash"]. \
|
|
replace('/', SEPARADOR_HASH_PROPOSICAO)
|
|
id = cod_hash.split(SEPARADOR_HASH_PROPOSICAO)[1]
|
|
proposicao = Proposicao.objects.get(id=id,
|
|
data_envio__isnull=False,
|
|
data_recebimento__isnull=True)
|
|
|
|
if proposicao.texto_articulado.exists():
|
|
ta = proposicao.texto_articulado.first()
|
|
# FIXME hash para textos articulados
|
|
hasher = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(proposicao.id)
|
|
else:
|
|
hasher = gerar_hash_arquivo(
|
|
proposicao.texto_original.path,
|
|
str(proposicao.id)) \
|
|
if proposicao.texto_original else None
|
|
if hasher == cod_hash:
|
|
return HttpResponseRedirect(
|
|
reverse('sapl.materia:proposicao-confirmar',
|
|
kwargs={
|
|
'hash': hasher.split(SEPARADOR_HASH_PROPOSICAO)[0][1:],
|
|
'pk': proposicao.pk}))
|
|
except ObjectDoesNotExist:
|
|
messages.error(request, _('Proposição não encontrada!'))
|
|
except IndexError:
|
|
messages.error(request, _('Código de recibo mal formado!'))
|
|
except IOError:
|
|
messages.error(request, _(
|
|
'Erro abrindo texto original de proposição'))
|
|
return self.form_invalid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse('sapl.materia:receber-proposicao')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ReceberProposicao, self).get_context_data(**kwargs)
|
|
context['subnav_template_name'] = 'materia/subnav_prop.yaml'
|
|
return context
|
|
|
|
|
|
class RetornarProposicao(UpdateView):
|
|
app_label = sapl.protocoloadm.apps.AppConfig.label
|
|
template_name = "materia/proposicao_confirm_return.html"
|
|
model = Proposicao
|
|
fields = ['data_envio', 'descricao']
|
|
permission_required = ('materia.detail_proposicao_enviada', )
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
username = request.user.username
|
|
try:
|
|
self.logger.info(
|
|
"user=" + username + ". Tentando obter objeto Proposicao com id={}.".format(kwargs['pk']))
|
|
p = Proposicao.objects.get(id=kwargs['pk'])
|
|
except:
|
|
self.logger.error(
|
|
"user=" + username + ". Objeto Proposicao com id={} não encontrado.".format(kwargs['pk']))
|
|
raise Http404()
|
|
|
|
if p.autor.user != request.user:
|
|
self.logger.error(
|
|
"user=" + username + ". Usuário ({}) sem acesso a esta opção.".format(request.user))
|
|
messages.error(
|
|
request,
|
|
'Usuário sem acesso a esta opção.' %
|
|
request.user)
|
|
return redirect('/')
|
|
|
|
return super(RetornarProposicao, self).dispatch(
|
|
request, *args, **kwargs)
|
|
|
|
|
|
class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
|
|
app_label = sapl.protocoloadm.apps.AppConfig.label
|
|
template_name = "materia/confirmar_proposicao.html"
|
|
model = Proposicao
|
|
form_class = ConfirmarProposicaoForm, DevolverProposicaoForm
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_success_url(self):
|
|
msgs = self.object.results['messages']
|
|
|
|
for key, value in msgs.items():
|
|
for item in value:
|
|
getattr(messages, key)(self.request, item)
|
|
|
|
return self.object.results['url']
|
|
|
|
def get_object(self, queryset=None):
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
"""
|
|
Não deve haver acesso na rotina de confirmação a proposições:
|
|
já recebidas -> data_recebimento != None
|
|
não enviadas -> data_envio == None
|
|
"""
|
|
self.logger.debug("user=" + username +
|
|
". Tentando obter objeto Proposicao.")
|
|
proposicao = Proposicao.objects.get(pk=self.kwargs['pk'],
|
|
data_envio__isnull=False,
|
|
data_recebimento__isnull=True)
|
|
self.object = None
|
|
|
|
if proposicao.texto_articulado.exists():
|
|
ta = proposicao.texto_articulado.first()
|
|
hasher = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(proposicao.id)
|
|
else:
|
|
hasher = gerar_hash_arquivo(
|
|
proposicao.texto_original.path,
|
|
str(proposicao.pk)) if proposicao.texto_original else None
|
|
|
|
if hasher == 'P%s%s%s' % (self.kwargs['hash'], SEPARADOR_HASH_PROPOSICAO, proposicao.pk):
|
|
self.object = proposicao
|
|
except Exception as e:
|
|
self.logger.error("user=" + username + ". Objeto Proposicao com atributos (pk={}, data_envio=Not Null, "
|
|
"data_recebimento=Null) não encontrado. ".format(self.kwargs['pk']) + str(e))
|
|
raise Http404()
|
|
|
|
if not self.object:
|
|
self.logger.error("user=" + username + ". Objeto vazio.")
|
|
raise Http404()
|
|
|
|
return self.object
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['subnav_template_name'] = ''
|
|
return context
|
|
|
|
def get_form(self, form_class=None):
|
|
if form_class is None:
|
|
form_class = self.get_form_class()
|
|
|
|
if self.request.POST:
|
|
if 'justificativa_devolucao' in self.request.POST:
|
|
return form_class[1](**self.get_form_kwargs())
|
|
else:
|
|
return form_class[0](**self.get_form_kwargs())
|
|
else:
|
|
forms = []
|
|
for form in form_class:
|
|
forms.append(form(**self.get_form_kwargs()))
|
|
return forms
|
|
|
|
def form_invalid(self, form):
|
|
# Só um form é enviado por vez mas podem existir invalidade em ambos.
|
|
# em caso de um form ser inválido e retornar para a tela dos
|
|
# formulários, o outro precisa ser renderizado, mas neste ponto por ser
|
|
# um POST só chega um form dada lógica no método acima get_form,
|
|
# assim o form_invalid cria o form alternativo e o insere para
|
|
# renderização do template_name definido nesta classe
|
|
|
|
kwargs = {
|
|
'initial': self.get_initial(),
|
|
'prefix': self.get_prefix(),
|
|
'instance': form.instance
|
|
}
|
|
|
|
if isinstance(form, self.form_class[0]):
|
|
forms = [form, DevolverProposicaoForm(**kwargs)]
|
|
else:
|
|
forms = [ConfirmarProposicaoForm(**kwargs), form]
|
|
|
|
return self.render_to_response(self.get_context_data(form=forms))
|
|
|
|
|
|
class UnidadeTramitacaoCrud(CrudAux):
|
|
model = UnidadeTramitacao
|
|
help_topic = 'unidade_tramitacao'
|
|
|
|
class BaseMixin(CrudAux.BaseMixin):
|
|
list_field_names = ['comissao', 'orgao', 'parlamentar']
|
|
|
|
class ListView(CrudAux.ListView):
|
|
|
|
def get_headers(self):
|
|
return [_('Unidade de Tramitação')]
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
for row in context['rows']:
|
|
if row[0][0]: # Comissão
|
|
pass
|
|
elif row[1][0]: # Órgão
|
|
row[0] = (row[1][0], row[0][1])
|
|
elif row[2][0]: # Parlamentar
|
|
row[0] = (row[2][0], row[0][1])
|
|
row[1], row[2] = ('', ''), ('', '')
|
|
return context
|
|
|
|
class UpdateView(Crud.UpdateView):
|
|
form_class = UnidadeTramitacaoForm
|
|
|
|
class CreateView(Crud.CreateView):
|
|
form_class = UnidadeTramitacaoForm
|
|
|
|
|
|
class ProposicaoCrud(Crud):
|
|
model = Proposicao
|
|
help_topic = 'proposicao'
|
|
container_field = 'autor__user'
|
|
|
|
class BaseMixin(Crud.BaseMixin):
|
|
list_field_names = ['data_envio', 'data_recebimento', 'descricao',
|
|
'tipo', 'conteudo_gerado_related', 'cancelado', ]
|
|
|
|
class BaseLocalMixin:
|
|
form_class = ProposicaoForm
|
|
layout_key = None
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['subnav_template_name'] = ''
|
|
return context
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
if not self._action_is_valid(request, *args, **kwargs):
|
|
return redirect(reverse('sapl.materia:proposicao_detail',
|
|
kwargs={'pk': kwargs['pk']}))
|
|
return super().get(self, request, *args, **kwargs)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
|
|
if not self._action_is_valid(request, *args, **kwargs):
|
|
return redirect(reverse('sapl.materia:proposicao_detail',
|
|
kwargs={'pk': kwargs['pk']}))
|
|
return super().post(self, request, *args, **kwargs)
|
|
|
|
class DetailView(Crud.DetailView):
|
|
layout_key = 'Proposicao'
|
|
permission_required = (RP_DETAIL, 'materia.detail_proposicao_enviada',
|
|
'materia.detail_proposicao_devolvida',
|
|
'materia.detail_proposicao_incorporada')
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['subnav_template_name'] = ''
|
|
context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last()
|
|
|
|
context['title'] = '%s <small>(%s)</small>' % (
|
|
self.object, self.object.autor)
|
|
return context
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
|
|
action = request.GET.get('action', '')
|
|
username = request.user.username
|
|
|
|
if not action:
|
|
return Crud.DetailView.get(self, request, *args, **kwargs)
|
|
|
|
p = Proposicao.objects.get(id=kwargs['pk'])
|
|
|
|
msg_error = ''
|
|
if p:
|
|
if action == 'send':
|
|
if p.data_envio and p.data_recebimento:
|
|
msg_error = _('Proposição já foi enviada e recebida.')
|
|
elif p.data_envio:
|
|
msg_error = _('Proposição já foi enviada.')
|
|
elif not p.texto_original and\
|
|
not p.texto_articulado.exists():
|
|
msg_error = _('Proposição não possui nenhum tipo de '
|
|
'Texto associado.')
|
|
else:
|
|
if p.texto_articulado.exists():
|
|
ta = p.texto_articulado.first()
|
|
ta.privacidade = STATUS_TA_IMMUTABLE_RESTRICT
|
|
ta.editing_locked = True
|
|
ta.save()
|
|
|
|
receber_recibo = BaseAppConfig.attr(
|
|
'receber_recibo_proposicao')
|
|
|
|
if not receber_recibo:
|
|
ta = p.texto_articulado.first()
|
|
p.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(p.pk)
|
|
|
|
p.data_devolucao = None
|
|
p.data_envio = timezone.now()
|
|
p.save()
|
|
|
|
messages.success(request, _(
|
|
'Proposição enviada com sucesso.'))
|
|
try:
|
|
self.logger.debug("user=" + username + ". Tentando obter número do objeto MateriaLegislativa com "
|
|
"atributos tipo={} e ano={}."
|
|
.format(p.tipo.tipo_conteudo_related, p.ano))
|
|
|
|
if p.numero_materia_futuro:
|
|
numero = p.numero_materia_futuro
|
|
else:
|
|
numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related,
|
|
ano=p.ano).last().numero + 1
|
|
messages.success(request, _(
|
|
'%s : nº %s de %s <br>Atenção! Este número é apenas um provável '
|
|
'número que pode não corresponder com a realidade'
|
|
% (p.tipo, numero, p.ano)))
|
|
except ValueError as e:
|
|
self.logger.error(
|
|
"user=" + username + "." + str(e))
|
|
pass
|
|
except AttributeError as e:
|
|
self.logger.error(
|
|
"user=" + username + "." + str(e))
|
|
pass
|
|
except TypeError as e:
|
|
self.logger.error(
|
|
"user=" + username + "." + str(e))
|
|
pass
|
|
|
|
elif action == 'return':
|
|
if not p.data_envio:
|
|
self.logger.error(
|
|
"user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao))
|
|
msg_error = _('Proposição ainda não foi enviada.')
|
|
elif p.data_recebimento:
|
|
self.logger.error("user=" + username + ". Proposição (numero={}) já foi recebida, não é "
|
|
"possível retorná-la.".format(p.numero_proposicao))
|
|
msg_error = _('Proposição já foi recebida, não é '
|
|
'possível retorná-la.')
|
|
else:
|
|
p.data_envio = None
|
|
p.save()
|
|
if p.texto_articulado.exists():
|
|
ta = p.texto_articulado.first()
|
|
ta.privacidade = STATUS_TA_PRIVATE
|
|
ta.editing_locked = False
|
|
ta.save()
|
|
self.logger.info(
|
|
"user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao))
|
|
messages.success(request, _(
|
|
'Proposição Retornada com sucesso.'))
|
|
|
|
if msg_error:
|
|
messages.error(request, msg_error)
|
|
|
|
# retornar redirecionando para limpar a variavel action
|
|
return redirect(reverse('sapl.materia:proposicao_detail',
|
|
kwargs={'pk': kwargs['pk']}))
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
username = request.user.username
|
|
try:
|
|
self.logger.debug(
|
|
"user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk']))
|
|
p = Proposicao.objects.get(id=kwargs['pk'])
|
|
except Exception as e:
|
|
self.logger.error(
|
|
"user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e))
|
|
raise Http404()
|
|
|
|
if not self.has_permission():
|
|
return self.handle_no_permission()
|
|
|
|
if p.autor.user != request.user:
|
|
if not p.data_envio and not p.data_devolucao:
|
|
raise Http404()
|
|
|
|
if p.data_devolucao and not request.user.has_perm(
|
|
'materia.detail_proposicao_devolvida'):
|
|
raise Http404()
|
|
|
|
if p.data_envio and not p.data_recebimento\
|
|
and not request.user.has_perm(
|
|
'materia.detail_proposicao_enviada'):
|
|
raise Http404()
|
|
|
|
if p.data_envio and p.data_recebimento\
|
|
and not request.user.has_perm(
|
|
'materia.detail_proposicao_incorporada'):
|
|
raise Http404()
|
|
|
|
return super(PermissionRequiredMixin, self).dispatch(
|
|
request, *args, **kwargs)
|
|
|
|
class DeleteView(BaseLocalMixin, Crud.DeleteView):
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def _action_is_valid(self, request, *args, **kwargs):
|
|
proposicao = Proposicao.objects.filter(
|
|
id=kwargs['pk']).values_list(
|
|
'data_envio', 'data_recebimento')
|
|
|
|
username = request.user.username
|
|
|
|
if proposicao:
|
|
if proposicao[0][0] and proposicao[0][1]:
|
|
self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada e recebida."
|
|
"Não pode mais ser excluida.".format(kwargs['pk']))
|
|
msg = _('Proposição já foi enviada e recebida.'
|
|
'Não pode mais ser excluida.')
|
|
elif proposicao[0][0] and not proposicao[0][1]:
|
|
self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada mas ainda não recebida "
|
|
"pelo protocolo. Use a opção Recuperar Proposição "
|
|
"para depois excluí-la.".format(kwargs['pk']))
|
|
msg = _('Proposição já foi enviada mas ainda não recebida '
|
|
'pelo protocolo. Use a opção Recuperar Proposição '
|
|
'para depois excluí-la.')
|
|
|
|
if proposicao[0][0] or proposicao[0][1]:
|
|
messages.error(request, msg)
|
|
return False
|
|
return True
|
|
|
|
class UpdateView(BaseLocalMixin, Crud.UpdateView):
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def _action_is_valid(self, request, *args, **kwargs):
|
|
|
|
proposicao = Proposicao.objects.filter(
|
|
id=kwargs['pk']).values_list(
|
|
'data_envio', 'data_recebimento')
|
|
|
|
username = request.user.username
|
|
|
|
if proposicao:
|
|
msg = ''
|
|
if proposicao[0][0] and proposicao[0][1]:
|
|
self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada e recebida.'
|
|
'Não pode mais ser editada'.format(kwargs['pk']))
|
|
msg = _('Proposição já foi enviada e recebida.'
|
|
'Não pode mais ser editada')
|
|
elif proposicao[0][0] and not proposicao[0][1]:
|
|
self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada mas ainda não recebida '
|
|
'pelo protocolo. Use a opção Recuperar Proposição '
|
|
'para voltar para edição.'.format(kwargs['pk']))
|
|
msg = _('Proposição já foi enviada mas ainda não recebida '
|
|
'pelo protocolo. Use a opção Recuperar Proposição '
|
|
'para voltar para edição.')
|
|
|
|
if proposicao[0][0] or proposicao[0][1]:
|
|
messages.error(request, msg)
|
|
return False
|
|
return True
|
|
|
|
def get_success_url(self):
|
|
|
|
tipo_texto = self.request.POST.get('tipo_texto', '')
|
|
username = self.request.user.username
|
|
|
|
if tipo_texto == 'T':
|
|
messages.info(self.request,
|
|
_('Sempre que uma Proposição é inclusa ou '
|
|
'alterada e a opção "Texto Articulado " for '
|
|
'marcada, você será redirecionado para a '
|
|
'edição do Texto Eletrônico.'))
|
|
self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou '
|
|
'alterada e a opção "Texto Articulado " for '
|
|
'marcada, você será redirecionado para a '
|
|
'edição do Texto Eletrônico.')
|
|
return reverse('sapl.materia:proposicao_ta',
|
|
kwargs={'pk': self.object.pk})
|
|
else:
|
|
return Crud.UpdateView.get_success_url(self)
|
|
|
|
class CreateView(Crud.CreateView):
|
|
logger = logging.getLogger(__name__)
|
|
form_class = ProposicaoForm
|
|
layout_key = None
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['subnav_template_name'] = ''
|
|
return context
|
|
|
|
def get_success_url(self):
|
|
|
|
tipo_texto = self.request.POST.get('tipo_texto', '')
|
|
username = self.request.user.username
|
|
|
|
if tipo_texto == 'T':
|
|
messages.info(self.request,
|
|
_('Sempre que uma Proposição é inclusa ou '
|
|
'alterada e a opção "Texto Articulado " for '
|
|
'marcada, você será redirecionado para o '
|
|
'Texto Eletrônico. Use a opção "Editar Texto" '
|
|
'para construir seu texto.'))
|
|
self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou '
|
|
'alterada e a opção "Texto Articulado " for '
|
|
'marcada, você será redirecionado para o '
|
|
'Texto Eletrônico. Use a opção "Editar Texto" '
|
|
'para construir seu texto.')
|
|
return reverse('sapl.materia:proposicao_ta',
|
|
kwargs={'pk': self.object.pk})
|
|
else:
|
|
return Crud.CreateView.get_success_url(self)
|
|
|
|
class ListView(Crud.ListView):
|
|
ordering = ['-data_envio', 'descricao']
|
|
|
|
def get_rows(self, object_list):
|
|
|
|
for obj in object_list:
|
|
if obj.data_recebimento is None:
|
|
obj.data_recebimento = 'Não recebida'\
|
|
if obj.data_envio else 'Não enviada'
|
|
else:
|
|
obj.data_recebimento = timezone.localtime(
|
|
obj.data_recebimento)
|
|
obj.data_recebimento = formats.date_format(
|
|
obj.data_recebimento, "DATETIME_FORMAT")
|
|
if obj.data_envio is None:
|
|
obj.data_envio = 'Em elaboração...'
|
|
else:
|
|
|
|
obj.data_envio = timezone.localtime(obj.data_envio)
|
|
obj.data_envio = formats.date_format(
|
|
obj.data_envio, "DATETIME_FORMAT")
|
|
|
|
return [self._as_row(obj) for obj in object_list]
|
|
|
|
|
|
class ReciboProposicaoView(TemplateView):
|
|
logger = logging.getLogger(__name__)
|
|
template_name = "materia/recibo_proposicao.html"
|
|
permission_required = ('materia.detail_proposicao', )
|
|
|
|
def has_permission(self):
|
|
perms = self.get_permission_required()
|
|
if not self.request.user.has_perms(perms):
|
|
return False
|
|
|
|
return (Proposicao.objects.filter(
|
|
id=self.kwargs['pk'],
|
|
autor__user_id=self.request.user.id).exists())
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(ReciboProposicaoView, self).get_context_data(
|
|
**kwargs)
|
|
proposicao = Proposicao.objects.get(pk=self.kwargs['pk'])
|
|
|
|
if proposicao.texto_original:
|
|
_hash = gerar_hash_arquivo(
|
|
proposicao.texto_original.path,
|
|
self.kwargs['pk'])
|
|
elif proposicao.texto_articulado.exists():
|
|
ta = proposicao.texto_articulado.first()
|
|
# FIXME hash para textos articulados
|
|
_hash = 'P' + ta.hash() + '/' + str(proposicao.id)
|
|
|
|
from sapl.utils import create_barcode
|
|
base64_data = create_barcode(_hash, 100, 500)
|
|
barcode = 'data:image/png;base64,{0}'.format(base64_data)
|
|
|
|
context.update({'proposicao': proposicao,
|
|
'hash': _hash,
|
|
'barcode': barcode})
|
|
return context
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
proposicao = Proposicao.objects.get(pk=self.kwargs['pk'])
|
|
username = request.user.username
|
|
|
|
if proposicao.data_envio:
|
|
return TemplateView.get(self, request, *args, **kwargs)
|
|
|
|
if not proposicao.data_envio and not proposicao.data_devolucao:
|
|
self.logger.error('user=' + username + '. Não é possível gerar recibo para uma '
|
|
'Proposição (pk={}) ainda não enviada.'.format(self.kwargs['pk']))
|
|
messages.error(request, _('Não é possível gerar recibo para uma '
|
|
'Proposição ainda não enviada.'))
|
|
elif proposicao.data_devolucao:
|
|
self.logger.error(
|
|
"user=" + username + ". Não é possível gerar recibo para proposicao de pk={}.".format(self.kwargs['pk']))
|
|
messages.error(request, _('Não é possível gerar recibo.'))
|
|
|
|
return redirect(reverse('sapl.materia:proposicao_detail',
|
|
kwargs={'pk': proposicao.pk}))
|
|
|
|
|
|
class RelatoriaCrud(MasterDetailCrud):
|
|
model = Relatoria
|
|
parent_field = 'materia'
|
|
help_topic = 'tramitacao_relatoria'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class CreateView(MasterDetailCrud.CreateView):
|
|
form_class = RelatoriaForm
|
|
layout_key = None
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_initial(self):
|
|
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
|
|
|
|
loc_atual = Tramitacao.objects.filter(materia=materia).last()
|
|
|
|
if loc_atual is None:
|
|
localizacao = 0
|
|
else:
|
|
comissao = loc_atual.unidade_tramitacao_destino.comissao
|
|
if comissao:
|
|
localizacao = comissao.pk
|
|
else:
|
|
localizacao = 0
|
|
|
|
return {'comissao': localizacao}
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = RelatoriaForm
|
|
layout_key = None
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_initial(self):
|
|
relatoria = Relatoria.objects.get(id=self.kwargs['pk'])
|
|
parlamentar = relatoria.parlamentar
|
|
comissao = relatoria.comissao
|
|
composicoes = [p.composicao for p in
|
|
Participacao.objects.filter(
|
|
parlamentar=parlamentar,
|
|
composicao__comissao=comissao)]
|
|
data_designacao = relatoria.data_designacao_relator
|
|
composicao = ''
|
|
for c in composicoes:
|
|
data_inicial = c.periodo.data_inicio
|
|
data_fim = c.periodo.data_fim if c.periodo.data_fim else timezone.now().date()
|
|
if data_inicial <= data_designacao <= data_fim:
|
|
composicao = c.id
|
|
break
|
|
return {'comissao': relatoria.comissao.id,
|
|
'parlamentar': relatoria.parlamentar.id,
|
|
'composicao': composicao}
|
|
|
|
|
|
class TramitacaoCrud(MasterDetailCrud):
|
|
model = Tramitacao
|
|
parent_field = 'materia'
|
|
help_topic = 'tramitacao_relatoria'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class BaseMixin(MasterDetailCrud.BaseMixin):
|
|
list_field_names = ['data_tramitacao', 'unidade_tramitacao_local',
|
|
'unidade_tramitacao_destino', 'status']
|
|
ordered_list = False
|
|
ordering = '-data_tramitacao',
|
|
|
|
class CreateView(MasterDetailCrud.CreateView):
|
|
form_class = TramitacaoForm
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_success_url(self):
|
|
return reverse('sapl.materia:tramitacao_list', kwargs={
|
|
'pk': self.kwargs['pk']})
|
|
|
|
def get_initial(self):
|
|
initial = super(CreateView, self).get_initial()
|
|
local = MateriaLegislativa.objects.get(
|
|
pk=self.kwargs['pk']).tramitacao_set.order_by(
|
|
'-data_tramitacao',
|
|
'-id').first()
|
|
|
|
if local:
|
|
initial['unidade_tramitacao_local'
|
|
] = local.unidade_tramitacao_destino.pk
|
|
else:
|
|
initial['unidade_tramitacao_local'] = ''
|
|
initial['data_tramitacao'] = timezone.now().date()
|
|
initial['ip'] = get_client_ip(self.request)
|
|
initial['user'] = self.request.user
|
|
return initial
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
username = self.request.user.username
|
|
|
|
ultima_tramitacao = Tramitacao.objects.filter(
|
|
materia_id=self.kwargs['pk']).order_by(
|
|
'-data_tramitacao',
|
|
'-timestamp',
|
|
'-id').first()
|
|
|
|
# TODO: Esta checagem foi inserida na issue #2027, mas é mesmo
|
|
# necessária?
|
|
if ultima_tramitacao:
|
|
if ultima_tramitacao.unidade_tramitacao_destino:
|
|
context['form'].fields[
|
|
'unidade_tramitacao_local'].choices = [
|
|
(ultima_tramitacao.unidade_tramitacao_destino.pk,
|
|
ultima_tramitacao.unidade_tramitacao_destino)]
|
|
else:
|
|
self.logger.error('user=' + username + '. Unidade de tramitação destino '
|
|
'da última tramitação não pode ser vazia!')
|
|
msg = _('Unidade de tramitação destino '
|
|
' da última tramitação não pode ser vazia!')
|
|
messages.add_message(self.request, messages.ERROR, msg)
|
|
|
|
primeira_tramitacao = not(Tramitacao.objects.filter(
|
|
materia_id=int(kwargs['root_pk'])).exists())
|
|
|
|
# Se não for a primeira tramitação daquela matéria, o campo
|
|
# não pode ser modificado
|
|
if not primeira_tramitacao:
|
|
context['form'].fields[
|
|
'unidade_tramitacao_local'].widget.attrs['readonly'] = True
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
|
|
self.object = form.save()
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
self.logger.debug("user=" + username + ". Tentando enviar Tramitacao (sender={}, post={}, request={})."
|
|
.format(Tramitacao, self.object, self.request))
|
|
tramitacao_signal.send(sender=Tramitacao,
|
|
post=self.object,
|
|
request=self.request)
|
|
except Exception as e:
|
|
msg = _('Tramitação criada, mas e-mail de acompanhamento '
|
|
'de matéria não enviado. Há problemas na configuração '
|
|
'do e-mail.')
|
|
self.logger.warning('user=' + username + '. Tramitação criada, mas e-mail de acompanhamento '
|
|
'de matéria não enviado. Há problemas na configuração '
|
|
'do e-mail. ' + str(e))
|
|
messages.add_message(self.request, messages.WARNING, msg)
|
|
return HttpResponseRedirect(self.get_success_url())
|
|
return super().form_valid(form)
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = TramitacaoUpdateForm
|
|
logger = logging.getLogger(__name__)
|
|
|
|
layout_key = 'TramitacaoUpdate'
|
|
|
|
def form_valid(self, form):
|
|
dict_objeto_antigo = Tramitacao.objects.get(
|
|
pk=self.kwargs['pk']).__dict__
|
|
|
|
self.object = form.save()
|
|
dict_objeto_novo = self.object.__dict__
|
|
|
|
user = self.request.user
|
|
|
|
atributos = [
|
|
'data_tramitacao', 'unidade_tramitacao_destino_id', 'status_id', 'texto',
|
|
'data_encaminhamento', 'data_fim_prazo', 'urgente', 'turno'
|
|
]
|
|
|
|
# Se não houve qualquer alteração em um dos dados, mantém o usuário
|
|
# e ip
|
|
for atributo in atributos:
|
|
if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]:
|
|
self.object.user = user
|
|
self.object.ip = get_client_ip(self.request)
|
|
self.object.save()
|
|
break
|
|
|
|
try:
|
|
self.logger.debug("user=" + user.username + ". Tentando enviar Tramitacao (sender={}, post={}, request={}"
|
|
.format(Tramitacao, self.object, self.request))
|
|
tramitacao_signal.send(sender=Tramitacao,
|
|
post=self.object,
|
|
request=self.request)
|
|
except Exception:
|
|
msg = _('Tramitação atualizada, mas e-mail de acompanhamento '
|
|
'de matéria não enviado. Há problemas na configuração '
|
|
'do e-mail.')
|
|
self.logger.warning('user=' + user.username + '. Tramitação atualizada, mas e-mail de acompanhamento '
|
|
'de matéria não enviado. Há problemas na configuração '
|
|
'do e-mail.')
|
|
messages.add_message(self.request, messages.WARNING, msg)
|
|
return HttpResponseRedirect(self.get_success_url())
|
|
return super().form_valid(form)
|
|
|
|
class ListView(MasterDetailCrud.ListView):
|
|
|
|
def get_queryset(self):
|
|
qs = super(MasterDetailCrud.ListView, self).get_queryset()
|
|
kwargs = {self.crud.parent_field: self.kwargs['pk']}
|
|
return qs.filter(**kwargs).order_by('-data_tramitacao',
|
|
'-timestamp',
|
|
'-id')
|
|
|
|
class DeleteView(MasterDetailCrud.DeleteView):
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def delete(self, request, *args, **kwargs):
|
|
tramitacao = Tramitacao.objects.get(id=self.kwargs['pk'])
|
|
materia = tramitacao.materia
|
|
url = reverse('sapl.materia:tramitacao_list',
|
|
kwargs={'pk': materia.id})
|
|
|
|
ultima_tramitacao = materia.tramitacao_set.order_by(
|
|
'-data_tramitacao',
|
|
'-timestamp',
|
|
'-id').first()
|
|
|
|
if tramitacao.pk != ultima_tramitacao.pk:
|
|
username = request.user.username
|
|
self.logger.error("user=" + username + ". Não é possível deletar a tramitação de pk={}. "
|
|
"Somente a última tramitação (pk={}) pode ser deletada!."
|
|
.format(tramitacao.pk, ultima_tramitacao.pk))
|
|
msg = _('Somente a última tramitação pode ser deletada!')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
return HttpResponseRedirect(url)
|
|
else:
|
|
tramitacoes_deletar = [tramitacao.id]
|
|
if materia.tramitacao_set.count() == 0:
|
|
materia.em_tramitacao = False
|
|
materia.save()
|
|
tramitar_anexadas = sapl.base.models.AppConfig.attr(
|
|
'tramitacao_materia')
|
|
if tramitar_anexadas:
|
|
mat_anexadas = lista_anexados(materia)
|
|
for ma in mat_anexadas:
|
|
tram_anexada = ma.tramitacao_set.last()
|
|
if compara_tramitacoes_mat(tram_anexada, tramitacao):
|
|
tramitacoes_deletar.append(tram_anexada.id)
|
|
if ma.tramitacao_set.count() == 0:
|
|
ma.em_tramitacao = False
|
|
ma.save()
|
|
Tramitacao.objects.filter(id__in=tramitacoes_deletar).delete()
|
|
|
|
return HttpResponseRedirect(url)
|
|
|
|
class DetailView(MasterDetailCrud.DetailView):
|
|
|
|
template_name = "materia/tramitacao_detail.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['user'] = self.request.user
|
|
return context
|
|
|
|
|
|
def montar_helper_documento_acessorio(self):
|
|
autor_row = montar_row_autor('autor')
|
|
self.helper = SaplFormHelper()
|
|
self.helper.layout = SaplFormLayout(*self.get_layout())
|
|
|
|
# Adiciona o novo campo 'autor' e mecanismo de busca
|
|
self.helper.layout[0][0].append(HTML(autor_label))
|
|
self.helper.layout[0][0].append(HTML(autor_modal))
|
|
self.helper.layout[0][1] = autor_row
|
|
|
|
# Remove botões que estão fora do form
|
|
self.helper.layout[1].pop()
|
|
|
|
# Adiciona novos botões dentro do form
|
|
self.helper.layout[0][3][0].insert(1, form_actions(more=[
|
|
HTML('<a href="{{ view.cancel_url }}"'
|
|
' class="btn btn-dark">Cancelar</a>')]))
|
|
|
|
|
|
class DocumentoAcessorioCrud(MasterDetailCrud):
|
|
model = DocumentoAcessorio
|
|
parent_field = 'materia'
|
|
help_topic = 'despacho_autoria'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class BaseMixin(MasterDetailCrud.BaseMixin):
|
|
list_field_names = ['nome', 'tipo', 'data', 'autor', 'arquivo']
|
|
|
|
class CreateView(MasterDetailCrud.CreateView):
|
|
form_class = DocumentoAcessorioForm
|
|
|
|
def __init__(self, **kwargs):
|
|
super(MasterDetailCrud.CreateView, self).__init__(**kwargs)
|
|
|
|
def get_initial(self):
|
|
initial = super(CreateView, self).get_initial()
|
|
initial['data'] = timezone.now().date()
|
|
|
|
return initial
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(
|
|
MasterDetailCrud.CreateView, self).get_context_data(**kwargs)
|
|
return context
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = DocumentoAcessorioForm
|
|
|
|
def __init__(self, **kwargs):
|
|
super(MasterDetailCrud.UpdateView, self).__init__(**kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(UpdateView, self).get_context_data(**kwargs)
|
|
return context
|
|
|
|
|
|
class AutoriaCrud(MasterDetailCrud):
|
|
model = Autoria
|
|
parent_field = 'materia'
|
|
help_topic = 'despacho_autoria'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
list_field_names = ['autor', 'autor__tipo__descricao', 'primeiro_autor']
|
|
|
|
class LocalBaseMixin():
|
|
form_class = AutoriaForm
|
|
|
|
@property
|
|
def layout_key(self):
|
|
return None
|
|
|
|
class CreateView(LocalBaseMixin, MasterDetailCrud.CreateView):
|
|
|
|
def get_initial(self):
|
|
initial = super().get_initial()
|
|
materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
|
|
initial['data_relativa'] = materia.data_apresentacao
|
|
initial['autor'] = []
|
|
initial['materia'] = materia
|
|
return initial
|
|
|
|
class UpdateView(LocalBaseMixin, MasterDetailCrud.UpdateView):
|
|
|
|
def get_initial(self):
|
|
initial = super().get_initial()
|
|
initial.update({
|
|
'data_relativa': self.object.materia.data_apresentacao,
|
|
'tipo_autor': self.object.autor.tipo.id,
|
|
'materia': self.object.materia
|
|
})
|
|
return initial
|
|
|
|
|
|
class AutoriaMultiCreateView(PermissionRequiredForAppCrudMixin, FormView):
|
|
app_label = sapl.materia.apps.AppConfig.label
|
|
form_class = AutoriaMultiCreateForm
|
|
template_name = 'materia/autoria_multicreate_form.html'
|
|
|
|
@classmethod
|
|
def get_url_regex(cls):
|
|
return r'^(?P<pk>\d+)/%s/multicreate' % cls.model._meta.model_name
|
|
|
|
@property
|
|
def layout_key(self):
|
|
return None
|
|
|
|
def get_initial(self):
|
|
initial = super().get_initial()
|
|
self.materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
|
|
initial['data_relativa'] = self.materia.data_apresentacao
|
|
initial['autores'] = self.materia.autores.all()
|
|
return initial
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = '%s <small>(%s)</small>' % (
|
|
_('Adicionar Várias Autorias'), self.materia)
|
|
return context
|
|
|
|
def get_success_url(self):
|
|
messages.add_message(
|
|
self.request, messages.SUCCESS,
|
|
_('Autorias adicionadas com sucesso.'))
|
|
return reverse(
|
|
'sapl.materia:autoria_list', kwargs={'pk': self.materia.pk})
|
|
|
|
def form_valid(self, form):
|
|
autores_selecionados = form.cleaned_data['autor']
|
|
primeiro_autor = form.cleaned_data['primeiro_autor']
|
|
for autor in autores_selecionados:
|
|
Autoria.objects.create(materia=self.materia,
|
|
autor=autor, primeiro_autor=primeiro_autor)
|
|
|
|
return FormView.form_valid(self, form)
|
|
|
|
|
|
class DespachoInicialMultiCreateView(PermissionRequiredForAppCrudMixin, FormView):
|
|
app_label = sapl.materia.apps.AppConfig.label
|
|
form_class = DespachoInicialCreateForm
|
|
template_name = 'materia/despachoinicial_multicreate_form.html'
|
|
|
|
def get_initial(self):
|
|
initial = super().get_initial()
|
|
self.materia = MateriaLegislativa.objects.get(id=self.kwargs['pk'])
|
|
initial['materia'] = self.materia
|
|
return initial
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['title'] = '%s <small>(%s)</small>' % (
|
|
_('Adicionar Vários Despachos'), self.materia)
|
|
context['root_pk'] = self.kwargs['pk']
|
|
context['subnav_template_name'] = 'materia/subnav.yaml'
|
|
return context
|
|
|
|
def get_success_url(self):
|
|
messages.add_message(
|
|
self.request, messages.SUCCESS,
|
|
_('Despachos adicionados com sucesso.'))
|
|
return reverse(
|
|
'sapl.materia:despachoinicial_list', kwargs={'pk': self.materia.pk})
|
|
|
|
def form_valid(self, form):
|
|
comissoes_selecionadas = form.cleaned_data['comissao']
|
|
for comissao in comissoes_selecionadas:
|
|
DespachoInicial.objects.create(
|
|
materia=self.materia, comissao=comissao)
|
|
|
|
return FormView.form_valid(self, form)
|
|
|
|
@property
|
|
def cancel_url(self):
|
|
return reverse(
|
|
'sapl.materia:despachoinicial_list', kwargs={'pk': self.materia.pk})
|
|
|
|
|
|
class DespachoInicialCrud(MasterDetailCrud):
|
|
model = DespachoInicial
|
|
parent_field = 'materia'
|
|
help_topic = 'despacho_autoria'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = DespachoInicialForm
|
|
|
|
|
|
class LegislacaoCitadaCrud(MasterDetailCrud):
|
|
model = LegislacaoCitada
|
|
parent_field = 'materia'
|
|
help_topic = 'legislacao_cita_matanexada'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class BaseMixin(MasterDetailCrud.BaseMixin):
|
|
list_field_names = ['norma', 'disposicoes']
|
|
|
|
def resolve_url(self, suffix, args=None):
|
|
namespace = 'sapl.materia'
|
|
return reverse('%s:%s' % (namespace, self.url_name(suffix)),
|
|
args=args)
|
|
|
|
class CreateView(MasterDetailCrud.CreateView):
|
|
form_class = LegislacaoCitadaForm
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = LegislacaoCitadaForm
|
|
|
|
def get_initial(self):
|
|
initial = super(UpdateView, self).get_initial()
|
|
initial['tipo'] = self.object.norma.tipo.id
|
|
initial['numero'] = self.object.norma.numero
|
|
initial['ano'] = self.object.norma.ano
|
|
return initial
|
|
|
|
class DetailView(MasterDetailCrud.DetailView):
|
|
|
|
layout_key = 'LegislacaoCitadaDetail'
|
|
|
|
class DeleteView(MasterDetailCrud.DeleteView):
|
|
pass
|
|
|
|
|
|
class NumeracaoCrud(MasterDetailCrud):
|
|
model = Numeracao
|
|
parent_field = 'materia'
|
|
help_topic = 'numeracao_docsacess'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
|
|
class AnexadaCrud(MasterDetailCrud):
|
|
model = Anexada
|
|
parent_field = 'materia_principal'
|
|
help_topic = 'materia_anexada'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class BaseMixin(MasterDetailCrud.BaseMixin):
|
|
list_field_names = ['materia_anexada', 'data_anexacao']
|
|
|
|
class CreateView(MasterDetailCrud.CreateView):
|
|
form_class = AnexadaForm
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = AnexadaForm
|
|
|
|
def get_initial(self):
|
|
initial = super(UpdateView, self).get_initial()
|
|
initial['tipo'] = self.object.materia_anexada.tipo.id
|
|
initial['numero'] = self.object.materia_anexada.numero
|
|
initial['ano'] = self.object.materia_anexada.ano
|
|
return initial
|
|
|
|
class DetailView(MasterDetailCrud.DetailView):
|
|
|
|
@property
|
|
def layout_key(self):
|
|
return 'AnexadaDetail'
|
|
|
|
|
|
class MateriaAssuntoCrud(MasterDetailCrud):
|
|
model = MateriaAssunto
|
|
parent_field = 'materia'
|
|
help_topic = ''
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class BaseMixin(MasterDetailCrud.BaseMixin):
|
|
list_field_names = ['assunto', 'materia']
|
|
|
|
class CreateView(MasterDetailCrud.CreateView):
|
|
form_class = MateriaAssuntoForm
|
|
|
|
def get_initial(self):
|
|
initial = super(CreateView, self).get_initial()
|
|
initial['materia'] = self.kwargs['pk']
|
|
return initial
|
|
|
|
class UpdateView(MasterDetailCrud.UpdateView):
|
|
form_class = MateriaAssuntoForm
|
|
|
|
def get_initial(self):
|
|
initial = super(UpdateView, self).get_initial()
|
|
initial['materia'] = self.get_object().materia
|
|
initial['assunto'] = self.get_object().assunto
|
|
return initial
|
|
|
|
|
|
class MateriaLegislativaCrud(Crud):
|
|
model = MateriaLegislativa
|
|
help_topic = 'materia_legislativa'
|
|
public = [RP_LIST, RP_DETAIL]
|
|
|
|
class BaseMixin(Crud.BaseMixin):
|
|
list_field_names = ['tipo', 'numero', 'ano', 'data_apresentacao']
|
|
|
|
list_url = ''
|
|
|
|
@property
|
|
def search_url(self):
|
|
namespace = self.model._meta.app_config.name
|
|
return reverse('%s:%s' % (namespace, 'pesquisar_materia'))
|
|
|
|
class CreateView(Crud.CreateView):
|
|
|
|
form_class = MateriaLegislativaForm
|
|
|
|
def get_initial(self):
|
|
initial = super().get_initial()
|
|
|
|
initial['user'] = self.request.user
|
|
initial['ip'] = get_client_ip(self.request)
|
|
|
|
return initial
|
|
|
|
@property
|
|
def cancel_url(self):
|
|
return self.search_url
|
|
|
|
class UpdateView(Crud.UpdateView):
|
|
|
|
form_class = MateriaLegislativaForm
|
|
|
|
def form_valid(self, form):
|
|
dict_objeto_antigo = MateriaLegislativa.objects.get(
|
|
pk=self.kwargs['pk']
|
|
).__dict__
|
|
|
|
self.object = form.save()
|
|
dict_objeto_novo = self.object.__dict__
|
|
|
|
atributos = [
|
|
'tipo_id', 'ano', 'numero', 'data_apresentacao', 'numero_protocolo',
|
|
'tipo_apresentacao', 'texto_original', 'apelido', 'dias_prazo', 'polemica',
|
|
'objeto', 'regime_tramitacao_id', 'em_tramitacao', 'data_fim_prazo',
|
|
'data_publicacao', 'complementar', 'tipo_origem_externa_id',
|
|
'numero_origem_externa', 'ano_origem_externa', 'local_origem_externa_id',
|
|
'data_origem_externa', 'ementa', 'indexacao', 'observacao'
|
|
]
|
|
|
|
for atributo in atributos:
|
|
if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]:
|
|
self.object.user = self.request.user
|
|
self.object.ip = get_client_ip(self.request)
|
|
self.object.save()
|
|
break
|
|
|
|
if Anexada.objects.filter(materia_principal=self.kwargs['pk']).exists():
|
|
materia = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
|
|
anexadas = lista_anexados(materia)
|
|
|
|
for anexada in anexadas:
|
|
anexada.em_tramitacao = True if form.instance.em_tramitacao else False
|
|
anexada.save()
|
|
|
|
return super().form_valid(form)
|
|
|
|
@property
|
|
def cancel_url(self):
|
|
return self.search_url
|
|
|
|
class DeleteView(Crud.DeleteView):
|
|
|
|
def get_success_url(self):
|
|
return self.search_url
|
|
|
|
class DetailView(Crud.DetailView):
|
|
|
|
layout_key = 'MateriaLegislativaDetail'
|
|
template_name = "materia/materialegislativa_detail.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['user'] = self.request.user
|
|
context['materia'] = MateriaLegislativa.objects.get(
|
|
pk=self.kwargs['pk'])
|
|
return context
|
|
|
|
class ListView(Crud.ListView, RedirectView):
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
namespace = self.model._meta.app_config.name
|
|
return reverse('%s:%s' % (namespace, 'pesquisar_materia'))
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return RedirectView.get(self, request, *args, **kwargs)
|
|
|
|
|
|
# FIXME - qual a finalidade dessa classe??
|
|
class DocumentoAcessorioView(PermissionRequiredMixin, CreateView):
|
|
template_name = "materia/documento_acessorio.html"
|
|
form_class = DocumentoAcessorioForm
|
|
permission_required = ('materia.add_documentoacessorio', )
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
|
|
docs = DocumentoAcessorio.objects.filter(
|
|
materia_id=kwargs['pk']).order_by('data')
|
|
form = DocumentoAcessorioForm()
|
|
|
|
return self.render_to_response(
|
|
{'object': materia,
|
|
'form': form,
|
|
'docs': docs})
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
form = self.get_form()
|
|
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
|
|
docs_list = DocumentoAcessorio.objects.filter(
|
|
materia_id=kwargs['pk'])
|
|
|
|
if form.is_valid():
|
|
documento_acessorio = form.save(commit=False)
|
|
documento_acessorio.materia = materia
|
|
documento_acessorio.save()
|
|
return self.form_valid(form)
|
|
else:
|
|
return self.render_to_response({'form': form,
|
|
'object': materia,
|
|
'docs': docs_list})
|
|
|
|
def get_success_url(self):
|
|
pk = self.kwargs['pk']
|
|
return reverse('sapl.materia:documento_acessorio', kwargs={'pk': pk})
|
|
|
|
|
|
class AcompanhamentoConfirmarView(TemplateView):
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_redirect_url(self, email):
|
|
username = self.request.user.username
|
|
self.logger.debug(
|
|
'user=' + username + '. Esta matéria está sendo acompanhada pelo e-mail: %s' % (email))
|
|
msg = _('Esta matéria está sendo acompanhada pelo e-mail: %s') % (
|
|
email)
|
|
messages.add_message(self.request, messages.SUCCESS, msg)
|
|
return reverse('sapl.materia:materialegislativa_detail',
|
|
kwargs={'pk': self.kwargs['pk']})
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
materia_id = kwargs['pk']
|
|
hash_txt = request.GET.get('hash_txt', '')
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
self.logger.info("user=" + username + ". Tentando obter objeto AcompanhamentoMateria (materia_id={}, hash={})."
|
|
.format(materia_id, hash_txt))
|
|
acompanhar = AcompanhamentoMateria.objects.get(
|
|
materia_id=materia_id,
|
|
hash=hash_txt)
|
|
except ObjectDoesNotExist:
|
|
self.logger.error("user=" + username + ". Objeto AcompanhamentoMateria(materia_id={}, hash={}) não encontrado."
|
|
.format(materia_id, hash_txt))
|
|
raise Http404()
|
|
except MultipleObjectsReturned as e:
|
|
# A melhor solução deve ser permitir que a exceção
|
|
# (MultipleObjectsReturned) seja lançada e vá para o log,
|
|
# pois só poderá ser causada por um erro de desenvolvimente
|
|
self.logger.error('user=' + username + '.' + str(e))
|
|
pass
|
|
acompanhar.confirmado = True
|
|
acompanhar.save()
|
|
|
|
return HttpResponseRedirect(self.get_redirect_url(acompanhar.email))
|
|
|
|
|
|
class AcompanhamentoExcluirView(TemplateView):
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_success_url(self):
|
|
username = self.request.user.username
|
|
self.logger.debug("user=" + username +
|
|
". Você parou de acompanhar esta matéria.")
|
|
msg = _('Você parou de acompanhar esta matéria.')
|
|
messages.add_message(self.request, messages.INFO, msg)
|
|
return reverse('sapl.materia:materialegislativa_detail',
|
|
kwargs={'pk': self.kwargs['pk']})
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
materia_id = kwargs['pk']
|
|
hash_txt = request.GET.get('hash_txt', '')
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
self.logger.info("user=" + username + ". Tentando deletar objeto AcompanhamentoMateria (materia_id={}, hash={})."
|
|
.format(materia_id, hash_txt))
|
|
AcompanhamentoMateria.objects.get(materia_id=materia_id,
|
|
hash=hash_txt).delete()
|
|
except ObjectDoesNotExist:
|
|
self.logger.error("user=" + username + ". Objeto AcompanhamentoMateria (materia_id={}, hash={}) não encontrado."
|
|
.format(materia_id, hash_txt))
|
|
pass
|
|
|
|
return HttpResponseRedirect(self.get_success_url())
|
|
|
|
|
|
class MateriaLegislativaPesquisaView(FilterView):
|
|
model = MateriaLegislativa
|
|
filterset_class = MateriaLegislativaFilterSet
|
|
paginate_by = 50
|
|
|
|
def get_filterset_kwargs(self, filterset_class):
|
|
super(MateriaLegislativaPesquisaView,
|
|
self).get_filterset_kwargs(filterset_class)
|
|
|
|
kwargs = {'data': self.request.GET or None}
|
|
|
|
tipo_listagem = self.request.GET.get('tipo_listagem', '1')
|
|
tipo_listagem = '1' if not tipo_listagem else tipo_listagem
|
|
|
|
qs = self.get_queryset().distinct()
|
|
if tipo_listagem == '1':
|
|
|
|
status_tramitacao = self.request.GET.get('tramitacao__status')
|
|
unidade_destino = self.request.GET.get(
|
|
'tramitacao__unidade_tramitacao_destino')
|
|
|
|
if status_tramitacao and unidade_destino:
|
|
lista = filtra_tramitacao_destino_and_status(status_tramitacao,
|
|
unidade_destino)
|
|
qs = qs.filter(id__in=lista).distinct()
|
|
|
|
elif status_tramitacao:
|
|
lista = filtra_tramitacao_status(status_tramitacao)
|
|
qs = qs.filter(id__in=lista).distinct()
|
|
|
|
elif unidade_destino:
|
|
lista = filtra_tramitacao_destino(unidade_destino)
|
|
qs = qs.filter(id__in=lista).distinct()
|
|
|
|
qs = qs.prefetch_related("autoria_set",
|
|
"autoria_set__autor",
|
|
"numeracao_set",
|
|
"anexadas",
|
|
"tipo",
|
|
"texto_articulado",
|
|
"tramitacao_set",
|
|
"tramitacao_set__status",
|
|
"tramitacao_set__unidade_tramitacao_local",
|
|
"tramitacao_set__unidade_tramitacao_destino",
|
|
"normajuridica_set",
|
|
"registrovotacao_set",
|
|
"documentoacessorio_set")
|
|
else:
|
|
|
|
qs = qs.prefetch_related("autoria_set",
|
|
"numeracao_set",
|
|
"autoria_set__autor",
|
|
"tipo",)
|
|
|
|
if 'o' in self.request.GET and not self.request.GET['o']:
|
|
qs = qs.order_by('-ano', 'tipo__sigla', '-numero')
|
|
|
|
kwargs.update({
|
|
'queryset': qs,
|
|
})
|
|
return kwargs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(MateriaLegislativaPesquisaView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['title'] = _('Pesquisar Matéria Legislativa')
|
|
|
|
tipo_listagem = self.request.GET.get('tipo_listagem', '1')
|
|
tipo_listagem = '1' if not tipo_listagem else tipo_listagem
|
|
|
|
context['tipo_listagem'] = tipo_listagem
|
|
|
|
qr = self.request.GET.copy()
|
|
if 'page' in qr:
|
|
del qr['page']
|
|
|
|
paginator = context['paginator']
|
|
page_obj = context['page_obj']
|
|
|
|
context['page_range'] = make_pagination(
|
|
page_obj.number, paginator.num_pages)
|
|
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
|
|
context['show_results'] = show_results_filter_set(qr)
|
|
|
|
context['USE_SOLR'] = settings.USE_SOLR if hasattr(
|
|
settings, 'USE_SOLR') else False
|
|
|
|
return context
|
|
|
|
|
|
class AcompanhamentoMateriaView(CreateView):
|
|
logger = logging.getLogger(__name__)
|
|
template_name = "materia/acompanhamento_materia.html"
|
|
|
|
def get_random_chars(self):
|
|
s = ascii_letters + digits
|
|
return ''.join(choice(s) for i in range(choice([6, 7])))
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if not mail_service_configured():
|
|
self.logger.warning(_('Servidor de email não configurado.'))
|
|
messages.error(request, _('Serviço de Acompanhamento de '
|
|
'Matérias não foi configurado'))
|
|
return redirect('/')
|
|
|
|
pk = self.kwargs['pk']
|
|
materia = MateriaLegislativa.objects.get(id=pk)
|
|
|
|
return self.render_to_response(
|
|
{'form': AcompanhamentoMateriaForm(),
|
|
'materia': materia})
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
|
|
if not settings.EMAIL_HOST:
|
|
self.logger.warning(_('Servidor de email não configurado.'))
|
|
messages.error(request, _('Serviço de Acompanhamento de '
|
|
'Matérias não foi configurado'))
|
|
return redirect('/')
|
|
|
|
form = AcompanhamentoMateriaForm(request.POST)
|
|
pk = self.kwargs['pk']
|
|
materia = MateriaLegislativa.objects.get(id=pk)
|
|
|
|
if form.is_valid():
|
|
email = form.cleaned_data['email']
|
|
usuario = request.user
|
|
|
|
hash_txt = self.get_random_chars()
|
|
|
|
acompanhar = AcompanhamentoMateria.objects.get_or_create(
|
|
materia=materia,
|
|
email=form.data['email'])
|
|
|
|
# Se o segundo elemento do retorno do get_or_create for True
|
|
# quer dizer que o elemento não existia
|
|
if acompanhar[1]:
|
|
acompanhar = acompanhar[0]
|
|
acompanhar.hash = hash_txt
|
|
acompanhar.usuario = usuario.username
|
|
acompanhar.confirmado = False
|
|
acompanhar.save()
|
|
|
|
base_url = get_base_url(request)
|
|
|
|
destinatario = AcompanhamentoMateria.objects.get(
|
|
materia=materia,
|
|
email=email,
|
|
confirmado=False)
|
|
casa = CasaLegislativa.objects.first()
|
|
|
|
do_envia_email_confirmacao(base_url,
|
|
casa,
|
|
"materia",
|
|
materia,
|
|
destinatario)
|
|
self.logger.debug('user=' + usuario.username + '. Foi enviado um e-mail de confirmação. Confira sua caixa \
|
|
de mensagens e clique no link que nós enviamos para \
|
|
confirmar o acompanhamento desta matéria.')
|
|
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
|
|
de mensagens e clique no link que nós enviamos para \
|
|
confirmar o acompanhamento desta matéria.')
|
|
messages.add_message(request, messages.SUCCESS, msg)
|
|
|
|
# Se o elemento existir e o email não foi confirmado:
|
|
# gerar novo hash e reenviar mensagem de email
|
|
elif not acompanhar[0].confirmado:
|
|
acompanhar = acompanhar[0]
|
|
acompanhar.hash = hash_txt
|
|
acompanhar.save()
|
|
|
|
base_url = get_base_url(request)
|
|
|
|
destinatario = AcompanhamentoMateria.objects.get(
|
|
materia=materia,
|
|
email=email,
|
|
confirmado=False
|
|
)
|
|
|
|
casa = CasaLegislativa.objects.first()
|
|
|
|
do_envia_email_confirmacao(base_url,
|
|
casa,
|
|
"materia",
|
|
materia,
|
|
destinatario)
|
|
|
|
self.logger.debug('user=' + usuario.username + '. Foi enviado um e-mail de confirmação. Confira sua caixa \
|
|
de mensagens e clique no link que nós enviamos para \
|
|
confirmar o acompanhamento desta matéria.')
|
|
|
|
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
|
|
de mensagens e clique no link que nós enviamos para \
|
|
confirmar o acompanhamento desta matéria.')
|
|
messages.add_message(request, messages.SUCCESS, msg)
|
|
|
|
# Caso esse Acompanhamento já exista
|
|
# avisa ao usuário que essa matéria já está sendo acompanhada
|
|
else:
|
|
self.logger.debug("user=" + usuario.username +
|
|
". Este e-mail já está acompanhando essa matéria.")
|
|
msg = _('Este e-mail já está acompanhando essa matéria.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
|
|
return self.render_to_response(
|
|
{'form': form,
|
|
'materia': materia
|
|
})
|
|
return HttpResponseRedirect(self.get_success_url())
|
|
else:
|
|
return self.render_to_response(
|
|
{'form': form,
|
|
'materia': materia})
|
|
|
|
def get_success_url(self):
|
|
return reverse('sapl.materia:materialegislativa_detail',
|
|
kwargs={'pk': self.kwargs['pk']})
|
|
|
|
|
|
class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
|
|
filterset_class = AcessorioEmLoteFilterSet
|
|
template_name = 'materia/em_lote/acessorio.html'
|
|
permission_required = ('materia.add_documentoacessorio',)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(DocumentoAcessorioEmLoteView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['title'] = _('Documentos Acessórios em Lote')
|
|
# Verifica se os campos foram preenchidos
|
|
if not self.filterset.form.is_valid():
|
|
return context
|
|
|
|
qr = self.request.GET.copy()
|
|
context['tipos_docs'] = TipoDocumento.objects.all()
|
|
context['object_list'] = context['object_list'].order_by(
|
|
'ano', 'numero')
|
|
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):
|
|
username = request.user.username
|
|
marcadas = request.POST.getlist('materia_id')
|
|
|
|
if len(marcadas) == 0:
|
|
msg = _('Nenhuma máteria foi selecionada.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
return self.get(request, self.kwargs)
|
|
|
|
tipo = TipoDocumento.objects.get(descricao=request.POST['tipo'])
|
|
|
|
tz = timezone.get_current_timezone()
|
|
|
|
if len(request.POST['autor']) > 50:
|
|
msg = _('Autor tem que ter menos do que 50 caracteres.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
return self.get(request, self.kwargs)
|
|
|
|
tmp_name = os.path.join(MEDIA_ROOT, request.FILES['arquivo'].name)
|
|
with open(tmp_name, 'wb') as destination:
|
|
for chunk in request.FILES['arquivo'].chunks():
|
|
destination.write(chunk)
|
|
try:
|
|
doc_data = tz.localize(datetime.strptime(
|
|
request.POST['data'], "%d/%m/%Y"))
|
|
except Exception as e:
|
|
msg = _(
|
|
'Formato da data incorreto. O formato deve ser da forma dd/mm/aaaa.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
self.logger.error("User={}. {}. Data inserida: {}".format(
|
|
username, str(msg), request.POST['data']))
|
|
os.remove(tmp_name)
|
|
return self.get(request, self.kwargs)
|
|
|
|
for materia_id in marcadas:
|
|
doc = DocumentoAcessorio()
|
|
doc.materia_id = materia_id
|
|
doc.tipo = tipo
|
|
doc.nome = request.POST['nome']
|
|
doc.data = doc_data
|
|
doc.autor = request.POST['autor']
|
|
doc.ementa = request.POST['ementa']
|
|
doc.arquivo.name = tmp_name
|
|
try:
|
|
doc.clean_fields()
|
|
except ValidationError as e:
|
|
for m in ['%s: %s' % (DocumentoAcessorio()._meta.get_field(k).verbose_name, '</br>'.join(v))
|
|
for k, v in e.message_dict.items()]:
|
|
# Insere as mensagens de erro no formato:
|
|
# 'verbose_name do nome do campo': 'mensagem de erro'
|
|
messages.add_message(request, messages.ERROR, m)
|
|
self.logger.error("User={}. {}. Nome do arquivo: {}.".format(
|
|
username, str(msg), request.FILES['arquivo'].name))
|
|
os.remove(tmp_name)
|
|
return self.get(request, self.kwargs)
|
|
doc.save()
|
|
diretorio = os.path.join(MEDIA_ROOT,
|
|
'sapl/public/documentoacessorio',
|
|
str(doc_data.year),
|
|
str(doc.id))
|
|
if not os.path.exists(diretorio):
|
|
os.makedirs(diretorio)
|
|
file_path = os.path.join(diretorio,
|
|
request.FILES['arquivo'].name)
|
|
shutil.copy2(tmp_name, file_path)
|
|
doc.arquivo.name = file_path.split(
|
|
MEDIA_ROOT + "/")[1] # Retira MEDIA_ROOT do nome
|
|
doc.save()
|
|
os.remove(tmp_name)
|
|
|
|
msg = _('Documento(s) criado(s).')
|
|
messages.add_message(request, messages.SUCCESS, msg)
|
|
return self.get(request, self.kwargs)
|
|
|
|
|
|
class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
|
|
filterset_class = AnexadaEmLoteFilterSet
|
|
template_name = 'materia/em_lote/anexada.html'
|
|
permission_required = ('materia.add_documentoacessorio',)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(MateriaAnexadaEmLoteView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['root_pk'] = self.kwargs['pk']
|
|
|
|
context['subnav_template_name'] = 'materia/subnav.yaml'
|
|
|
|
context['title'] = _('Matérias Anexadas em Lote')
|
|
|
|
# Verifica se os campos foram preenchidos
|
|
if not self.request.GET.get('tipo', " "):
|
|
msg = _('Por favor, selecione um tipo de matéria.')
|
|
messages.add_message(self.request, messages.ERROR, msg)
|
|
|
|
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
|
|
msg = _('Por favor, preencha as datas.')
|
|
messages.add_message(self.request, messages.ERROR, msg)
|
|
|
|
return context
|
|
|
|
if not self.request.GET.get('data_apresentacao_0', " ") or not self.request.GET.get('data_apresentacao_1', " "):
|
|
msg = _('Por favor, preencha as datas.')
|
|
messages.add_message(self.request, messages.ERROR, msg)
|
|
return context
|
|
|
|
qr = self.request.GET.copy()
|
|
context['object_list'] = context['object_list'].order_by(
|
|
'numero', '-ano')
|
|
principal = MateriaLegislativa.objects.get(pk=self.kwargs['pk'])
|
|
not_list = [self.kwargs['pk']] + \
|
|
[m for m in principal.materia_principal_set.all(
|
|
).values_list('materia_anexada_id', flat=True)]
|
|
context['object_list'] = context['object_list'].exclude(
|
|
pk__in=not_list)
|
|
|
|
context['temp_object_list'] = context['object_list']
|
|
context['object_list'] = []
|
|
for obj in context['temp_object_list']:
|
|
materia_anexada = obj
|
|
ciclico = False
|
|
anexadas_anexada = Anexada.objects.filter(
|
|
materia_principal=materia_anexada
|
|
)
|
|
|
|
while anexadas_anexada and not ciclico:
|
|
anexadas = []
|
|
|
|
for anexa in anexadas_anexada:
|
|
|
|
if principal == anexa.materia_anexada:
|
|
ciclico = True
|
|
else:
|
|
for a in Anexada.objects.filter(materia_principal=anexa.materia_anexada):
|
|
anexadas.append(a)
|
|
|
|
anexadas_anexada = anexadas
|
|
|
|
if not ciclico:
|
|
context['object_list'].append(obj)
|
|
|
|
context['numero_res'] = len(context['object_list'])
|
|
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
|
|
context['show_results'] = show_results_filter_set(qr)
|
|
|
|
return context
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
marcadas = request.POST.getlist('materia_id')
|
|
|
|
data_anexacao = datetime.strptime(
|
|
request.POST['data_anexacao'], "%d/%m/%Y").date()
|
|
|
|
if request.POST['data_desanexacao'] == '':
|
|
data_desanexacao = None
|
|
v_data_desanexacao = data_anexacao
|
|
else:
|
|
data_desanexacao = datetime.strptime(
|
|
request.POST['data_desanexacao'], "%d/%m/%Y").date()
|
|
v_data_desanexacao = data_desanexacao
|
|
|
|
if len(marcadas) == 0:
|
|
msg = _('Nenhuma máteria foi selecionada.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
|
|
if data_anexacao > v_data_desanexacao:
|
|
msg = _('Data de anexação posterior à data de desanexação.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
|
|
return self.get(request, self.kwargs)
|
|
|
|
if data_anexacao > v_data_desanexacao:
|
|
msg = _('Data de anexação posterior à data de desanexação.')
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
return self.get(request, self.kwargs)
|
|
|
|
principal = MateriaLegislativa.objects.get(pk=kwargs['pk'])
|
|
for materia in MateriaLegislativa.objects.filter(id__in=marcadas):
|
|
|
|
anexada = Anexada()
|
|
anexada.materia_principal = principal
|
|
anexada.materia_anexada = materia
|
|
anexada.data_anexacao = data_anexacao
|
|
anexada.data_desanexacao = data_desanexacao
|
|
anexada.save()
|
|
|
|
msg = _('Matéria(s) anexada(s).')
|
|
messages.add_message(request, messages.SUCCESS, msg)
|
|
|
|
success_url = reverse('sapl.materia:anexada_list',
|
|
kwargs={'pk': kwargs['pk']})
|
|
return HttpResponseRedirect(success_url)
|
|
|
|
|
|
class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
|
|
filterset_class = PrimeiraTramitacaoEmLoteFilterSet
|
|
template_name = 'materia/em_lote/tramitacao.html'
|
|
permission_required = ('materia.add_tramitacao', )
|
|
|
|
primeira_tramitacao = True
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(PrimeiraTramitacaoEmLoteView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['subnav_template_name'] = 'materia/em_lote/subnav_em_lote.yaml'
|
|
context['primeira_tramitacao'] = self.primeira_tramitacao
|
|
|
|
# Verifica se os campos foram preenchidos
|
|
if not self.filterset.form.is_valid():
|
|
return context
|
|
|
|
context['object_list'] = context['object_list'].order_by(
|
|
'ano', 'numero')
|
|
qr = self.request.GET.copy()
|
|
|
|
form = TramitacaoEmLoteForm()
|
|
context['form'] = form
|
|
|
|
if self.primeira_tramitacao:
|
|
context['title'] = _('Primeira Tramitação em Lote')
|
|
# Pega somente documentos que não possuem tramitação
|
|
context['object_list'] = [obj for obj in context['object_list']
|
|
if obj.tramitacao_set.all().count() == 0]
|
|
else:
|
|
context['title'] = _('Tramitação em Lote')
|
|
context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get(
|
|
id=qr['tramitacao__unidade_tramitacao_destino'])
|
|
|
|
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):
|
|
user = request.user
|
|
ip = get_client_ip(request)
|
|
|
|
materias_ids = request.POST.getlist('materias')
|
|
if not materias_ids:
|
|
msg = _("Escolha alguma matéria para ser tramitada.")
|
|
messages.add_message(request, messages.ERROR, msg)
|
|
return self.get(request, self.kwargs)
|
|
|
|
form = TramitacaoEmLoteForm(request.POST,
|
|
initial= {'materias': materias_ids,
|
|
'user': user, 'ip':ip})
|
|
|
|
if form.is_valid():
|
|
form.save()
|
|
|
|
msg = _('Tramitação completa.')
|
|
self.logger.info('user=' + user.username + '. Tramitação completa.')
|
|
messages.add_message(request, messages.SUCCESS, msg)
|
|
return self.get_success_url()
|
|
|
|
return self.form_invalid(form)
|
|
|
|
|
|
def get_success_url(self):
|
|
return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote'))
|
|
|
|
|
|
def form_invalid(self, form, *args, **kwargs):
|
|
for key, erros in form.errors.items():
|
|
if not key=='__all__':
|
|
[messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros]
|
|
else:
|
|
[messages.add_message(self.request, messages.ERROR, e) for e in erros]
|
|
return self.get(self.request, kwargs, {'form':form})
|
|
|
|
|
|
|
|
class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
|
|
filterset_class = TramitacaoEmLoteFilterSet
|
|
|
|
primeira_tramitacao = False
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(TramitacaoEmLoteView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
qr = self.request.GET.copy()
|
|
|
|
context['primeira_tramitacao'] = self.primeira_tramitacao
|
|
|
|
if ('tramitacao__status' in qr and
|
|
'tramitacao__unidade_tramitacao_destino' in qr and
|
|
qr['tramitacao__status'] and
|
|
qr['tramitacao__unidade_tramitacao_destino']):
|
|
lista = filtra_tramitacao_destino_and_status(
|
|
qr['tramitacao__status'],
|
|
qr['tramitacao__unidade_tramitacao_destino'])
|
|
context['object_list'] = context['object_list'].filter(
|
|
id__in=lista).distinct()
|
|
|
|
return context
|
|
|
|
|
|
class ImpressosView(PermissionRequiredMixin, TemplateView):
|
|
template_name = 'materia/impressos/impressos.html'
|
|
permission_required = ('materia.can_access_impressos', )
|
|
|
|
|
|
def gerar_pdf_impressos(request, context, template_name):
|
|
template = loader.get_template(template_name)
|
|
html = template.render(context, request)
|
|
pdf = weasyprint.HTML(
|
|
string=html, base_url=request.build_absolute_uri()).write_pdf()
|
|
|
|
response = HttpResponse(pdf, content_type='application/pdf')
|
|
response['Content-Disposition'] = 'inline; filename="relatorio_impressos.pdf"'
|
|
response['Content-Transfer-Encoding'] = 'binary'
|
|
|
|
return response
|
|
|
|
|
|
class EtiquetaPesquisaView(PermissionRequiredMixin, FormView):
|
|
form_class = EtiquetaPesquisaForm
|
|
template_name = 'materia/impressos/impressos_form.html'
|
|
permission_required = ('materia.can_access_impressos', )
|
|
|
|
def form_valid(self, form):
|
|
context = {}
|
|
|
|
materias = MateriaLegislativa.objects.all().order_by(
|
|
'-data_apresentacao')
|
|
|
|
if form.cleaned_data['tipo_materia']:
|
|
materias = materias.filter(tipo=form.cleaned_data['tipo_materia'])
|
|
|
|
if form.cleaned_data['data_inicial']:
|
|
materias = materias.filter(
|
|
data_apresentacao__gte=form.cleaned_data['data_inicial'],
|
|
data_apresentacao__lte=form.cleaned_data['data_final'])
|
|
|
|
if form.cleaned_data['processo_inicial']:
|
|
materias = materias.filter(
|
|
numeracao__numero_materia__gte=form.cleaned_data[
|
|
'processo_inicial'],
|
|
numeracao__numero_materia__lte=form.cleaned_data[
|
|
'processo_final'])
|
|
|
|
context['quantidade'] = len(materias)
|
|
|
|
if context['quantidade'] > 20:
|
|
materias = materias[:20]
|
|
|
|
for m in materias:
|
|
if len(m.ementa) > 100:
|
|
m.ementa = m.ementa[0:99] + "[...]"
|
|
|
|
context['materias'] = materias
|
|
|
|
return gerar_pdf_impressos(self.request, context,
|
|
'materia/impressos/etiqueta_pdf.html')
|
|
|
|
|
|
class FichaPesquisaView(PermissionRequiredMixin, FormView):
|
|
form_class = FichaPesquisaForm
|
|
template_name = 'materia/impressos/impressos_form.html'
|
|
permission_required = ('materia.can_access_impressos', )
|
|
|
|
def form_valid(self, form):
|
|
tipo_materia = form.data['tipo_materia']
|
|
data_inicial = form.data['data_inicial']
|
|
data_final = form.data['data_final']
|
|
|
|
url = reverse('sapl.materia:impressos_ficha_seleciona')
|
|
url = url + '?tipo=%s&data_inicial=%s&data_final=%s' % (
|
|
tipo_materia, data_inicial, data_final)
|
|
|
|
return HttpResponseRedirect(url)
|
|
|
|
|
|
class FichaSelecionaView(PermissionRequiredMixin, FormView):
|
|
logger = logging.getLogger(__name__)
|
|
form_class = FichaSelecionaForm
|
|
template_name = 'materia/impressos/impressos_form.html'
|
|
permission_required = ('materia.can_access_impressos', )
|
|
|
|
def get_context_data(self, **kwargs):
|
|
if ('tipo' not in self.request.GET or
|
|
'data_inicial' not in self.request.GET or
|
|
'data_final' not in self.request.GET):
|
|
return HttpResponseRedirect(reverse(
|
|
'sapl.materia:impressos_ficha_pesquisa'))
|
|
|
|
context = super(FichaSelecionaView, self).get_context_data(
|
|
**kwargs)
|
|
|
|
tipo = self.request.GET['tipo']
|
|
data_inicial = datetime.strptime(
|
|
self.request.GET['data_inicial'], "%d/%m/%Y").date()
|
|
data_final = datetime.strptime(
|
|
self.request.GET['data_final'], "%d/%m/%Y").date()
|
|
|
|
materia_list = MateriaLegislativa.objects.filter(
|
|
tipo=tipo,
|
|
data_apresentacao__range=(data_inicial, data_final))
|
|
context['quantidade'] = len(materia_list)
|
|
materia_list = materia_list[:100]
|
|
|
|
context['form'].fields['materia'].choices = [
|
|
(m.id, str(m)) for m in materia_list]
|
|
|
|
username = self.request.user.username
|
|
|
|
if context['quantidade'] > 100:
|
|
self.logger.info('user=' + username + '. Sua pesquisa (tipo={}, data_inicial={}, data_final={}) retornou mais do que '
|
|
'100 impressos. Por questões de '
|
|
'performance, foram retornados '
|
|
'apenas os 100 primeiros. Caso '
|
|
'queira outros, tente fazer uma '
|
|
'pesquisa mais específica'.format(tipo, data_inicial, data_final))
|
|
messages.info(self.request, _('Sua pesquisa retornou mais do que '
|
|
'100 impressos. Por questões de '
|
|
'performance, foram retornados '
|
|
'apenas os 100 primeiros. Caso '
|
|
'queira outros, tente fazer uma '
|
|
'pesquisa mais específica'))
|
|
|
|
return context
|
|
|
|
def form_valid(self, form):
|
|
context = {}
|
|
username = self.request.user.username
|
|
|
|
try:
|
|
self.logger.debug(
|
|
"user=" + username + ". Tentando obter objeto MateriaLegislativa com id={}".format(form.data['materia']))
|
|
materia = MateriaLegislativa.objects.get(
|
|
id=form.data['materia'])
|
|
except ObjectDoesNotExist:
|
|
self.logger.error(
|
|
"user=" + username + ". Esta MáteriaLegislativa não existe (id={}).".format(form.data['materia']))
|
|
mensagem = _('Esta Máteria não existe!')
|
|
self.messages.add_message(self.request, messages.INFO, mensagem)
|
|
|
|
return self.render_to_response(context)
|
|
if len(materia.ementa) > 301:
|
|
materia.ementa = materia.ementa[0:300] + '[...]'
|
|
context['materia'] = materia
|
|
context['despachos'] = materia.despachoinicial_set.all().values_list(
|
|
'comissao__nome', flat=True)
|
|
|
|
return gerar_pdf_impressos(self.request, context,
|
|
'materia/impressos/ficha_pdf.html')
|
|
|
|
|
|
class ExcluirTramitacaoEmLoteView(PermissionRequiredMixin, FormView):
|
|
|
|
template_name = 'materia/em_lote/excluir_tramitacao.html'
|
|
permission_required = ('materia.add_tramitacao',)
|
|
form_class = ExcluirTramitacaoEmLote
|
|
form_valid_message = _('Tramitações excluídas com sucesso!')
|
|
|
|
def get_success_url(self):
|
|
return reverse('sapl.materia:excluir_tramitacao_em_lote')
|
|
|
|
def form_valid(self, form):
|
|
|
|
tramitacao_set = Tramitacao.objects.filter(
|
|
data_tramitacao=form.cleaned_data['data_tramitacao'],
|
|
unidade_tramitacao_local=form.cleaned_data[
|
|
'unidade_tramitacao_local'],
|
|
unidade_tramitacao_destino=form.cleaned_data[
|
|
'unidade_tramitacao_destino'],
|
|
status=form.cleaned_data['status'])
|
|
for tramitacao in tramitacao_set:
|
|
materia = tramitacao.materia
|
|
if tramitacao == materia.tramitacao_set.last():
|
|
tramitacao.delete()
|
|
|
|
return redirect(self.get_success_url())
|
|
|
|
|
|
class MateriaPesquisaSimplesView(PermissionRequiredMixin, FormView):
|
|
form_class = MateriaPesquisaSimplesForm
|
|
template_name = 'materia/impressos/impressos_form.html'
|
|
permission_required = ('materia.can_access_impressos', )
|
|
|
|
def form_valid(self, form):
|
|
template_materia = 'materia/impressos/materias_pdf.html'
|
|
|
|
kwargs = {}
|
|
if form.cleaned_data.get('tipo_materia'):
|
|
kwargs.update({'tipo': form.cleaned_data['tipo_materia']})
|
|
|
|
if form.cleaned_data.get('data_inicial'):
|
|
kwargs.update({'data__gte': form.cleaned_data['data_inicial'],
|
|
'data__lte': form.cleaned_data['data_final']})
|
|
|
|
materias = MateriaLegislativa.objects.filter(
|
|
**kwargs).order_by('-numero', 'ano')
|
|
|
|
quantidade_materias = materias.count()
|
|
materias = materias[:2000] if quantidade_materias > 2000 else materias
|
|
|
|
context = {'quantidade': quantidade_materias,
|
|
'titulo': form.cleaned_data['titulo'],
|
|
'materias': materias}
|
|
|
|
return gerar_pdf_impressos(self.request, context, template_materia)
|
|
|
|
|
|
class TipoMateriaCrud(CrudAux):
|
|
model = TipoMateriaLegislativa
|
|
|
|
class DetailView(CrudAux.DetailView):
|
|
layout_key = 'TipoMateriaLegislativaDetail'
|
|
|
|
class DeleteView(CrudAux.DeleteView):
|
|
def delete(self, request, *args, **kwargs):
|
|
d = CrudAux.DeleteView.delete(self, request, *args, **kwargs)
|
|
TipoMateriaLegislativa.objects.reordene()
|
|
return d
|
|
|
|
class ListView(CrudAux.ListView):
|
|
paginate_by = None
|
|
layout_key = 'TipoMateriaLegislativaDetail'
|
|
template_name = "materia/tipomaterialegislativa_list.html"
|
|
|
|
def hook_sigla(self, obj, default, url):
|
|
return '<a href="{}" pk="{}">{}</a>'.format(
|
|
url, obj.id, obj.sigla), ''
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if TipoMateriaLegislativa.objects.filter(
|
|
sequencia_regimental=0).exists():
|
|
TipoMateriaLegislativa.objects.reordene()
|
|
return CrudAux.ListView.get(self, request, *args, **kwargs)
|
|
|
|
class CreateView(CrudAux.CreateView):
|
|
|
|
def form_valid(self, form):
|
|
fv = super().form_valid(form)
|
|
|
|
if not TipoMateriaLegislativa.objects.exclude(
|
|
sequencia_regimental=0).exists():
|
|
TipoMateriaLegislativa.objects.reordene()
|
|
else:
|
|
sr__max = TipoMateriaLegislativa.objects.all().aggregate(
|
|
Max('sequencia_regimental'))
|
|
self.object.sequencia_regimental = sr__max['sequencia_regimental__max'] + 1
|
|
self.object.save()
|
|
|
|
return fv
|
|
|