diff --git a/sigi/apps/casas/admin_urls.py b/sigi/apps/casas/admin_urls.py index 1f6489e..2909fa6 100644 --- a/sigi/apps/casas/admin_urls.py +++ b/sigi/apps/casas/admin_urls.py @@ -4,6 +4,14 @@ from sigi.apps.casas import views urlpatterns = [ path("carteira/", views.painel_relacionamento, name="casas_carteira"), path("gerentes/", views.GerentesListView.as_view(), name="casas_gerentes"), - path("cnpjduplicado/", views.cnpj_duplicado, name="casas_cnpj_duplicado"), - path("cnpjerrado/", views.cnpj_errado, name="casas_cnpj_errado"), + path( + "cnpjduplicado/", + views.CnpjDuplicadoReport.as_view(), + name="casas_cnpj_duplicado", + ), + path( + "cnpjerrado/", + views.CnpjErradoReport.as_view(), + name="casas_cnpj_errado", + ), ] diff --git a/sigi/apps/casas/templates/casas/cnpj_duplicado.html b/sigi/apps/casas/templates/casas/cnpj_duplicado.html deleted file mode 100644 index 58ef6f8..0000000 --- a/sigi/apps/casas/templates/casas/cnpj_duplicado.html +++ /dev/null @@ -1,44 +0,0 @@ -{% extends "admin/base_site.html" %} -{% load static i18n %} - -{% block extrastyle %} -{{ block.super }} - - -{% endblock %} - -{% block coltype %}colMS{% endblock %} - -{% block content_title %} -
{% blocktranslate with count=orgaos.count %}{{ count }} órgãos com CNPJ duplicado{% endblocktranslate %}
-{% endblock %} - -{% block content %} -
- - print - - -
- {% include "casas/snippets/cnpj_duplicado_snippet.html" with mode="html" %} -{% endblock %} - -{% block footer %} - {{ block.super }} - -{% endblock %} \ No newline at end of file diff --git a/sigi/apps/casas/templates/casas/cnpj_duplicado_pdf.html b/sigi/apps/casas/templates/casas/cnpj_duplicado_pdf.html deleted file mode 100644 index e9f7280..0000000 --- a/sigi/apps/casas/templates/casas/cnpj_duplicado_pdf.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "pdf/base_report.html" %} -{% load static i18n %} - -{% block page_size %}A4 landscape{% endblock %} - -{% block extra_style %} - {{ block.super }} - .bordered td { - border-top: 1px solid #000; - } -{% endblock %} - -{% block report_name %} - {% blocktranslate with count=orgaos.count %}{{ count }} órgãos com CNPJ duplicado{% endblocktranslate %} -{% endblock report_name %} - -{% block main_content %} - {% include "casas/snippets/cnpj_duplicado_snippet.html" %} -{% endblock %} diff --git a/sigi/apps/casas/templates/casas/cnpj_errado.html b/sigi/apps/casas/templates/casas/cnpj_errado.html deleted file mode 100644 index 6bf16f8..0000000 --- a/sigi/apps/casas/templates/casas/cnpj_errado.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "admin/base_site.html" %} -{% load static i18n %} - -{% block extrastyle %} -{{ block.super }} - - -{% endblock %} - -{% block coltype %}colMS{% endblock %} - -{% block content_title %} -
{% blocktranslate with count=orgaos|length %}{{ count }} órgãos com CNPJ digitado errado{% endblocktranslate %}
-{% endblock %} - -{% block content %} -
-
-
- -
-
- -
-
-
- - print - - -
-
- {% include "casas/snippets/cnpj_errado_snippet.html" with mode="html" %} -{% endblock %} - -{% block footer %} - {{ block.super }} - -{% endblock %} \ No newline at end of file diff --git a/sigi/apps/casas/templates/casas/cnpj_errado_pdf.html b/sigi/apps/casas/templates/casas/cnpj_errado_pdf.html deleted file mode 100644 index c0be206..0000000 --- a/sigi/apps/casas/templates/casas/cnpj_errado_pdf.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "pdf/base_report.html" %} -{% load static i18n %} - -{% block page_size %}A4 landscape{% endblock %} - -{% block extra_style %} - {{ block.super }} - .bordered td { - border-top: 1px solid #000; - } -{% endblock %} - -{% block report_name %} - {% blocktranslate with count=orgaos|length %}{{ count }} órgãos com CNPJ digitado errado{% endblocktranslate %} -{% endblock report_name %} - -{% block main_content %} - {% include "casas/snippets/cnpj_errado_snippet.html" %} -{% endblock %} diff --git a/sigi/apps/casas/templates/casas/report/cnpj_errado_report/report.html b/sigi/apps/casas/templates/casas/report/cnpj_errado_report/report.html new file mode 100644 index 0000000..c00c146 --- /dev/null +++ b/sigi/apps/casas/templates/casas/report/cnpj_errado_report/report.html @@ -0,0 +1,8 @@ +{% extends 'utils/report/report.html' %} + +{% block filterform %} + +{% endblock filterform %} \ No newline at end of file diff --git a/sigi/apps/casas/templates/casas/snippets/cnpj_duplicado_snippet.html b/sigi/apps/casas/templates/casas/snippets/cnpj_duplicado_snippet.html deleted file mode 100644 index 90e7c83..0000000 --- a/sigi/apps/casas/templates/casas/snippets/cnpj_duplicado_snippet.html +++ /dev/null @@ -1,37 +0,0 @@ -{% load i18n %} -
-
- - - - - - - - - - - - - - {% for orgao in orgaos %} - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% translate "ID" %}{% translate "CNPJ" %}{% translate "Tipo de órgão" %}{% translate "Sigla" %}{% translate "Nome" %}{% translate "Cidade" %}{% translate "UF" %}
{{ orgao.id|stringformat:"s" }}{{ orgao.cnpj }}{{ orgao.tipo.nome }}{{ orgao.sigla }}{{ orgao.nome }}{{ orgao.municipio.nome }}{{ orgao.municipio.uf.sigla }}
- {% translate "Nenhum órgão com CNPJ duplicado" %} -
-
-
diff --git a/sigi/apps/casas/templates/casas/snippets/cnpj_errado_snippet.html b/sigi/apps/casas/templates/casas/snippets/cnpj_errado_snippet.html deleted file mode 100644 index 5839e0f..0000000 --- a/sigi/apps/casas/templates/casas/snippets/cnpj_errado_snippet.html +++ /dev/null @@ -1,38 +0,0 @@ -{% load i18n %} -
-
- - - - - - - - - - - - - {% for orgao in orgaos %} - {% ifchanged orgao.tipo_nome %} - - {% endifchanged %} - - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% translate "ID" %}{% translate "CNPJ" %}{% translate "Sigla" %}{% translate "Nome" %}{% translate "Cidade" %}{% translate "UF" %}
{{ orgao.tipo_nome }}
{{ orgao.id|stringformat:"s" }}{{ orgao.cnpj }}{{ orgao.sigla }}{{ orgao.nome }}{{ orgao.municipio_nome }}{{ orgao.uf_sigla }}
- {% translate "Nenhum órgão com CNPJ digitado errado" %} -
-
-
diff --git a/sigi/apps/casas/views.py b/sigi/apps/casas/views.py index e53c45a..0572a3d 100644 --- a/sigi/apps/casas/views.py +++ b/sigi/apps/casas/views.py @@ -6,12 +6,13 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import ( LoginRequiredMixin, PermissionRequiredMixin, + UserPassesTestMixin, ) from django.core.paginator import Paginator, InvalidPage, EmptyPage from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.urls import reverse_lazy -from django.utils.translation import gettext as _ +from django.utils.translation import gettext as _, ngettext from django.views.generic import ( CreateView, DeleteView, @@ -35,6 +36,7 @@ from sigi.apps.servicos.models import Servico, TipoServico from sigi.apps.eventos.models import Evento, TipoEvento from sigi.apps.convenios.models import Convenio from sigi.apps.utils import valida_cnpj +from sigi.apps.utils.views import ReportListView def resumo_carteira(casas): @@ -338,67 +340,61 @@ def painel_relacionamento(request): return render(request, "casas/painel.html", context) -@login_required -@staff_member_required -def cnpj_duplicado(request): - formato = request.GET.get("fmt", "html") - dups = ( - Orgao.objects.exclude(cnpj="") - .order_by("cnpj") - .values("cnpj") - .annotate(tot=Count("cnpj")) - .filter(tot__gt=1) - .values("cnpj") - ) - orgaos = ( - Orgao.objects.filter(cnpj__in=dups) - .order_by("cnpj", "nome", "municipio__nome", "municipio__uf") - .prefetch_related("tipo", "municipio", "municipio__uf") - ) - context = { - "orgaos": orgaos, - "title": _("Órgãos com CNPJ duplicado"), - } - if formato == "pdf": - return WeasyTemplateResponse( - filename="cnpj_duplicado.pdf", - request=request, - template="casas/cnpj_duplicado_pdf.html", - context=context, - content_type="application/pdf", - ) - elif formato == "csv": - response = HttpResponse(content_type="text/csv") - response["Content-Disposition"] = ( - 'attachment; filename="cnpj_duplicado.csv"' +class CnpjDuplicadoReport( + LoginRequiredMixin, UserPassesTestMixin, ReportListView +): + title = _("Órgãos com CNPJ duplicado") + empty_message = _("Nenhum órgão com CNPJ duplicado!") + queryset = Orgao.objects.filter( + cnpj__in=( + Orgao.objects.exclude(cnpj="") + .order_by("cnpj") + .values("cnpj") + .annotate(tot=Count("cnpj")) + .filter(tot__gt=1) + .values("cnpj") ) - fieldnames = [ - "id", - "cnpj", - "tipo__nome", - "sigla", - "nome", - "municipio__nome", - "municipio__uf__sigla", - ] - writer = csv.DictWriter(response, fieldnames) - writer.writeheader() - writer.writerows(orgaos.values(*fieldnames)) - return response - return render(request, "casas/cnpj_duplicado.html", context=context) + ).prefetch_related("tipo", "municipio", "municipio__uf") + ordering = ["cnpj", "nome", "municipio__nome", "municipio__uf"] + list_fields = [ + "id", + "cnpj", + "tipo__nome", + "sigla", + "nome", + "municipio__nome", + "municipio__uf__sigla", + ] + list_labels = [ + "ID", + "CNPJ", + "Tipo de órgão", + "Sigla", + "Nome", + "Cidade", + "UF", + ] + link_fields = ["id"] + change_field = "cnpj" + def test_func(self): + return self.request.user.is_staff + + def get_title(self): + count = self.get_queryset().count() + return ngettext( + "Um órgão com CNPJ duplicado", + f"{count} órgãos com CNPJ duplicado", + count, + ) -@login_required -@staff_member_required -def cnpj_errado(request): - formato = request.GET.get("fmt", "html") - form = CnpjErradoForm(request.GET) - if form.is_valid(): - has_convenio = form.cleaned_data.get("has_convenio", False) - else: - has_convenio = False - todos_orgaos = ( +class CnpjErradoReport( + LoginRequiredMixin, UserPassesTestMixin, ReportListView +): + title = _("Órgãos com CNPJ digitado errado") + empty_message = _("Nenhum órgão com CNPJ digitado errado") + queryset = ( Orgao.objects.exclude(cnpj="") .order_by("tipo", "cnpj", "nome") .annotate( @@ -407,46 +403,48 @@ def cnpj_errado(request): uf_sigla=F("municipio__uf__sigla"), ) ) - if has_convenio: - todos_orgaos = todos_orgaos.exclude(convenio=None) - orgaos = [] - for orgao in todos_orgaos: - if not valida_cnpj(orgao.cnpj): - orgaos.append(orgao) - context = { - "orgaos": orgaos, - "form": form, - "title": _("Órgãos com CNPJ digitado errado"), - } - if formato == "pdf": - return WeasyTemplateResponse( - filename="cnpj_errado.pdf", - request=request, - template="casas/cnpj_errado_pdf.html", - context=context, - content_type="application/pdf", - ) - elif formato == "csv": - response = HttpResponse(content_type="text/csv") - response["Content-Disposition"] = ( - 'attachment; filename="cnpj_errado.csv"' + filter_form = CnpjErradoForm + list_fields = ["id", "cnpj", "sigla", "nome", "municipio_nome", "uf_sigla"] + list_labels = ["ID", "CNPJ", "Sigla", "Nome", "Cidade", "UF"] + link_fields = ["id"] + break_field = "tipo_nome" + + def test_func(self): + return self.request.user.is_staff + + def get_title(self): + count = len(self.get_queryset()) + return ngettext( + "Um órgão com CNPJ digitado errado", + f"{count} órgãos com CNPJ digitado errado", + count, ) - fieldnames = [ - "id", - "cnpj", - "tipo_nome", - "sigla", - "nome", - "municipio_nome", - "uf_sigla", - ] - writer = csv.DictWriter(response, fieldnames) - writer.writeheader() - writer.writerows( - [{f: getattr(o, f) for f in fieldnames} for o in orgaos] + + def filter_queryset(self, queryset): + form = self.get_filter_form_instance() + if form.is_valid(): + has_convenio = form.cleaned_data["has_convenio"] + else: + has_convenio = False + if has_convenio: + queryset = queryset.exclude(convenio=None) + orgaos = [] + for orgao in queryset: + if not valida_cnpj(orgao.cnpj): + orgaos.append(orgao) + return orgaos + + def get_dataset(self): + return ( + [ + {f: getattr(o, f) for f in self.list_fields} + for o in self.get_queryset() + ], + self.list_fields, ) - return response - return render(request, "casas/cnpj_errado.html", context=context) + + def _get_options(self): + return Orgao._meta class GerentesListView(PermissionRequiredMixin, ListView): diff --git a/sigi/apps/convenios/templates/convenios/erros_gescon.html b/sigi/apps/convenios/templates/convenios/erros_gescon.html deleted file mode 100644 index 0c051d6..0000000 --- a/sigi/apps/convenios/templates/convenios/erros_gescon.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends "admin/base_site.html" %} -{% load static i18n %} - -{% block extrastyle %} -{{ block.super }} - - -{% endblock %} - -{% block coltype %}colMS{% endblock %} - -{% block content_title %} -
- {% blocktranslate count counter=convenios.count %} - Um convênio com erro na importação do Gescon - {% plural %} - {{ counter }} convênios com erro na importação do Gescon - {% endblocktranslate %} -
-{% endblock %} - -{% block breadcrumbs %} -{% endblock %} - -{% block content %} - {% include "convenios/snippets/erros_gescon_snippet.html" with mode="html" %} -{% endblock %} - -{% block footer %} - {{ block.super }} - -{% endblock %} \ No newline at end of file diff --git a/sigi/apps/convenios/templates/convenios/erros_gescon_pdf.html b/sigi/apps/convenios/templates/convenios/erros_gescon_pdf.html deleted file mode 100644 index 61c350c..0000000 --- a/sigi/apps/convenios/templates/convenios/erros_gescon_pdf.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "pdf/base_report.html" %} -{% load static i18n %} - -{% block page_size %}A4 landscape{% endblock %} - -{% block report_name %} - {% blocktranslate count counter=convenios.count %} - Um convênio com erro na importação do Gescon - {% plural %} - {{ counter }} convênios com erro na importação do Gescon - {% endblocktranslate %} -{% endblock report_name %} - -{% block main_content %} - {% include "convenios/snippets/erros_gescon_snippet.html" %} -
-
-

{% translate "Resumo da última importação de dados do Gescon" %}

- {{ ultima_importacao }} -
-{% endblock %} diff --git a/sigi/apps/convenios/templates/convenios/report/erros_gescon_report_view/report_pdf.html b/sigi/apps/convenios/templates/convenios/report/erros_gescon_report_view/report_pdf.html new file mode 100644 index 0000000..a4b94b0 --- /dev/null +++ b/sigi/apps/convenios/templates/convenios/report/erros_gescon_report_view/report_pdf.html @@ -0,0 +1,11 @@ +{% extends "utils/report/report_pdf.html" %} +{% load i18n %} + +{% block main_content %} + {{ block.super }} +
+
+

{% translate "Resumo da última importação de dados do Gescon" %}

+ {{ ultima_importacao }} +
+{% endblock %} \ No newline at end of file diff --git a/sigi/apps/convenios/templates/convenios/snippets/erros_gescon_snippet.html b/sigi/apps/convenios/templates/convenios/snippets/erros_gescon_snippet.html deleted file mode 100644 index 3344246..0000000 --- a/sigi/apps/convenios/templates/convenios/snippets/erros_gescon_snippet.html +++ /dev/null @@ -1,39 +0,0 @@ -{% load i18n %} -
-
- - - - - - - - - - - - - - {% for convenio in convenios %} - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% translate "id SIGI" %}{% translate "NUP sigad" %}{% translate "Número" %}{% translate "Projeto" %}{% translate "Órgão conveniado" %}{% translate "UF" %}{% translate "Erro encontrado" %}
- {{ convenio.id|stringformat:"s" }} - {{ convenio.num_processo_sf }}{{ convenio.num_convenio }}{{ convenio.projeto.nome }}{{ convenio.casa_legislativa }}{{ convenio.casa_legislativa.municipio.uf.sigla }}{{ convenio.observacao_gescon|safe }}
- {% translate "Nenhum convênio com erro de importação do Gescon." %} -
-
-
diff --git a/sigi/apps/convenios/urls.py b/sigi/apps/convenios/urls.py index a7db026..9f521d2 100644 --- a/sigi/apps/convenios/urls.py +++ b/sigi/apps/convenios/urls.py @@ -4,7 +4,7 @@ from sigi.apps.convenios import views urlpatterns = [ path( "errosgescon/", - views.report_erros_gescon, + views.ErrosGesconReportView.as_view(), name="convenios-report_erros_gescon", ), path( diff --git a/sigi/apps/convenios/views.py b/sigi/apps/convenios/views.py index 25c62ad..dc283d3 100644 --- a/sigi/apps/convenios/views.py +++ b/sigi/apps/convenios/views.py @@ -3,78 +3,74 @@ from docutils.core import publish_parts from django.utils.safestring import mark_safe from django.http import HttpResponse, HttpResponseForbidden from django.shortcuts import render, get_list_or_404 -from django.utils.translation import gettext as _ +from django.utils.translation import gettext as _, ngettext from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.decorators import login_required +from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django_weasyprint.views import WeasyTemplateResponse from sigi.apps.casas.models import Orgao from sigi.apps.contatos.models import UnidadeFederativa from sigi.apps.convenios.models import Convenio, Gescon, Projeto +from sigi.apps.utils.views import ReportListView -@login_required -@staff_member_required -def report_erros_gescon(request): - formato = request.GET.get("fmt", "html") - convenios = ( - Convenio.objects.filter(erro_gescon=True) - .order_by( - "num_processo_sf", - "projeto", - "num_convenio", - "casa_legislativa", - ) - .prefetch_related( - "casa_legislativa", "casa_legislativa__municipio__uf" - ) +class ErrosGesconReportView( + LoginRequiredMixin, UserPassesTestMixin, ReportListView +): + title = _("Convênios com erros no Gescon") + empty_message = _("Nenhum convênio com erro de importação do Gescon!") + queryset = Convenio.objects.filter(erro_gescon=True).prefetch_related( + "casa_legislativa", "casa_legislativa__municipio__uf" ) - rst = Gescon.load().ultima_importacao - parts = publish_parts( - rst, - writer_name="html5", - settings_overrides={ - "input_encoding": "unicode", - "output_encoding": "unicode", - }, - ) - context = { - "convenios": convenios, - "ultima_importacao": mark_safe(parts["html_body"]), - "title": "Convênios com erros no Gescon", - } - if formato == "pdf": - return WeasyTemplateResponse( - filename="erros_gescon.pdf", - request=request, - template="convenios/erros_gescon_pdf.html", - context=context, - content_type="application/pdf", + ordering = [ + "num_processo_sf", + "projeto", + "num_convenio", + "casa_legislativa__nome", + ] + list_fields = [ + "id", + "num_processo_sf", + "num_convenio", + "projeto__nome", + "casa_legislativa__nome", + "casa_legislativa__municipio__uf__sigla", + "observacao_gescon", + ] + list_labels = [ + _("id SIGI"), + _("NUP sigad"), + _("Número"), + _("Projeto"), + _("Órgão conveniado"), + _("UF"), + _("Erro encontrado"), + ] + + def test_func(self): + return self.request.user.is_staff + + def get_title(self): + count = self.get_queryset().count() + return ngettext( + "Um convênio com erro no Gescon", + f"{count} convênios com erros no Gescon", + count, ) - elif formato == "csv": - response = HttpResponse(content_type="text/csv") - response["Content-Disposition"] = ( - 'attachment; filename="erros_gescon.csv"' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + rst = Gescon.load().ultima_importacao + parts = publish_parts( + rst, + writer_name="html5", + settings_overrides={ + "input_encoding": "unicode", + "output_encoding": "unicode", + }, ) - fieldnames = [ - "id", - "num_processo_sf", - "num_convenio", - "projeto__nome", - "casa_legislativa__nome", - "casa_legislativa__municipio__uf__sigla", - "observacao_gescon", - ] - writer = csv.DictWriter(response, fieldnames) - writer.writeheader() - writer.writerows(convenios.values(*fieldnames)) - response.write("\n\nResumo da última importação do Gescon\n\n") - response.write('"' + rst.replace("\n", '"\n"') + '"') - return response - return render( - request, - "convenios/erros_gescon.html", - context=context, - ) + context["ultima_importacao"] = mark_safe(parts["html_body"]) + return context @login_required diff --git a/sigi/apps/utils/templates/utils/report/report.html b/sigi/apps/utils/templates/utils/report/report.html new file mode 100644 index 0000000..f667878 --- /dev/null +++ b/sigi/apps/utils/templates/utils/report/report.html @@ -0,0 +1,73 @@ +{% extends "admin/base_site.html" %} +{% load static i18n %} + +{% block breadcrumbs %}{% endblock %} + +{% block extrastyle %} +{{ block.super }} + + +{% endblock %} + +{% block coltype %}colMS{% endblock %} + +{% block content_title %} +
{{ report_title }}
+{% endblock %} + +{% block content %} + {% if form %} +
+
+
+
+ {% block filterform %}{{ form }}{% endblock filterform %} +
+
+ +
+ + print + +
    +
  • +
  • +
+
+
+
+
+
+ {% else %} +
+ + print + + +
+ {% endif %} + {% include "utils/report/report_items_snippet.html" with mode="html" %} +{% endblock %} + +{% block footer %} + {{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/sigi/apps/utils/templates/utils/report/report_items_snippet.html b/sigi/apps/utils/templates/utils/report/report_items_snippet.html new file mode 100644 index 0000000..da5c42e --- /dev/null +++ b/sigi/apps/utils/templates/utils/report/report_items_snippet.html @@ -0,0 +1,48 @@ +{% load i18n admin_urls sigi_tags %} +
+
+
+
+ + + + {% for label in list_labels %} + + {% endfor %} + + + + {% for obj in object_list %} + {% if break_field %} + {% with obj|valueof:break_field as monitor_break %} + {% ifchanged monitor_break %} + + {% endifchanged %} + {% endwith %} + {% endif %} + + {% for field_name in list_fields %} + + {% endfor %} + + {% empty %} + + + + {% endfor %} + +
{{ label }}
{{ monitor_break }}
+ {% if field_name in link_fields %} + + {{ obj|valueof:field_name|safe }} + + {% else %} + {{ obj|valueof:field_name|safe }} + {% endif %} +
+ {{ empty_message }} +
+
+
+
+
diff --git a/sigi/apps/utils/templates/utils/report/report_pdf.html b/sigi/apps/utils/templates/utils/report/report_pdf.html new file mode 100644 index 0000000..d766e1a --- /dev/null +++ b/sigi/apps/utils/templates/utils/report/report_pdf.html @@ -0,0 +1,20 @@ +{% extends "pdf/base_report.html" %} +{% load static i18n %} + +{% block page_size %}A4 landscape{% endblock %} + +{% block extra_style %} + {{ block.super }} + tr.changed { + border-top: 1px solid var(--body-fg); + } + tr.changed td { + border-top: 1px solid var(--body-fg); + } +{% endblock %} + +{% block report_name %}{{ report_title }}{% endblock report_name %} + +{% block main_content %} + {% include "utils/report/report_items_snippet.html" %} +{% endblock %} diff --git a/sigi/apps/utils/templatetags/sigi_tags.py b/sigi/apps/utils/templatetags/sigi_tags.py index 87fb7ab..e783510 100644 --- a/sigi/apps/utils/templatetags/sigi_tags.py +++ b/sigi/apps/utils/templatetags/sigi_tags.py @@ -1,6 +1,6 @@ import datetime from django import template -from django.conf import settings +from django.db import models from django.utils import timezone from django.utils.translation import gettext as _ @@ -36,3 +36,13 @@ def sum(value, arg): @register.simple_tag def multiply(value, arg): return value * arg + + +@register.filter +def valueof(obj, attr_name): + if hasattr(obj, attr_name): + return getattr(obj, attr_name) + if isinstance(obj, models.Model): + for part in attr_name.split("__"): + obj = getattr(obj, part) + return str(obj) diff --git a/sigi/apps/utils/views.py b/sigi/apps/utils/views.py index 0e4d6cb..016d52a 100644 --- a/sigi/apps/utils/views.py +++ b/sigi/apps/utils/views.py @@ -1,14 +1,159 @@ +import csv import docutils.core import io -from contextlib import redirect_stdout, redirect_stderr +import re from parsel import Selector +from contextlib import redirect_stdout, redirect_stderr +from django.apps import apps +from django.http.response import HttpResponse as HttpResponse from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import login_required -from django.shortcuts import render, get_object_or_404 +from django.contrib.admin.utils import label_for_field, get_fields_from_path +from django.core.exceptions import ImproperlyConfigured +from django.shortcuts import render from django.template.loader import render_to_string from django.utils import timezone +from django.views.generic import ListView from django_extensions.management.jobs import get_job -from sigi.apps.utils.models import JobSchedule +from django_weasyprint import WeasyTemplateResponse +from django.utils.translation import gettext_lazy as _ + + +class ReportListView(ListView): + filter_form = None + filter_form_initials = None + template_name = None + template_name_pdf = None + pdf_suffix = "_pdf" + format_param_name = "fmt" + filename = None + title = None + list_fields = None + list_labels = None + link_fields = None + change_field = None + break_field = None + empty_message = _("No data to display") + + def get_queryset(self): + queryset = super().get_queryset() + return self.filter_queryset(queryset) + + def get_template_names(self): + snake_name = re.sub( + r"(?