diff --git a/sigi/apps/casas/dashboards.py b/sigi/apps/casas/dashboards.py
new file mode 100644
index 0000000..b0027fd
--- /dev/null
+++ b/sigi/apps/casas/dashboards.py
@@ -0,0 +1,73 @@
+import django_filters
+from dashboard import Dashcard, getcolor
+from django.db.models import Count
+from django.utils.translation import gettext as _
+from sigi.apps.casas.models import Orgao
+from sigi.apps.servidores.models import Servidor
+
+
+class GerenteFilter(django_filters.FilterSet):
+ servidor = django_filters.ModelChoiceFilter(
+ field_name="gerentes_interlegis",
+ label="Gerente",
+ queryset=Servidor.objects.exclude(casas_que_gerencia=None),
+ )
+
+ class Meta:
+ model = Orgao
+ fields = ["servidor"]
+
+
+class CasasGerente(Dashcard):
+ chart_type = Dashcard.TYPE_DOUGHNUT
+ title = _("Distribuição de Casas por Gerente")
+ model = Servidor
+ label_field = "nome_completo"
+ datasets = [{"data_field": ("casas_que_gerencia", Count)}]
+
+ def apply_filters(self, request, queryset):
+ return (
+ super()
+ .apply_filters(request, queryset)
+ .exclude(casas_que_gerencia=None)
+ )
+
+
+class PerformanceCarteira(Dashcard):
+ chart_type = Dashcard.TYPE_DOUGHNUT
+ title = _("Performance da gerência de carteiras")
+ model = Orgao
+ filterset = GerenteFilter
+
+ LABEL_USAM = _("Utilizam serviços")
+ LABEL_NAO_USAM = _("Não utilizam servços")
+
+ def apply_filters(self, request, queryset):
+ filter = self.filterset(request.GET, queryset=queryset)
+ valid = filter.is_valid()
+ if filter.form.cleaned_data["servidor"] is None:
+ if (
+ request.user.servidor
+ and request.user.servidor.casas_que_gerencia.exists()
+ ):
+ return request.user.servidor.casas_que_gerencia.all()
+ return (
+ super()
+ .apply_filters(request, queryset)
+ .exclude(gerentes_interlegis=None)
+ )
+
+ def get_labels(self, request, queryset=None):
+ return [self.LABEL_USAM, self.LABEL_NAO_USAM]
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ return [
+ {
+ "data": [
+ queryset.exclude(servico=None).count(),
+ queryset.filter(servico=None).count(),
+ ]
+ }
+ ]
diff --git a/sigi/apps/convenios/dashboards.py b/sigi/apps/convenios/dashboards.py
new file mode 100644
index 0000000..7a9a484
--- /dev/null
+++ b/sigi/apps/convenios/dashboards.py
@@ -0,0 +1,194 @@
+import numpy as np
+import pandas as pd
+import django_filters
+from dashboard import Dashcard
+from django.db.models import Q, Count
+from django.utils import timezone
+from django.utils.translation import gettext as _
+from sigi.apps.casas.models import TipoOrgao, Orgao
+from sigi.apps.convenios.models import Convenio, Projeto
+
+
+def get_tipos():
+ tipos = list(
+ TipoOrgao.objects.filter(sigla__in=["CM", "AL"]).values_list(
+ "sigla", "nome"
+ )
+ )
+ tipos.extend(
+ [
+ ("_legislativo", _("Todo o legislativo")),
+ ("_outros", _("Demais órgãos")),
+ ]
+ )
+ return tipos
+
+
+class ResumoConveniosFilter(django_filters.FilterSet):
+ tipo = django_filters.ChoiceFilter(
+ field_name="casa_legislativa__tipo__sigla",
+ label=_("Tipo"),
+ choices=get_tipos,
+ method="filter_tipo",
+ empty_label=None,
+ initial="CM",
+ )
+
+ class Meta:
+ model = Convenio
+ fields = ["tipo"]
+
+ def filter_tipo(self, queryset, name, value):
+ if value == "_legislativo":
+ tipos = TipoOrgao.objects.filter(legislativo=True).values_list(
+ "sigla", flat=True
+ )
+ elif value == "_outros":
+ tipos = TipoOrgao.objects.filter(legislativo=False).values_list(
+ "sigla", flat=True
+ )
+ else:
+ tipos = [value]
+ return queryset.filter(**{f"{name}__in": tipos})
+
+
+class ResumoConvenios(Dashcard):
+ chart_type = Dashcard.TYPE_TABLE
+ title = _("Resumo de informações")
+ model = Convenio
+ filterset = ResumoConveniosFilter
+ template_table = "convenios/dashboard/resumo_convenios.html"
+
+ def apply_filters(self, request, queryset):
+ if "tipo" not in request.GET:
+ request.GET = request.GET.copy()
+ request.GET["tipo"] = "CM"
+ return super().apply_filters(request, queryset)
+
+ def get_labels(self, request, queryset=None):
+ return []
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ filter = self.get_filter(request.GET, queryset)
+ if filter and filter.is_valid():
+ label_tipo = dict(get_tipos())[filter.form.cleaned_data["tipo"]]
+ else:
+ label_tipo = dict(get_tipos())["CM"]
+ convenios = queryset
+ camaras = filter.filter_tipo(
+ Orgao.objects.all(),
+ "tipo__sigla",
+ filter.form.cleaned_data["tipo"],
+ )
+ convenios_vigentes = convenios.exclude(
+ data_retorno_assinatura=None
+ ).filter(
+ Q(data_termino_vigencia__gte=timezone.localdate())
+ | Q(data_termino_vigencia=None)
+ )
+ convenios_andando = convenios.filter(data_retorno_assinatura=None)
+ convenios_vencidos = convenios.exclude(
+ Q(data_retorno_assinatura=None) | Q(data_termino_vigencia=None)
+ ).filter(data_termino_vigencia__lt=timezone.localdate())
+ dataset = {
+ _(f"{label_tipo} com convênios vigentes"): {
+ k: v
+ for k, v in convenios_vigentes.values_list(
+ "projeto__sigla"
+ ).annotate(Count("casa_legislativa_id", distinct=True))
+ },
+ _(f"{label_tipo} com convênios em andamento"): {
+ k: v
+ for k, v in convenios_andando.values_list(
+ "projeto__sigla"
+ ).annotate(Count("casa_legislativa_id", distinct=True))
+ },
+ _(f"{label_tipo} com convênios vencidos"): {
+ k: v
+ for k, v in convenios_vencidos.values_list(
+ "projeto__sigla"
+ ).annotate(Count("casa_legislativa_id", distinct=True))
+ },
+ }
+
+ ds_totais = (
+ (_(f"Total de {label_tipo} do país"), camaras.count()),
+ (
+ _(f"Total de {label_tipo} com convênio vigente"),
+ convenios_vigentes.order_by("casa_legislativa_id")
+ .distinct("casa_legislativa_id")
+ .count(),
+ ),
+ (
+ _(f"Total de {label_tipo} com convênio em andamento"),
+ convenios_andando.order_by("casa_legislativa_id")
+ .distinct("casa_legislativa_id")
+ .count(),
+ ),
+ (
+ _(f"Total de {label_tipo} com convênio vencido"),
+ convenios_vencidos.order_by("casa_legislativa_id")
+ .distinct("casa_legislativa_id")
+ .count(),
+ ),
+ )
+
+ df = (
+ pd.DataFrame.from_dict(dataset, orient="index")
+ .replace(np.nan, 0)
+ .convert_dtypes()
+ )
+
+ return {"data_frame": df, "totais": ds_totais}
+
+
+class ConvenioServico(Dashcard):
+ chart_type = Dashcard.TYPE_TABLE
+ title = _("Convenios e serviços")
+ model = Orgao
+ label_name = _("Situação")
+
+ def get_queryset(self, request):
+ return (
+ Orgao.objects.exclude(servico=None)
+ .filter(servico__data_desativacao=None, convenio=None)
+ .aggregate(
+ total=Count("id", distinct=True),
+ hospedagem=Count(
+ "id",
+ filter=Q(servico__tipo_servico__modo="H"),
+ distinct=True,
+ ),
+ )
+ )
+
+ def get_labels(self, request, queryset=None):
+ return [_("Total")]
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ values = dict(queryset)
+ datasets = [
+ {
+ "label": _(
+ "Casas sem convenio que utilizam algum serviço de hospedagem"
+ ),
+ "data": [values["hospedagem"]],
+ },
+ {
+ "label": _(
+ "Casas sem convenio que utilizam somente serviço de registro"
+ ),
+ "data": [values["total"] - values["hospedagem"]],
+ },
+ {
+ "label": _(
+ "Casas sem convenio que utilizam algum serviço de registro e/ou hospedagem"
+ ),
+ "data": [values["total"]],
+ },
+ ]
+ return datasets
diff --git a/sigi/apps/convenios/templates/convenios/dashboard/resumo_convenios.html b/sigi/apps/convenios/templates/convenios/dashboard/resumo_convenios.html
new file mode 100644
index 0000000..27c977e
--- /dev/null
+++ b/sigi/apps/convenios/templates/convenios/dashboard/resumo_convenios.html
@@ -0,0 +1,30 @@
+{% load i18n %}
+
+
+
+ |
+ {% for item in datasets.data_frame.columns %}
+ {{ item }} |
+ {% endfor %}
+
+
+
+ {% for label, values in datasets.data_frame.iterrows %}
+
+ {{ label }} |
+ {% for value in values %}
+ {{ value }} |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+
+ {% for label, value in datasets.totais %}
+
+ {{ label }} |
+ {{ value }} |
+
+ {% endfor %}
+
\ No newline at end of file
diff --git a/sigi/apps/eventos/dashboards.py b/sigi/apps/eventos/dashboards.py
new file mode 100644
index 0000000..a600108
--- /dev/null
+++ b/sigi/apps/eventos/dashboards.py
@@ -0,0 +1,153 @@
+import calendar
+import datetime
+import django_filters
+from dashboard import Dashcard, getcolor
+from django.db.models import F, Count, Q
+from django.utils import timezone
+from django.utils.translation import gettext as _
+from sigi.apps.eventos.models import Evento, TipoEvento
+
+
+def get_anos():
+ return [
+ (str(a), str(a))
+ for a in Evento.objects.filter(status=Evento.STATUS_REALIZADO)
+ .order_by("data_inicio__year")
+ .values_list("data_inicio__year", flat=True)
+ .distinct("data_inicio__year")
+ ]
+
+
+class AnoFilterset(django_filters.FilterSet):
+ ano = django_filters.ChoiceFilter(
+ field_name="data_inicio",
+ lookup_expr="year",
+ label=_("Ano"),
+ distinct=True,
+ choices=get_anos,
+ )
+
+ class Meta:
+ model = Evento
+ fields = ["ano"]
+
+
+class EventosStatus(Dashcard):
+ chart_type = Dashcard.TYPE_DOUGHNUT
+ title = _("Eventos por status")
+ model = Evento
+ label_field = ("status", F, lambda s: dict(Evento.STATUS_CHOICES)[s])
+ datasets = [{"data_field": ("id", Count)}]
+
+ def get_dataset_color(self, dataset_label):
+ return getcolor(dataset_label)
+
+
+class EventosAno(Dashcard):
+ chart_type = Dashcard.TYPE_LINE
+ title = _("Eventos nos últimos 12 meses")
+ model = TipoEvento
+
+ def get_dataset_color(self, dataset_label):
+ print(f"EventosAno: {dataset_label}, {getcolor(dataset_label)}")
+ return getcolor(dataset_label)
+
+ def get_meses(self, request=None):
+ if request is None:
+ mes = timezone.localdate().month
+ ano = timezone.localdate().year
+ else:
+ mes = int(request.GET.get("mes", timezone.localdate().month))
+ ano = int(request.GET.get("ano", timezone.localdate().year))
+
+ mes_ano = datetime.date(
+ year=ano, month=mes, day=1
+ ) + datetime.timedelta(days=calendar.monthrange(ano, mes)[1])
+
+ meses = []
+
+ for i in range(13):
+ meses.append(mes_ano)
+ mes_ano = (mes_ano - datetime.timedelta(days=1)).replace(day=1)
+ meses.reverse()
+
+ return meses
+
+ def get_labels(self, request, queryset=None):
+ return [f"{m:%m/%Y}" for m in self.get_meses(request)[:-1]]
+
+ def get_counters(self, request):
+ counts = {}
+ for mes in self.get_meses(request)[:-1]:
+ counts[f"count_{mes:%Y_%m}"] = Count(
+ "evento",
+ Q(
+ evento__data_inicio__year=mes.year,
+ evento__data_inicio__month=mes.month,
+ ),
+ )
+ return counts
+
+ def apply_filters(self, request, queryset):
+ return (
+ super()
+ .apply_filters(request, queryset)
+ .filter(evento__status=Evento.STATUS_REALIZADO)
+ )
+
+ def get_queryset(self, request):
+ counts = self.get_counters(request)
+ return (
+ super()
+ .get_queryset(request)
+ .values("categoria")
+ .annotate(**counts)
+ )
+
+ def get_dataset_color(self, dataset_label):
+ return getcolor(dataset_label)
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ categorias = dict(TipoEvento.CATEGORIA_CHOICES)
+ counters = self.get_counters(request).keys()
+ return [
+ {
+ "label": categorias[r["categoria"]],
+ "data": [r[c] for c in counters],
+ "backgroundColor": self.get_dataset_color(r["categoria"]),
+ }
+ for r in queryset
+ ]
+
+ def get_next_page(self, request=None, queryset=None):
+ mes = self.get_meses(request)[-1]
+ return f"ano={mes.year}&mes={mes.month}"
+
+ def get_prev_page(self, request=None, queryset=None):
+ mes = self.get_meses(request)[-3]
+ return f"ano={mes.year}&mes={mes.month}"
+
+
+class EventosCategoria(Dashcard):
+ chart_type = Dashcard.TYPE_DOUGHNUT
+ title = _("Eventos por categoria")
+ filterset = AnoFilterset
+ model = Evento
+ label_field = (
+ "tipo_evento__categoria",
+ F,
+ lambda x: dict(TipoEvento.CATEGORIA_CHOICES)[x],
+ )
+ datasets = [{"data_field": ("id", Count)}]
+
+ def apply_filters(self, request, queryset):
+ return (
+ super()
+ .apply_filters(request, queryset)
+ .filter(status=Evento.STATUS_REALIZADO)
+ )
+
+ def get_dataset_color(self, dataset_label):
+ return getcolor(dataset_label)
diff --git a/sigi/apps/servicos/dashboards.py b/sigi/apps/servicos/dashboards.py
new file mode 100644
index 0000000..d4a2403
--- /dev/null
+++ b/sigi/apps/servicos/dashboards.py
@@ -0,0 +1,393 @@
+import calendar
+import datetime
+import locale
+from dashboard import Dashcard, getcolor
+from random import randint, seed
+from django.db.models import Count, F, Q
+from django.db.models.functions import TruncMonth
+from django.http import QueryDict
+from django.utils import timezone
+from django.utils.text import slugify
+from django.utils.translation import gettext as _, to_locale, get_language
+import django_filters
+from sigi.apps.servicos.models import Servico, TipoServico
+from sigi.apps.contatos.models import UnidadeFederativa
+
+
+class UsoServicosFilter(django_filters.FilterSet):
+ uf = django_filters.ModelChoiceFilter(
+ field_name="servico__casa_legislativa__municipio__uf",
+ label=_("UF"),
+ queryset=UnidadeFederativa.objects.all(),
+ )
+
+ class Meta:
+ model = TipoServico
+ fields = ["uf"]
+
+
+class AnoServicoFilter(django_filters.FilterSet):
+ ano = django_filters.ModelChoiceFilter(
+ field_name="data_ativacao__year",
+ label=_("Ano"),
+ queryset=(
+ Servico.objects.filter(hospedagem_interlegis=True)
+ .order_by("data_ativacao__year")
+ .values_list("data_ativacao__year", flat=True)
+ .distinct("data_ativacao__year")
+ ),
+ )
+
+ class Meta:
+ model = Servico
+ fields = ["ano"]
+
+
+class Sazonalidade(Dashcard):
+ title = _("Sazonalidade da hospedagem de serviços")
+ chart_type = Dashcard.TYPE_LINE
+ model = Servico
+ label_field = ("data_ativacao", TruncMonth, lambda d: d.strftime("%m/%Y"))
+ datasets = [
+ {
+ "label_field": "tipo_servico__sigla",
+ "data_field": ("*", Count),
+ }
+ ]
+
+ def get_dataset_color(self, dataset_label):
+ return getcolor(dataset_label)
+
+ def get_queryset(self, request):
+ qs = (
+ super()
+ .get_queryset(request)
+ .filter(data_desativacao=None)
+ .order_by("tipo_servico__sigla", "data_ativacao")
+ )
+ ano = request.GET.get("ano", None)
+ if ano is None:
+ ano = (
+ qs.dates("data_ativacao", "year")
+ .values_list("data_ativacao__year", flat=True)
+ .last()
+ )
+ return qs.filter(data_ativacao__year=ano)
+
+ def get_prev_page(self, request=None, queryset=None):
+ anos = Servico.objects.dates("data_ativacao", "year").values_list(
+ "data_ativacao__year", flat=True
+ )
+ if request is None:
+ params = QueryDict().copy()
+ params["ano"] = anos.last() - 1
+ else:
+ params = request.GET.copy()
+ params["ano"] = int(request.GET.get("ano", anos.last())) - 1
+ if params["ano"] not in anos:
+ return None
+ return params.urlencode()
+
+ def get_next_page(self, request=None, queryset=None):
+ if request is None:
+ return None
+ anos = Servico.objects.dates("data_ativacao", "year").values_list(
+ "data_ativacao__year", flat=True
+ )
+ params = request.GET.copy()
+ params["ano"] = int(request.GET.get("ano", anos.last())) + 1
+ if params["ano"] not in anos:
+ return None
+ return params.urlencode()
+
+
+class ResumoSeit(Dashcard):
+ title = _("Serviços hospedados no Interlegis")
+ chart_type = Dashcard.TYPE_TABLE
+ label_name = _("Serviço")
+ model = Servico
+
+ def get_meses(self, request=None):
+ if request is None:
+ mes = datetime.date.today().month
+ ano = datetime.date.today().year
+ else:
+ mes = int(request.GET.get("mes", datetime.date.today().month))
+ ano = int(request.GET.get("ano", datetime.date.today().year))
+ mes_atual = datetime.date(year=ano, month=mes, day=1)
+ mes_anterior = (mes_atual - datetime.timedelta(days=1)).replace(day=1)
+ mes_proximo = mes_atual + datetime.timedelta(
+ days=calendar.monthrange(mes_atual.year, mes_atual.month)[1]
+ )
+
+ return mes_atual, mes_anterior, mes_proximo
+
+ def get_queryset(self, request):
+ mes_atual, mes_anterior, mes_proximo = self.get_meses(request)
+ return (
+ super()
+ .get_queryset(request)
+ .filter(
+ (
+ Q(data_ativacao__year=mes_atual.year)
+ & Q(Q(data_ativacao__month=mes_atual.month))
+ )
+ | (
+ Q(data_ativacao__year=mes_anterior.year)
+ & Q(Q(data_ativacao__month=mes_anterior.month))
+ )
+ )
+ .values(
+ servico=F("tipo_servico__nome"),
+ mes=TruncMonth("data_ativacao"),
+ )
+ .annotate(ativados=Count("casa_legislativa__id", distinct=True))
+ )
+
+ def get_labels(self, request, queryset=None):
+ mes_atual, mes_anterior, mes_proximo = self.get_meses(request)
+ return [
+ _("Total de casas atendidas"),
+ _(f"Novas casas em {mes_anterior:%m/%Y}"),
+ _(f"Novas casas em {mes_atual:%m/%Y}"),
+ ]
+
+ def get_datasets(self, request, queryset=None):
+ mes_atual, mes_anterior, mes_proximo = self.get_meses(request)
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ labels = self.get_labels(request, queryset)
+ datasets = {
+ s["servico"]: {
+ "total": s["total"],
+ mes_anterior: 0,
+ mes_atual: 0,
+ }
+ for s in Servico.objects.filter(data_desativacao=None)
+ .values(servico=F("tipo_servico__nome"))
+ .annotate(total=Count("casa_legislativa", distinct=True))
+ }
+ for data in queryset:
+ datasets[data["servico"]][data["mes"]] = data["ativados"]
+
+ return [
+ {
+ "label": label,
+ "data": {
+ labels[0]: data["total"],
+ labels[1]: data[mes_atual],
+ labels[2]: data[mes_anterior],
+ },
+ }
+ for label, data in datasets.items()
+ ]
+
+ def get_prev_page(self, request=None, queryset=None):
+ mes_atual, mes_anterior, mes_proximo = self.get_meses(request)
+ params = QueryDict().copy()
+ params["ano"] = mes_anterior.year
+ params["mes"] = mes_anterior.month
+ return params.urlencode()
+
+ def get_next_page(self, request=None, queryset=None):
+ mes_atual, mes_anterior, mes_proximo = self.get_meses(request)
+ params = QueryDict().copy()
+ params["ano"] = mes_proximo.year
+ params["mes"] = mes_proximo.month
+ return params.urlencode()
+
+
+class AtualizacaoServicos(Dashcard):
+ title = _("Frequência de atualização")
+ chart_type = Dashcard.TYPE_BAR
+ model = TipoServico
+
+ intervalos = [
+ ("Na semana", 7),
+ ("No mês", 30),
+ ("No trimestre", 3 * 30),
+ ("No semestre", 6 * 30),
+ ("No ano", 365),
+ ("Mais de ano", None),
+ ]
+
+ def get_queryset(self, request):
+ counts = {}
+ hoje = timezone.localdate()
+ ate = hoje
+
+ for label, dias in self.intervalos:
+ if dias is not None:
+ de = hoje - datetime.timedelta(days=dias)
+ counts[slugify(label)] = Count(
+ "servico", Q(servico__data_ultimo_uso__range=(de, ate))
+ )
+ ate = de - datetime.timedelta(days=1)
+ else:
+ counts[slugify(label)] = Count(
+ "servico", Q(servico__data_ultimo_uso__lte=ate)
+ )
+
+ return (
+ super()
+ .get_queryset(request)
+ .exclude(string_pesquisa="")
+ .filter(servico__data_desativacao=None)
+ .annotate(**counts)
+ )
+
+ def get_labels(self, request, queryset=None):
+ return [label for label, *__ in self.intervalos]
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ return [
+ {
+ "type": "bar",
+ "label": ts.sigla,
+ "data": {
+ label: getattr(ts, slugify(label))
+ for label, *__ in self.intervalos
+ },
+ "backgroundColor": getcolor(ts.sigla),
+ }
+ for ts in queryset
+ ]
+
+
+class UsoServicos(Dashcard):
+ title = _("Uso dos serviços")
+ chart_type = Dashcard.TYPE_BAR
+ model = TipoServico
+ filterset = UsoServicosFilter
+ label_field = "sigla"
+
+ def get_dataset_color(self, dataset_label):
+ return getcolor(dataset_label)
+
+ def apply_filters(self, request, queryset):
+ queryset = queryset.exclude(string_pesquisa="").filter(
+ servico__data_desativacao=None
+ )
+ return super().apply_filters(request, queryset)
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+
+ counts = {
+ f"{key}_count": Count(
+ "servico",
+ distinct=True,
+ filter=Q(servico__resultado_verificacao=key),
+ )
+ for key, *__ in Servico.RESULTADO_CHOICES
+ }
+
+ queryset = queryset.annotate(**counts)
+
+ return [
+ {
+ "label": label,
+ "data": {
+ r.sigla: getattr(r, f"{key}_count") for r in queryset
+ },
+ }
+ for key, label in Servico.RESULTADO_CHOICES
+ ]
+
+
+class ServicosAno(Dashcard):
+ title = _("Serviços hospedados por ano")
+ chart_type = Dashcard.TYPE_BAR
+ model = Servico
+ filterset = AnoServicoFilter
+ chart_options = {
+ "scales": {"x": {"stacked": True}, "y": {"stacked": True}},
+ "plugins": {"tooltip": {"mode": "index"}},
+ }
+
+ def get_dataset_color(self, dataset_label):
+ return getcolor(dataset_label)
+
+ def apply_filters(self, request, queryset):
+ return (
+ super()
+ .apply_filters(request, queryset)
+ .filter(hospedagem_interlegis=True)
+ )
+
+ def get_queryset(self, request):
+ qs = super().get_queryset(request)
+ if request.GET.get("ano", None):
+ # Usuário informou um ano, então vamos mostrar os meses daquele ano
+ qs = (
+ qs.order_by("data_ativacao__month", "tipo_servico__sigla")
+ .values(
+ label=F("data_ativacao__month"),
+ sigla=F("tipo_servico__sigla"),
+ )
+ .annotate(total=Count("id"))
+ )
+ else:
+ qs = (
+ qs.order_by("data_ativacao__year", "tipo_servico__sigla")
+ .values(
+ label=F("data_ativacao__year"),
+ sigla=F("tipo_servico__sigla"),
+ )
+ .annotate(total=Count("id"))
+ )
+ return qs
+
+ def get_labels(self, request, queryset=None):
+ if queryset is None:
+ return list(
+ Servico.objects.filter(hospedagem_interlegis=True)
+ .order_by("data_ativacao__year")
+ .values_list("data_ativacao__year")
+ .distinct("data_ativacao__year")
+ )
+
+ if request.GET.get("ano", None):
+ lang = to_locale(get_language()) + ".UTF-8"
+ locale.setlocale(locale.LC_ALL, lang)
+ map_function = lambda x: _(calendar.month_abbr[x])
+ else:
+ map_function = str
+
+ labels = list({r["label"] for r in queryset})
+ labels.sort()
+ labels = list(map(map_function, labels))
+
+ return labels
+
+ def get_datasets(self, request, queryset=None):
+ if queryset is None:
+ queryset = self.get_queryset(request)
+ if request.GET.get("ano", None):
+ lang = to_locale(get_language()) + ".UTF-8"
+ locale.setlocale(locale.LC_ALL, lang)
+ map_function = lambda x: _(calendar.month_abbr[x])
+ else:
+ map_function = str
+
+ labels = self.get_labels(request, queryset)
+
+ series = {}
+ for d in queryset:
+ sigla = d["sigla"]
+ label = map_function(d["label"])
+ if sigla not in series:
+ series[sigla] = dict(zip(labels, [0] * len(labels)))
+ series[sigla][label] = d["total"]
+
+ return [
+ {
+ "label": s,
+ "data": series[s],
+ "backgroundColor": getcolor(s),
+ }
+ for s in series
+ ]