from datetime import datetime from random import choice from string import ascii_letters, digits import weasyprint from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML 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 from django.core.urlresolvers import reverse from django.db.models import Max 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 FormView, 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 sapl from sapl.base.models import Autor, CasaLegislativa from sapl.comissoes.models import Comissao, Participacao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE) from sapl.compilacao.views import IntegracaoTaView 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) from sapl.norma.models import LegislacaoCitada from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, gerar_hash_arquivo, get_base_url, get_mime_type_from_file_extension, montar_row_autor, show_results_filter_set) from .email_utils import do_envia_email_confirmacao from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, 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) from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, Tramitacao, UnidadeTramitacao) from .signals import tramitacao_signal AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') OrigemCrud = CrudAux.build(Origem, '') TipoMateriaCrud = CrudAux.build( TipoMateriaLegislativa, 'tipo_materia_legislativa') 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): proposicao = Proposicao.objects.get(pk=pk) if proposicao.texto_original: if (not proposicao.data_recebimento and proposicao.autor.user_id != 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 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!') 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) try: protocolo = Protocolo.objects.get(pk=self.kwargs['pk']) except ObjectDoesNotExist: raise Http404() numero = 1 try: materias_ano = MateriaLegislativa.objects.filter( ano=protocolo.ano, tipo=protocolo.tipo_materia).latest('numero') numero = materias_ano.numero + 1 except ObjectDoesNotExist: 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 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() try: protocolo = Protocolo.objects.get(pk=self.kwargs['pk']) except ObjectDoesNotExist: 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', } 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', } 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): tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo']) ano = request.GET.get('ano', '') numeracao = None try: numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao except AttributeError: 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(): proposicoes = Proposicao.objects.filter( data_envio__isnull=False, data_recebimento__isnull=True) for proposicao in proposicoes: if proposicao.texto_articulado.exists(): ta = proposicao.texto_articulado.first() # FIXME hash para textos articulados hasher = 'P' + ta.hash() + '/' + str(proposicao.id) else: hasher = gerar_hash_arquivo( proposicao.texto_original.path, str(proposicao.pk)) \ if proposicao.texto_original else None if hasher == form.cleaned_data['cod_hash']: return HttpResponseRedirect( reverse('sapl.materia:proposicao-confirmar', kwargs={ 'hash': hasher.split('/')[0][1:], 'pk': proposicao.pk})) messages.error(request, _('Proposição não encontrada!')) 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 ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView): app_label = sapl.protocoloadm.apps.AppConfig.label template_name = "materia/confirmar_proposicao.html" model = Proposicao form_class = ConfirmarProposicaoForm, DevolverProposicaoForm 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): 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 """ 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() + '/' + 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' % (self.kwargs['hash'], proposicao.pk): self.object = proposicao except: raise Http404() if not self.object: 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'] 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') 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 (%s)' % ( self.object, self.object.autor) return context def get(self, request, *args, **kwargs): action = request.GET.get('action', '') 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: p.data_devolucao = None p.data_envio = timezone.now() p.save() if p.texto_articulado.exists(): ta = p.texto_articulado.first() ta.privacidade = STATUS_TA_IMMUTABLE_RESTRICT ta.editing_locked = True ta.save() messages.success(request, _( 'Proposição enviada com sucesso.')) try: numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, ano=p.ano).last().numero + 1 messages.success(request, _( '%s : nº %s de %s
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: pass 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() if p.texto_articulado.exists(): ta = p.texto_articulado.first() ta.privacidade = STATUS_TA_PRIVATE ta.editing_locked = False ta.save() 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): try: p = Proposicao.objects.get(id=kwargs['pk']) except: 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): 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 class UpdateView(BaseLocalMixin, Crud.UpdateView): 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 editada') 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.') 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', '') 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.')) return reverse('sapl.materia:proposicao_ta', kwargs={'pk': self.object.pk}) else: return Crud.UpdateView.get_success_url(self) class CreateView(Crud.CreateView): 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', '') 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.')) 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): 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']) if proposicao.data_envio: return TemplateView.get(self, request, *args, **kwargs) if not proposicao.data_envio and not proposicao.data_devolucao: messages.error(request, _('Não é possível gerar recibo para uma ' 'Proposição ainda não enviada.')) elif proposicao.data_devolucao: 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 def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) try: comissao = Comissao.objects.get( pk=context['form'].initial['comissao']) except: pass else: composicao = comissao.composicao_set.order_by( '-periodo__data_inicio').first() participacao = Participacao.objects.filter( composicao=composicao) parlamentares = [] parlamentares.append(['', '---------']) for p in participacao: if p.titular: parlamentares.append( [p.parlamentar.id, p.parlamentar.nome_parlamentar]) context['form'].fields['parlamentar'].choices = parlamentares return context 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 def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) try: comissao = Comissao.objects.get( pk=context['form'].initial['comissao']) except ObjectDoesNotExist: pass else: composicao = comissao.composicao_set.last() participacao = Participacao.objects.filter( composicao=composicao) parlamentares = [[p.parlamentar.id, p.parlamentar.nome_parlamentar] for p in participacao if p.titular] context['form'].fields['parlamentar'].choices = parlamentares return context 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 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() return initial def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) ultima_tramitacao = Tramitacao.objects.filter( materia_id=self.kwargs['pk']).order_by( '-data_tramitacao', '-id').first() 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: msg = _('Unidade de tramitação destino ' ' da última tramitação não pode ser vazia!') messages.add_message(self.request, messages.ERROR, msg) return context def form_valid(self, form): self.object = form.save() if form.instance.status.indicador == 'F': form.instance.materia.em_tramitacao = False else: form.instance.materia.em_tramitacao = True form.instance.materia.save() try: tramitacao_signal.send(sender=Tramitacao, post=self.object, request=self.request) except Exception: # TODO log error msg = _('Tramitação criada, 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.ERROR, msg) return HttpResponseRedirect(self.get_success_url()) return super().form_valid(form) class UpdateView(MasterDetailCrud.UpdateView): form_class = TramitacaoUpdateForm layout_key = 'TramitacaoUpdate' def form_valid(self, form): self.object = form.save() if form.instance.status.indicador == 'F': form.instance.materia.em_tramitacao = False else: form.instance.materia.em_tramitacao = True form.instance.materia.save() try: tramitacao_signal.send(sender=Tramitacao, post=self.object, request=self.request) except Exception: # TODO log error msg = _('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.ERROR, 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', '-id') class DeleteView(MasterDetailCrud.DeleteView): def delete(self, request, *args, **kwargs): tramitacao = Tramitacao.objects.get(id=self.kwargs['pk']) materia = MateriaLegislativa.objects.get(id=tramitacao.materia.id) url = reverse('sapl.materia:tramitacao_list', kwargs={'pk': tramitacao.materia.id}) ultima_tramitacao = materia.tramitacao_set.order_by( '-data_tramitacao', '-id').first() if 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: tramitacao.delete() return HttpResponseRedirect(url) def montar_helper_documento_acessorio(self): autor_row = montar_row_autor('autor') self.helper = FormHelper() 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('Cancelar')])) 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'] = [] 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, }) 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\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 (%s)' % ( _('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'] for autor in autores_selecionados: Autoria.objects.create(materia=self.materia, autor=autor) return FormView.form_valid(self, form) class DespachoInicialCrud(MasterDetailCrud): model = DespachoInicial parent_field = 'materia' help_topic = 'despacho_autoria' public = [RP_LIST, RP_DETAIL] class CreateView(MasterDetailCrud.CreateView): form_class = DespachoInicialForm 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 @property def cancel_url(self): return self.search_url class UpdateView(Crud.UpdateView): form_class = MateriaLegislativaForm @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' 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): def get_redirect_url(self, 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', '') try: acompanhar = AcompanhamentoMateria.objects.get( materia_id=materia_id, hash=hash_txt) except ObjectDoesNotExist: raise Http404() # except MultipleObjectsReturned: # 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 acompanhar.confirmado = True acompanhar.save() return HttpResponseRedirect(self.get_redirect_url(acompanhar.email)) class AcompanhamentoExcluirView(TemplateView): def get_success_url(self): 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', '') try: AcompanhamentoMateria.objects.get(materia_id=materia_id, hash=hash_txt).delete() except ObjectDoesNotExist: 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} status_tramitacao = self.request.GET.get('tramitacao__status') unidade_destino = self.request.GET.get( 'tramitacao__unidade_tramitacao_destino') qs = self.get_queryset().distinct() 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() if 'o' in self.request.GET and not self.request.GET['o']: qs = qs.order_by('-ano', 'tipo__sigla', '-numero') 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") 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') self.filterset.form.fields['o'].label = _('Ordenação') 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) return context class AcompanhamentoMateriaView(CreateView): 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): 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): 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, destinatario) 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: msg = _('Este e-mail já está acompanhando essa matéria.') messages.add_message(request, messages.INFO, msg) return self.render_to_response( {'form': form, 'materia': materia, 'error': _('Essa matéria já está\ sendo acompanhada por este e-mail.')}) 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',) 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): 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() for materia_id in marcadas: doc = DocumentoAcessorio() doc.materia_id = materia_id doc.tipo = tipo doc.arquivo = request.FILES['arquivo'] doc.nome = request.POST['nome'] doc.data = tz.localize(datetime.strptime( request.POST['data'], "%d/%m/%Y")) doc.autor = request.POST['autor'] doc.ementa = request.POST['ementa'] doc.save() msg = _('Documento(s) criado(s).') messages.add_message(request, messages.SUCCESS, msg) return self.get(request, self.kwargs) class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): filterset_class = PrimeiraTramitacaoEmLoteFilterSet template_name = 'materia/em_lote/tramitacao.html' permission_required = ('materia.add_tramitacao', ) primeira_tramitacao = True 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' # Verifica se os campos foram preenchidos if not self.filterset.form.is_valid(): return context context['title'] = _('Primeira Tramitação em Lote') qr = self.request.GET.copy() context['unidade_destino'] = UnidadeTramitacao.objects.all() context['status_tramitacao'] = StatusTramitacao.objects.all() context['turnos_tramitacao'] = Tramitacao.TURNO_CHOICES context['urgente_tramitacao'] = YES_NO_CHOICES context['unidade_local'] = UnidadeTramitacao.objects.all() context['primeira_tramitacao'] = True # Pega somente matéria que não possuem tramitação if (type(self.__dict__['filterset']).__name__ == 'PrimeiraTramitacaoEmLoteFilterSet'): context['object_list'] = context['object_list'].filter( tramitacao__isnull=True) else: context['title'] = _('Tramitação em Lote') context['unidade_local'] = [UnidadeTramitacao.objects.get( id=qr['tramitacao__unidade_tramitacao_destino'])] 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): marcadas = request.POST.getlist('materia_id') tz = timezone.get_current_timezone() if len(marcadas) == 0: msg = _('Nenhuma máteria foi selecionada.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['status'] == '': msg = _('Campo Status deve ser preenchido.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['unidade_tramitacao_local'] == '': msg = _('Campo Unidade Local deve ser preenchido.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['data_tramitacao'] == '': msg = _('Campo Data da Tramitação deve ser preenchido.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['unidade_tramitacao_destino'] == '': msg = _('Campo Unidade Destino deve ser preenchido.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['urgente'] == '': msg = _('Campo Urgente deve ser preenchido.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['texto'] == '': msg = _('Campo Texto da Ação deve ser preenchido.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) if request.POST['data_encaminhamento'] == '': data_encaminhamento = None else: data_encaminhamento = tz.localize(datetime.strptime( request.POST['data_encaminhamento'], "%d/%m/%Y")) if request.POST['data_fim_prazo'] == '': data_fim_prazo = None else: data_fim_prazo = tz.localize(datetime.strptime( request.POST['data_fim_prazo'], "%d/%m/%Y")) # issue https://github.com/interlegis/sapl/issues/1123 # TODO: usar Form urgente = request.POST['urgente'] == 'True' for materia_id in marcadas: t = Tramitacao( materia_id=materia_id, data_tramitacao=tz.localize(datetime.strptime( request.POST['data_tramitacao'], "%d/%m/%Y")), data_encaminhamento=data_encaminhamento, data_fim_prazo=data_fim_prazo, unidade_tramitacao_local_id=request.POST[ 'unidade_tramitacao_local'], unidade_tramitacao_destino_id=request.POST[ 'unidade_tramitacao_destino'], urgente=urgente, status_id=request.POST['status'], turno=request.POST['turno'], texto=request.POST['texto'] ) t.save() status = StatusTramitacao.objects.get(id=request.POST['status']) for materia in MateriaLegislativa.objects.filter(id__in=marcadas): if status.indicador == 'F': materia.em_tramitacao = False elif self.primeira_tramitacao: materia.em_tramitacao = True materia.save() msg = _('Tramitação completa.') messages.add_message(request, messages.SUCCESS, msg) return self.get(request, self.kwargs) 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'] = False 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(RequestContext(request, context)) 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/etiqueta.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] 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/ficha.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): form_class = FichaSelecionaForm template_name = 'materia/impressos/ficha_seleciona.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] if context['quantidade'] > 100: 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 = {} try: materia = MateriaLegislativa.objects.get( id=form.data['materia']) except ObjectDoesNotExist: mensagem = _('Esta Máteria não existe!') self.messages.add_message(self.request, messages.INFO, mensagem) return self.render_to_response(context) 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())