Browse Source

Adiciona relatório uso de espaços. Gertiq #160526

pull/169/head
Sesóstris Vieira 1 year ago
parent
commit
d0d8da2652
  1. 1
      sigi/apps/espacos/admin_urls.py
  2. 44
      sigi/apps/espacos/forms.py
  3. 2
      sigi/apps/espacos/templates/espacos/agenda_pdf.html
  4. 43
      sigi/apps/espacos/templates/espacos/snippets/uso_espaco_snippet.html
  5. 56
      sigi/apps/espacos/templates/espacos/uso_espaco.html
  6. 19
      sigi/apps/espacos/templates/espacos/uso_espaco_pdf.html
  7. 87
      sigi/apps/espacos/views.py
  8. 55
      sigi/apps/utils/mixins.py
  9. 2
      sigi/menu_conf.yaml
  10. 2
      sigi/templates/pdf/base.html

1
sigi/apps/espacos/admin_urls.py

@ -3,4 +3,5 @@ from sigi.apps.espacos import views
urlpatterns = [ urlpatterns = [
path("agenda/", views.Agenda.as_view(), name="espacos_agenda"), path("agenda/", views.Agenda.as_view(), name="espacos_agenda"),
path("usoespacos/", views.UsoEspacos.as_view(), name="espacos_usoespaco"),
] ]

44
sigi/apps/espacos/forms.py

@ -0,0 +1,44 @@
import calendar
from django.utils import timezone
from django import forms
from material.admin.widgets import MaterialAdminDateWidget
from django.forms.widgets import CheckboxSelectMultiple
from django.utils.translation import gettext as _
from sigi.apps.espacos.models import Espaco
class UsoEspacoReportForm(forms.Form):
class Media:
css = {"all": ["css/change_form.css"]}
js = [
"/admin/js/vendor/select2/select2.full.js",
"/admin/js/change_form.js",
"/admin/js/vendor/select2/i18n/pt-BR.js",
"/material/admin/js/widgets/TimeInput.js",
"/admin/js/core.js",
]
def get_semana(self):
return [
{"first": s[0], "last": s[-1]}
for s in calendar.Calendar().monthdatescalendar(
timezone.localdate().year, timezone.localdate().month
)
if s[0] <= timezone.localdate() <= s[-1]
][0]
data_inicio = forms.DateField(
label=_("Data início"), required=True, widget=MaterialAdminDateWidget
)
data_fim = forms.DateField(
label=_("Data fim"), required=True, widget=MaterialAdminDateWidget
)
espaco = forms.ModelMultipleChoiceField(
label=_("Espaços"), required=True, queryset=Espaco.objects.all(), widget=CheckboxSelectMultiple
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
semana = self.get_semana()
self.fields["data_inicio"].initial = semana["first"]
self.fields["data_fim"].initial = semana["last"]

2
sigi/apps/espacos/templates/espacos/agenda_pdf.html

@ -1,8 +1,6 @@
{% extends 'pdf/base_report.html' %} {% extends 'pdf/base_report.html' %}
{% load static i18n sigi_tags %} {% load static i18n sigi_tags %}
{% block page_size %}A4 landscape{% endblock page_size %}
{% block extra_style %} {% block extra_style %}
{{ block.super }} {{ block.super }}
blockquote { blockquote {

43
sigi/apps/espacos/templates/espacos/snippets/uso_espaco_snippet.html

@ -0,0 +1,43 @@
{% load i18n static sigi_tags dict_get %}
<table class="calendar-table" repeat="2">
<thead>
<tr>
<th rowspan="2">{% trans "Espaço" %}</th>
<th rowspan="2">{% trans "Data início" %}</th>
<th rowspan="2">{% trans "Data término" %}</th>
<th rowspan="2">{% trans "Propósito" %}</th>
<th rowspan="2">{% trans "Solicitante" %}</th>
<th colspan="2">{% trans "Contato" %}</th>
<th rowspan="2">{% trans "Informações adicionais" %}</th>
<th rowspan="2">{% trans "Recursos solicitados" %}</th>
</tr>
<tr>
<th>{% trans "Nome" %}</th>
<th>{% trans "Telefone" %}</th>
</tr>
</thead>
<tbody>
{% for reserva in reservas %}
<tr>
{% ifchanged reserva.espaco %}
<th rowspan="{{ rowspans|get:reserva.espaco.id }}">{{ reserva.espaco.nome }}</th>
{% endifchanged %}
<td>{{ reserva.inicio }}</td>
<td>{{ reserva.termino }}</td>
<td>{{ reserva.proposito }}</td>
<td>{{ reserva.solicitante }}</td>
<td>{{ reserva.contato }}</td>
<td>{{ reserva.telefone_contato }}</td>
<td>{{ reserva.informacoes }}</td>
<td>
<ul>
{% for recurso in reserva.recursosolicitado_set.all %}
<li>{{ recurso.quantidade}} {{ recurso.recurso }} ( {{ recurso.observacoes }})</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>

56
sigi/apps/espacos/templates/espacos/uso_espaco.html

@ -0,0 +1,56 @@
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static "css/calendario.css" %}">
<style>
tr {
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--darkened-bg);
}
</style>
{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block content %}
<div class="row">
<div class="col s12">
<form method="get" action="">
<div class="card">
<div class="card-content">
{{ form }}
</div>
<div class="card-action">
<button class="btn waves-effect waves-light" type="submit">
{% trans "View" %}
<i class="material-icons right">send</i>
</button>
<button class="btn waves-effect waves-light" type="submit" name="pdf" value="1">
{% trans "PDF" %}
<i class="material-icons right">picture_as_pdf</i>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col s12">
<div class="card">
<div class="card-content">
{% include "espacos/snippets/uso_espaco_snippet.html" %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block footer %}
{{ block.super }}
{{ form.media }}
{% endblock %}

19
sigi/apps/espacos/templates/espacos/uso_espaco_pdf.html

@ -0,0 +1,19 @@
{% extends "pdf/base_report.html" %}
{% load i18n static %}
{% block extra_style %}
{{ block.super }}
h4 {
margin: 20px 0;
padding-left: 1.5rem;
border-left: 5px solid #ee6e73;
}
{% endblock %}
{% block main_content %}
<h4>
{% blocktranslate%}Semana de {{ data_inicio }} a {{ data_termino }}{% endblocktranslate %}
</h4>
<br/>
{% include "espacos/snippets/uso_espaco_snippet.html" %}
{% endblock %}

87
sigi/apps/espacos/views.py

@ -2,29 +2,24 @@ import calendar
import locale import locale
from typing import Any from typing import Any
from django import http from django import http
from django.db.models import Q from django.db.models import Q, Count
from django.template.response import TemplateResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ( from django.utils.translation import (
to_locale, to_locale,
get_language, get_language,
ngettext,
gettext as _, gettext as _,
) )
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django_weasyprint.views import WeasyTemplateResponse
from sigi.apps.espacos.models import Espaco, Reserva from sigi.apps.espacos.models import Espaco, Reserva
from sigi.apps.espacos.forms import UsoEspacoReportForm
from sigi.apps.utils.mixins import ReportViewMixin, StaffMemberRequiredMixin
class Agenda(TemplateView): class Agenda(ReportViewMixin, StaffMemberRequiredMixin, TemplateView):
def _is_pdf(self): html_template_name = "espacos/agenda.html"
return bool(self.request.GET.get("pdf", 0)) pdf_template_name = "espacos/agenda_pdf.html"
report_title = _("Reserva de espaços do ILB")
def get_template_names(self): pagesize = "A4 landscape"
if self._is_pdf():
return ["espacos/agenda_pdf.html"]
else:
return ["espacos/agenda.html"]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
mes_pesquisa = int( mes_pesquisa = int(
@ -108,19 +103,59 @@ class Agenda(TemplateView):
context["semanas"] = semanas context["semanas"] = semanas
context["day_names"] = calendar.day_abbr context["day_names"] = calendar.day_abbr
if self._is_pdf():
context["pdf"] = True
context["title"] = _("Reserva de espaços do ILB")
return context return context
def render_to_response(self, context, **response_kwargs):
self.response_class = TemplateResponse class UsoEspacos(ReportViewMixin, StaffMemberRequiredMixin, TemplateView):
self.content_type = None html_template_name = "espacos/uso_espaco.html"
if self._is_pdf(): pdf_template_name = "espacos/uso_espaco_pdf.html"
self.content_type = "application/pdf" report_title = _("Uso dos espaços")
self.response_class = WeasyTemplateResponse pagesize = "A4 landscape"
response_kwargs.setdefault(
"filename", f"agenda-{timezone.localdate()}.pdf" def get_context_data(self, **kwargs):
form = UsoEspacoReportForm(self.request.GET)
if form.is_valid():
data_inicio = form.cleaned_data["data_inicio"]
data_fim = form.cleaned_data["data_fim"]
sel_espacos = form.cleaned_data["espaco"]
else:
form = UsoEspacoReportForm(
initial={"espaco": Espaco.objects.all()}
)
semana = form.get_semana()
data_inicio = semana["first"]
data_fim = semana["last"]
sel_espacos = None
if not sel_espacos:
sel_espacos = Espaco.objects.all()
reservas = (
Reserva.objects.filter(
status=Reserva.STATUS_ATIVO, espaco__in=sel_espacos
)
.filter(
Q(inicio__range=(data_inicio, data_fim))
| Q(termino__range=(data_inicio, data_fim))
) )
return super().render_to_response(context, **response_kwargs) .order_by("espaco", "inicio", "termino")
)
rowspans = dict(
reservas.order_by("espaco")
.values_list("espaco")
.annotate(Count("espaco"))
)
context = super().get_context_data(**kwargs)
context.update(
{
"reservas": reservas,
"rowspans": rowspans,
"form": form,
"data_inicio": data_inicio,
"data_termino": data_fim,
"sel_espacos": sel_espacos,
}
)
return context

55
sigi/apps/utils/mixins.py

@ -5,12 +5,15 @@ from django.contrib import admin
from django.contrib.admin import helpers from django.contrib.admin import helpers
from django.contrib.admin.options import csrf_protect_m from django.contrib.admin.options import csrf_protect_m
from django.contrib.admin.utils import pretty_name from django.contrib.admin.utils import pretty_name
from django.contrib.auth.mixins import UserPassesTestMixin
from django.core.exceptions import PermissionDenied, ImproperlyConfigured from django.core.exceptions import PermissionDenied, ImproperlyConfigured
from django.http import Http404 from django.http import Http404
from django.http.response import HttpResponse, HttpResponseRedirect from django.http.response import HttpResponse, HttpResponseRedirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import path from django.urls import path
from django.utils import timezone
from django.utils.translation import gettext as _, ngettext from django.utils.translation import gettext as _, ngettext
from django_weasyprint.views import WeasyTemplateResponse
from import_export import resources from import_export import resources
from import_export.admin import ImportMixin, ExportMixin from import_export.admin import ImportMixin, ExportMixin
from import_export.fields import Field from import_export.fields import Field
@ -308,13 +311,63 @@ class ReturnMixin:
return HttpResponseRedirect(self._return_path) return HttpResponseRedirect(self._return_path)
return response return response
class AsciifyQParameter: class AsciifyQParameter:
def asciify_q_param(self, request): def asciify_q_param(self, request):
if "q" in request.GET: if "q" in request.GET:
request.GET._mutable = True request.GET._mutable = True
request.GET["q"] = to_ascii(request.GET["q"]) request.GET["q"] = to_ascii(request.GET["q"])
request.GET._mutable = False request.GET._mutable = False
def get_queryset(self, request): def get_queryset(self, request):
self.asciify_q_param(request) self.asciify_q_param(request)
return super().get_queryset(request) return super().get_queryset(request)
class StaffMemberRequiredMixin(UserPassesTestMixin):
def test_func(self):
return self.request.user.is_staff
class ReportViewMixin:
html_template_name = None
pdf_template_name = None
report_title = _("Report")
pagesize = None
attachment = True
def _is_pdf(self):
return bool(self.request.GET.get("pdf", 0))
def get_template_names(self):
if self.html_template_name is None or self.pdf_template_name is None:
raise ImproperlyConfigured(
"TemplateResponseMixin requires either a definition of "
"'html_template_name' and 'pdf_template_name' or an "
"implementation of 'get_template_names()'"
)
if self._is_pdf():
return [self.pdf_template_name]
else:
return [self.html_template_name]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = self.report_title
context["pdf"] = self._is_pdf()
if self.pagesize:
context["pagesize"] = self.pagesize
return context
def render_to_response(self, context, **response_kwargs):
self.response_class = TemplateResponse
self.content_type = None
if self._is_pdf():
self.content_type = "application/pdf"
self.response_class = WeasyTemplateResponse
response_kwargs.setdefault(
"filename",
f"{self.report_title.lower()}-{timezone.localdate()}.pdf",
)
response_kwargs.setdefault("attachment", self.attachment)
return super().render_to_response(context, **response_kwargs)

2
sigi/menu_conf.yaml

@ -79,6 +79,8 @@ main_menu:
querystr: status=A querystr: status=A
- title: Agenda de reservas - title: Agenda de reservas
view_name: espacos_agenda view_name: espacos_agenda
- title: Uso dos espaços
view_name: espacos_usoespaco
- title: Eventos - title: Eventos
icon: school icon: school
children: children:

2
sigi/templates/pdf/base.html

@ -7,7 +7,7 @@
<meta name="author" content="Interlegis"> <meta name="author" content="Interlegis">
<style type="text/css"> <style type="text/css">
@page { @page {
size: {% block page_size %}A4 portrait{% endblock page_size %}; size: {% block page_size %}{{ pagesize|default:"A4 portrait" }}{% endblock page_size %};
margin: {% block page_margin %}3cm 2cm 2cm 2cm{% endblock page_margin %}; margin: {% block page_margin %}3cm 2cm 2cm 2cm{% endblock page_margin %};
font-family: "Helvetica", "Arial", "sans-serif"; font-family: "Helvetica", "Arial", "sans-serif";
font-size: 10px; font-size: 10px;

Loading…
Cancel
Save