|
|
@ -7,14 +7,16 @@ from crispy_forms.layout import HTML |
|
|
|
from django.contrib import messages |
|
|
|
from django.contrib.auth import get_user_model |
|
|
|
from django.contrib.auth.mixins import PermissionRequiredMixin |
|
|
|
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist |
|
|
|
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist,\ |
|
|
|
PermissionDenied |
|
|
|
from django.core.mail import send_mail |
|
|
|
from django.core.urlresolvers import reverse |
|
|
|
from django.db.models import Q |
|
|
|
from django.http import JsonResponse |
|
|
|
from django.http.response import HttpResponseRedirect |
|
|
|
from django.http.response import HttpResponseRedirect, Http404 |
|
|
|
from django.shortcuts import redirect |
|
|
|
from django.template import Context, loader |
|
|
|
from django.utils import dateformat, formats |
|
|
|
from django.utils.http import urlsafe_base64_decode |
|
|
|
from django.utils.translation import ugettext_lazy as _ |
|
|
|
from django.views.generic import CreateView, ListView, TemplateView, UpdateView |
|
|
@ -30,7 +32,7 @@ from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL, |
|
|
|
make_pagination) |
|
|
|
from sapl.materia import apps |
|
|
|
from sapl.materia.forms import AnexadaForm, LegislacaoCitadaForm,\ |
|
|
|
TipoProposicaoForm, ProposicaoCreateForm |
|
|
|
TipoProposicaoForm, ProposicaoForm |
|
|
|
from sapl.norma.models import LegislacaoCitada |
|
|
|
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, |
|
|
|
autor_modal, gerar_hash_arquivo, get_base_url, |
|
|
@ -38,7 +40,6 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, |
|
|
|
permissoes_protocoloadm, permission_required_for_app, |
|
|
|
montar_row_autor) |
|
|
|
|
|
|
|
|
|
|
|
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, |
|
|
|
ConfirmarProposicaoForm, DocumentoAcessorioForm, |
|
|
|
MateriaLegislativaFilterSet, |
|
|
@ -54,6 +55,7 @@ from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, |
|
|
|
TipoMateriaLegislativa, TipoProposicao, Tramitacao, |
|
|
|
UnidadeTramitacao) |
|
|
|
|
|
|
|
|
|
|
|
OrigemCrud = Crud.build(Origem, '') |
|
|
|
|
|
|
|
TipoMateriaCrud = CrudAux.build( |
|
|
@ -326,145 +328,144 @@ class ConfirmarProposicao(PermissionRequiredMixin, CreateView): |
|
|
|
|
|
|
|
|
|
|
|
class ProposicaoCrud(Crud): |
|
|
|
""" |
|
|
|
TODO: Entre outros comportamento gerais, mesmo que um usuário tenha |
|
|
|
Perfil de Autor o Crud de proposição não deverá permitir acesso a |
|
|
|
proposições. O acesso só deve ser permitido se existe um Autor registrado |
|
|
|
e vinculado ao usuário. Essa tarefa deve ser realizada nas Tabelas Aux. |
|
|
|
""" |
|
|
|
model = Proposicao |
|
|
|
help_path = '' |
|
|
|
container_field = 'autor__user' |
|
|
|
|
|
|
|
class BaseMixin(Crud.BaseMixin): |
|
|
|
list_field_names = ['data_envio', 'descricao', |
|
|
|
'tipo', 'data_recebimento'] |
|
|
|
|
|
|
|
class ListView(Crud.ListView): |
|
|
|
ordering = ['-data_envio', 'descricao'] |
|
|
|
|
|
|
|
def get_rows(self, object_list): |
|
|
|
|
|
|
|
for obj in object_list: |
|
|
|
if obj.data_envio is None: |
|
|
|
obj.data_envio = 'Em elaboração...' |
|
|
|
else: |
|
|
|
obj.data_envio = obj.data_envio.strftime("%d/%m/%Y %H:%M") |
|
|
|
if obj.data_recebimento is None: |
|
|
|
obj.data_recebimento = 'Não recebida' |
|
|
|
else: |
|
|
|
obj.data_recebimento = obj.data_recebimento.strftime( |
|
|
|
"%d/%m/%Y %H:%M") |
|
|
|
list_field_names = ['data_envio', 'data_recebimento', 'descricao', |
|
|
|
'tipo'] |
|
|
|
|
|
|
|
return [self._as_row(obj) for obj in object_list] |
|
|
|
|
|
|
|
class CreateView(Crud.CreateView): |
|
|
|
form_class = ProposicaoCreateForm |
|
|
|
class BaseLocalMixin: |
|
|
|
form_class = ProposicaoForm |
|
|
|
layout_key = None |
|
|
|
|
|
|
|
def get_success_url(self): |
|
|
|
def get_context_data(self, **kwargs): |
|
|
|
context = super().get_context_data(**kwargs) |
|
|
|
context['subnav_template_name'] = '' |
|
|
|
return context |
|
|
|
|
|
|
|
tipo_texto = self.request.POST.get('tipo_texto', '') |
|
|
|
def get(self, request, *args, **kwargs): |
|
|
|
"""if not Proposicao.objects.filter( |
|
|
|
pk=kwargs.get('pk'), autor__user=self.autor.user).exists(): |
|
|
|
raise Http404()""" |
|
|
|
|
|
|
|
if tipo_texto != 'T': |
|
|
|
return Crud.CreateView.get_success_url(self) |
|
|
|
else: |
|
|
|
return reverse('sapl.materia:proposicao_ta', |
|
|
|
kwargs={'pk': self.object.pk}) |
|
|
|
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 Proposicao.objects.filter( |
|
|
|
pk=kwargs.get('pk'), autor__user=self.autor.user).exists(): |
|
|
|
raise Http404()""" |
|
|
|
|
|
|
|
class ProposicaoOldCrud(Crud): |
|
|
|
""" |
|
|
|
TODO: Entre outros comportamento gerais, mesmo que um usuário tenha |
|
|
|
Perfil de Autor o Crud de proposição não deverá permitir acesso a |
|
|
|
proposições. O acesso só deve ser permitido se existe um Autor registrado |
|
|
|
e vinculado ao usuário. Essa tarefa deve ser realizada nas Tabelas Aux. |
|
|
|
""" |
|
|
|
model = Proposicao |
|
|
|
help_path = '' |
|
|
|
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 BaseMixin(Crud.BaseMixin): |
|
|
|
list_field_names = ['data_envio', 'descricao', |
|
|
|
'tipo', 'data_recebimento'] |
|
|
|
class DetailView(BaseLocalMixin, Crud.DetailView): |
|
|
|
layout_key = 'Proposicao' |
|
|
|
|
|
|
|
class CreateView(Crud.CreateView): |
|
|
|
form_class = ProposicaoOldForm |
|
|
|
def get(self, request, *args, **kwargs): |
|
|
|
action = request.GET.get('action', '') |
|
|
|
|
|
|
|
@property |
|
|
|
def layout_key(self): |
|
|
|
return 'ProposicaoCreate' |
|
|
|
if not action: |
|
|
|
return Crud.DetailView.get(self, request, *args, **kwargs) |
|
|
|
|
|
|
|
def get_initial(self): |
|
|
|
try: |
|
|
|
autor_id = Autor.objects.get(user=self.request.user).id |
|
|
|
except MultipleObjectsReturned: |
|
|
|
msg = _('Este usuário está relacionado a mais de um autor. ' + |
|
|
|
'Operação cancelada') |
|
|
|
messages.add_message(self.request, messages.ERROR, msg) |
|
|
|
return redirect(self.get_success_url()) |
|
|
|
except ObjectDoesNotExist: |
|
|
|
# FIXME: Pensar em uma melhor forma |
|
|
|
tipo = TipoAutor.objects.get(name='Externo') |
|
|
|
|
|
|
|
autor_id = Autor.objects.create( |
|
|
|
user=self.request.user, |
|
|
|
nome=str(self.request.user), |
|
|
|
tipo=tipo).id |
|
|
|
return {'autor': autor_id} |
|
|
|
else: |
|
|
|
return {'autor': autor_id} |
|
|
|
p = Proposicao.objects.get(id=kwargs['pk']) |
|
|
|
|
|
|
|
class UpdateView(Crud.UpdateView): |
|
|
|
form_class = ProposicaoOldForm |
|
|
|
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.') |
|
|
|
else: |
|
|
|
p.data_envio = datetime.now() |
|
|
|
p.save() |
|
|
|
messages.success(request, _( |
|
|
|
'Proposição enviada com sucesso.')) |
|
|
|
|
|
|
|
elif action == 'return': |
|
|
|
if not p.data_envio: |
|
|
|
msg_error = _('Proposição ainda não foi enviada.') |
|
|
|
elif p.data_recebimento: |
|
|
|
msg_error = _('Proposição já foi recebida, não é ' |
|
|
|
'possível retorná-la.') |
|
|
|
else: |
|
|
|
p.data_envio = None |
|
|
|
p.save() |
|
|
|
messages.success(request, _( |
|
|
|
'Proposição Retornada com sucesso.')) |
|
|
|
|
|
|
|
if msg_error: |
|
|
|
messages.error(request, msg_error) |
|
|
|
|
|
|
|
return Crud.DetailView.get(self, request, *args, **kwargs) |
|
|
|
|
|
|
|
class DeleteView(BaseLocalMixin, Crud.DeleteView): |
|
|
|
|
|
|
|
def _action_is_valid(self, request, *args, **kwargs): |
|
|
|
proposicao = Proposicao.objects.filter( |
|
|
|
id=kwargs['pk']).values_list( |
|
|
|
'data_envio', 'data_recebimento') |
|
|
|
|
|
|
|
if proposicao: |
|
|
|
if proposicao[0][0] and proposicao[0][1]: |
|
|
|
msg = _('Proposição já foi enviada e recebida.' |
|
|
|
'Não pode mais ser excluida.') |
|
|
|
elif proposicao[0][0] and not proposicao[0][1]: |
|
|
|
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 |
|
|
|
|
|
|
|
def get_initial(self): |
|
|
|
initial = self.initial.copy() |
|
|
|
if self.object.materia: |
|
|
|
initial['tipo_materia'] = self.object.materia.tipo.id |
|
|
|
initial['numero_materia'] = self.object.materia.numero |
|
|
|
initial['ano_materia'] = self.object.materia.ano |
|
|
|
return initial |
|
|
|
class UpdateView(BaseLocalMixin, Crud.UpdateView): |
|
|
|
|
|
|
|
@property |
|
|
|
def layout_key(self): |
|
|
|
return 'ProposicaoCreate' |
|
|
|
def _action_is_valid(self, request, *args, **kwargs): |
|
|
|
|
|
|
|
def has_permission(self): |
|
|
|
perms = self.get_permission_required() |
|
|
|
if not self.request.user.has_perms(perms): |
|
|
|
return False |
|
|
|
proposicao = Proposicao.objects.filter( |
|
|
|
id=kwargs['pk']).values_list( |
|
|
|
'data_envio', 'data_recebimento') |
|
|
|
|
|
|
|
if (Proposicao.objects.filter( |
|
|
|
id=self.kwargs['pk'], |
|
|
|
autor__user_id=self.request.user.id).exists()): |
|
|
|
proposicao = Proposicao.objects.get( |
|
|
|
id=self.kwargs['pk'], |
|
|
|
autor__user_id=self.request.user.id) |
|
|
|
if (not proposicao.data_recebimento or |
|
|
|
proposicao.data_devolucao): |
|
|
|
return True |
|
|
|
else: |
|
|
|
msg = _('Essa proposição já foi recebida. ' + |
|
|
|
if proposicao: |
|
|
|
if proposicao[0][0] and proposicao[0][1]: |
|
|
|
msg = _('Proposição já foi enviada e recebida.' |
|
|
|
'Não pode mais ser editada') |
|
|
|
messages.add_message(self.request, messages.ERROR, msg) |
|
|
|
return False |
|
|
|
|
|
|
|
class DetailView(Crud.DetailView): |
|
|
|
elif proposicao[0][0] and not proposicao[0][1]: |
|
|
|
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.') |
|
|
|
|
|
|
|
def has_permission(self): |
|
|
|
perms = self.get_permission_required() |
|
|
|
if not self.request.user.has_perms(perms): |
|
|
|
if proposicao[0][0] or proposicao[0][1]: |
|
|
|
messages.error(request, msg) |
|
|
|
return False |
|
|
|
return True |
|
|
|
|
|
|
|
return (Proposicao.objects.filter( |
|
|
|
id=self.kwargs['pk'], |
|
|
|
autor__user_id=self.request.user.id).exists()) |
|
|
|
class CreateView(Crud.CreateView): |
|
|
|
|
|
|
|
def get_context_data(self, **kwargs): |
|
|
|
context = CrudDetailView.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', '') |
|
|
|
|
|
|
|
if tipo_texto == 'T': |
|
|
|
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'] |
|
|
|
|
|
|
@ -474,60 +475,17 @@ class ProposicaoOldCrud(Crud): |
|
|
|
if obj.data_envio is None: |
|
|
|
obj.data_envio = 'Em elaboração...' |
|
|
|
else: |
|
|
|
obj.data_envio = obj.data_envio.strftime("%d/%m/%Y %H:%M") |
|
|
|
obj.data_envio = formats.date_format( |
|
|
|
obj.data_envio, "DATE_FORMAT") |
|
|
|
|
|
|
|
if obj.data_recebimento is None: |
|
|
|
obj.data_recebimento = 'Não recebida' |
|
|
|
else: |
|
|
|
obj.data_recebimento = obj.data_recebimento.strftime( |
|
|
|
"%d/%m/%Y %H:%M") |
|
|
|
obj.data_envio = formats.date_format( |
|
|
|
obj.data_recebimento, "DATE_FORMAT") |
|
|
|
|
|
|
|
return [self._as_row(obj) for obj in object_list] |
|
|
|
|
|
|
|
def get_queryset(self): |
|
|
|
# Só tem acesso as Proposicoes criadas por ele que ainda nao foram |
|
|
|
# recebidas ou foram devolvidas |
|
|
|
lista = Proposicao.objects.filter( |
|
|
|
autor__user_id=self.request.user.id) |
|
|
|
lista = lista.filter( |
|
|
|
Q(data_recebimento__isnull=True) | |
|
|
|
Q(data_devolucao__isnull=False)) |
|
|
|
|
|
|
|
return lista |
|
|
|
|
|
|
|
class DeleteView(Crud.DeleteView): |
|
|
|
|
|
|
|
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 delete(self, request, *args, **kwargs): |
|
|
|
proposicao = Proposicao.objects.get(id=self.kwargs['pk']) |
|
|
|
|
|
|
|
if not proposicao.data_envio or proposicao.data_devolucao: |
|
|
|
proposicao.delete() |
|
|
|
return HttpResponseRedirect( |
|
|
|
reverse('sapl.materia:proposicao_list')) |
|
|
|
|
|
|
|
elif not proposicao.data_recebimento: |
|
|
|
proposicao.data_envio = None |
|
|
|
proposicao.save() |
|
|
|
return HttpResponseRedirect( |
|
|
|
reverse('sapl.materia:proposicao_detail', |
|
|
|
kwargs={'pk': proposicao.pk})) |
|
|
|
|
|
|
|
else: |
|
|
|
msg = _('Essa proposição já foi recebida. ' + |
|
|
|
'Não pode mais ser excluída/recuperada') |
|
|
|
messages.add_message(self.request, messages.ERROR, msg) |
|
|
|
return HttpResponseRedirect( |
|
|
|
reverse('sapl.materia:proposicao_detail', |
|
|
|
kwargs={'pk': proposicao.pk})) |
|
|
|
|
|
|
|
|
|
|
|
class ReciboProposicaoView(TemplateView): |
|
|
|
template_name = "materia/recibo_proposicao.html" |
|
|
|