diff --git a/requirements/requirements.txt b/requirements/requirements.txt index fb70f9368..e64eb97dc 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -32,4 +32,5 @@ pysolr==3.6.0 python-magic==0.4.12 gunicorn==19.6.0 django-reversion==2.0.8 +WeasyPrint==0.30 whoosh==2.7.4 diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index f8aa30ea5..e2ff7f535 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1595,3 +1595,87 @@ class MateriaAssuntoForm(ModelForm): fields = ['materia', 'assunto'] widgets = {'materia': forms.HiddenInput()} + + +class EtiquetaPesquisaForm(forms.Form): + tipo_materia = forms.ModelChoiceField( + label=TipoMateriaLegislativa._meta.verbose_name, + queryset=TipoMateriaLegislativa.objects.all(), + required=False, + empty_label='Selecione') + + data_inicial = forms.DateField( + label='Data Inicial', + required=False, + widget=forms.DateInput(format='%d/%m/%Y') + ) + + data_final = forms.DateField( + label='Data Final', + required=False, + widget=forms.DateInput(format='%d/%m/%Y') + ) + + processo_inicial = forms.IntegerField( + label='Processo Inicial', + required=False) + + processo_final = forms.IntegerField( + label='Processo Final', + required=False) + + def __init__(self, *args, **kwargs): + super(EtiquetaPesquisaForm, self).__init__(*args, **kwargs) + + row1 = to_row( + [('tipo_materia', 6), + ('data_inicial', 3), + ('data_final', 3)]) + + row2 = to_row( + [('processo_inicial', 6), + ('processo_final', 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset( + ('Formulário de Etiqueta'), + row1, row2, + form_actions(save_label='Pesquisar') + ) + ) + + def clean(self): + cleaned_data = self.cleaned_data + + # Verifica se algum campo de data foi preenchido + if cleaned_data['data_inicial'] or cleaned_data['data_final']: + # Então verifica se o usuário preencheu o Incial e mas não + # preencheu o Final, ou vice-versa + if (not cleaned_data['data_inicial'] or + not cleaned_data['data_final']): + raise ValidationError(_( + 'Caso pesquise por data, os campos de Data Incial e ' + + 'Data Final devem ser preenchidos obrigatoriamente')) + # Caso tenha preenchido, verifica se a data final é maior que + # a inicial + elif cleaned_data['data_final'] < cleaned_data['data_inicial']: + raise ValidationError(_( + 'A Data Final não pode ser menor que a Data Inicial')) + + # O mesmo processo anterior é feito com o processo + if (cleaned_data['processo_inicial'] or + cleaned_data['processo_final']): + if (not cleaned_data['processo_inicial'] or + not cleaned_data['processo_final']): + raise ValidationError(_( + 'Caso pesquise por número de processo, os campos de ' + + 'Processo Inicial e Processo Final ' + + 'devem ser preenchidos obrigatoriamente')) + elif (cleaned_data['processo_final'] < + cleaned_data['processo_inicial']): + raise ValidationError(_( + 'O processo final não pode ser menor que o inicial')) + + return cleaned_data + diff --git a/sapl/materia/migrations/0012_auto_20170829_1321.py b/sapl/materia/migrations/0012_auto_20170829_1321.py new file mode 100644 index 000000000..69e1b1c22 --- /dev/null +++ b/sapl/materia/migrations/0012_auto_20170829_1321.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.3 on 2017-08-29 13:21 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0011_auto_20170808_1034'), + ] + + operations = [ + migrations.AlterModelOptions( + name='materialegislativa', + options={'permissions': (('can_access_impressos', 'Can access impressos'),), 'verbose_name': 'Matéria Legislativa', 'verbose_name_plural': 'Matérias Legislativas'}, + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index cd44363b4..9c95e1c44 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -234,6 +234,8 @@ class MateriaLegislativa(models.Model): verbose_name_plural = _('Matérias Legislativas') unique_together = (("tipo", "numero", "ano"),) + permissions = (("can_access_impressos", "Can access impressos"),) + def __str__(self): return _('%(tipo)s nº %(numero)s de %(ano)s') % { 'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano} diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index e91505c24..e803f18e0 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -8,6 +8,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView, CriarProtocoloMateriaView, DespachoInicialCrud, DocumentoAcessorioCrud, DocumentoAcessorioEmLoteView, + ImpressosView, EtiquetaPesquisaView, LegislacaoCitadaCrud, MateriaAssuntoCrud, MateriaLegislativaCrud, MateriaLegislativaPesquisaView, MateriaTaView, @@ -27,6 +28,15 @@ from .apps import AppConfig app_name = AppConfig.name +urlpatterns_impressos = [ + url(r'^materia/impressos/$', + ImpressosView.as_view(), + name='impressos'), + url(r'^materia/impressos/etiqueta-pesquisa/$', + EtiquetaPesquisaView.as_view(), + name='impressos_etiqueta'), +] + urlpatterns_materia = [ url(r'^materia/', include(MateriaLegislativaCrud.get_urls() + AnexadaCrud.get_urls() + @@ -118,5 +128,5 @@ urlpatterns_sistema = [ url(r'^sistema/materia/orgao/', include(OrgaoCrud.get_urls())), ] -urlpatterns = urlpatterns_materia + \ +urlpatterns = urlpatterns_impressos + urlpatterns_materia + \ urlpatterns_proposicao + urlpatterns_sistema diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 9e9b63e45..2d11ecf67 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -12,6 +12,7 @@ from django.core.urlresolvers import reverse 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 Context, loader, RequestContext from django.utils import formats from django.utils.translation import ugettext_lazy as _ from django.views.generic import CreateView, ListView, TemplateView, UpdateView @@ -44,7 +45,8 @@ from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, from .email_utils import do_envia_email_confirmacao from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, AdicionarVariasAutoriasFilterSet, DespachoInicialForm, - DocumentoAcessorioForm, MateriaAssuntoForm, + DocumentoAcessorioForm, EtiquetaPesquisaForm, + MateriaAssuntoForm, MateriaLegislativaFilterSet, MateriaSimplificadaForm, PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm, RelatoriaForm, TramitacaoEmLoteFilterSet, @@ -59,6 +61,8 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, TipoProposicao, Tramitacao, UnidadeTramitacao) from .signals import tramitacao_signal +import weasyprint + AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia') OrigemCrud = Crud.build(Origem, '') @@ -1741,3 +1745,57 @@ class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView): 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 = loader.get_template('materia/impressos/pdf.html') + html = template.render(RequestContext(request, context)) + response = HttpResponse(content_type="application/pdf") + weasyprint.HTML( + string=html, + base_url=request.build_absolute_uri()).write_pdf( + response) + + 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) + + diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 34d7372f6..6702a1f27 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -53,6 +53,7 @@ __listdetailchange__ = [RP_LIST, RP_DETAIL, RP_CHANGE] rules_group_administrativo = { 'group': SAPL_GROUP_ADMINISTRATIVO, 'rules': [ + (materia.MateriaLegislativa, ['can_access_impressos']), (protocoloadm.DocumentoAdministrativo, __base__), (protocoloadm.DocumentoAcessorioAdministrativo, __base__), (protocoloadm.TramitacaoAdministrativo, __base__), @@ -69,6 +70,7 @@ rules_group_protocolo = { (protocoloadm.DocumentoAcessorioAdministrativo, __listdetailchange__), (materia.MateriaLegislativa, __listdetailchange__), + (materia.MateriaLegislativa, ['can_access_impressos']), (materia.DocumentoAcessorio, __listdetailchange__), (materia.Anexada, __base__), (materia.Autoria, __base__), @@ -98,7 +100,7 @@ rules_group_materia = { (materia.DespachoInicial, __base__), (materia.DocumentoAcessorio, __base__), - (materia.MateriaLegislativa, __base__), + (materia.MateriaLegislativa, __base__ + ['can_access_impressos']), (materia.Numeracao, __base__), (materia.Tramitacao, __base__), (norma.LegislacaoCitada, __base__), @@ -209,6 +211,7 @@ rules_group_geral = { (materia.AssuntoMateria, __base__), # não há implementação (materia.MateriaAssunto, __base__), # não há implementação + (materia.MateriaLegislativa, ['can_access_impressos']), (materia.TipoProposicao, __base__), (materia.TipoMateriaLegislativa, __base__), (materia.RegimeTramitacao, __base__), diff --git a/sapl/templates/materia/impressos/etiqueta.html b/sapl/templates/materia/impressos/etiqueta.html new file mode 100644 index 000000000..03d1c8580 --- /dev/null +++ b/sapl/templates/materia/impressos/etiqueta.html @@ -0,0 +1,7 @@ +{% extends "crud/form.html" %} +{% load i18n crispy_forms_tags %} + +{% block base_content %} +

Impressos

+ {% crispy form %} +{% endblock base_content %} diff --git a/sapl/templates/materia/impressos/impressos.html b/sapl/templates/materia/impressos/impressos.html new file mode 100644 index 000000000..6f48dfddd --- /dev/null +++ b/sapl/templates/materia/impressos/impressos.html @@ -0,0 +1,33 @@ +{% extends "crud/detail.html" %} +{% load i18n %} + + +{% block actions %} +{% endblock %} + + +{% block detail_content %} + +

Impressos

+ +

Etiqueta

+ + +{#

Ficha

#} +{# #} +{##} +{#

Guia de Remessa

#} +{# #} +{##} +{#

Espelho

#} +{# #} + +{% endblock %} diff --git a/sapl/templates/materia/impressos/pdf.html b/sapl/templates/materia/impressos/pdf.html new file mode 100644 index 000000000..345835ba5 --- /dev/null +++ b/sapl/templates/materia/impressos/pdf.html @@ -0,0 +1,82 @@ + + + + + Impressos + + + + + + + +{% if quantidade > 30 %} +

Sua pesquisa retornou mais do que 20 impressos.

Por questões de performance, foram retornados apenas os 20 primeiros. Caso queira outros, tente fazer uma pesquisa mais específica

+


+{% endif %} + +{% for m in materias %} +
+ + + {% if m.numeracao_set.first %} + PROCESSO: {{ m.numeracao_set.first.numero_materia }} +   + {% else %} + PROCESSO: {{ m.numero }} +   + {% endif %} + + + {{m.tipo.sigla}}: {{m.numero}}/{{m.ano}}   + + + Pref: + {% if m.numeracao_set.first %} + {{ m.numeracao_set.first.numero_materia }} + {% endif %}
+ DATA DE ENTRADA: {{m.data_apresentacao}}
+ + + {% if m.autoria_set.all %} + Autores: + {% for a in m.autoria_set.all %} + {% if not forloop.first %} + ,    {{a.autor}} + {% else %} +  {{a.autor}} + {% endif %} + {% endfor %} +
+ {% endif %} + + + EMENTA: {{m.ementa}} + +
+ +
+
+
+
+
+ +{% endfor %} + + \ No newline at end of file diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml index 4ce7c6a03..9bcb12e2d 100644 --- a/sapl/templates/navbar.yaml +++ b/sapl/templates/navbar.yaml @@ -33,6 +33,9 @@ - title: {% trans 'Acessório em Lote' %} url: sapl.materia:acessorio_em_lote check_permission: materia.list_documentoacessorio {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} + - title: {% trans 'Impressos' %} + url: sapl.materia:impressos + check_permission: materia.can_access_impressos {% comment %} FIXME transformar para checagens de menu_[funcionalidade]{% endcomment%} - title: {% trans 'Matérias Legislativas' %} url: sapl.materia:pesquisar_materia - title: {% trans 'Pautas das Sessões' %}