Browse Source

Melhorias dashboard

pull/159/head
Sesostris Vieira 2 years ago
parent
commit
4e8d22d48a
  1. 1
      requirements/requirements.txt
  2. 48
      sigi/apps/home/templates/home/dashboard/resumo_convenios.html
  3. 29
      sigi/apps/home/templates/home/dashboard/servicos_ativos_snippet.html
  4. 18
      sigi/apps/home/urls.py
  5. 284
      sigi/apps/home/views.py
  6. 2
      sigi/templates/material/admin/index.html

1
requirements/requirements.txt

@ -2,6 +2,7 @@ docutils==0.19
gunicorn==20.1.0 gunicorn==20.1.0
ibge==0.0.5 ibge==0.0.5
ipython==8.5.0 ipython==8.5.0
pandas==1.5.1
Pillow==9.2.0 Pillow==9.2.0
psycopg2-binary==2.9.3 psycopg2-binary==2.9.3
python-docx==0.8.11 python-docx==0.8.11

48
sigi/apps/home/templates/home/dashboard/resumo_convenios.html

@ -1,5 +1,22 @@
{% load i18n %} {% load i18n %}
<ul class="collapsible" style="width: 100%;">
<li>
<div class="collapsible-header">
{{ tipo }}
</div>
<div class="collapsible-body">
<ul>
{% for key, label in filtros.items %}
<li>
<a class="dashlink" href="{% url "home_resumoconvenios" %}?tipo={{ key }}" data-target="card-resumoconvenios">
{{ label }}
</a>
</li>
{% endfor %}
</ul>
</div>
</li>
</ul>
<a class="waves-effect waves-light btn-small btn-flat" href="{% url 'convenios-report_regiao_pdf' 'CO' %}">Centro Oeste</a> <a class="waves-effect waves-light btn-small btn-flat" href="{% url 'convenios-report_regiao_pdf' 'CO' %}">Centro Oeste</a>
<a class="waves-effect waves-light btn-small btn-flat" href="{% url 'convenios-report_regiao_pdf' 'NE' %}">Nordeste</a> <a class="waves-effect waves-light btn-small btn-flat" href="{% url 'convenios-report_regiao_pdf' 'NE' %}">Nordeste</a>
<a class="waves-effect waves-light btn-small btn-flat" href="{% url 'convenios-report_regiao_pdf' 'NO' %}">Norte</a> <a class="waves-effect waves-light btn-small btn-flat" href="{% url 'convenios-report_regiao_pdf' 'NO' %}">Norte</a>
@ -8,15 +25,16 @@
<table class="responsive-table numeros"> <table class="responsive-table numeros">
<tr> <tr>
{% for item in tabela_resumo_camara.cabecalho_topo %} <th>&nbsp;</th>
<th>{{item}}</th> {% for item in tabela_resumo_camara.data_frame.columns %}
<th>{{ item }}</th>
{% endfor %} {% endfor %}
</tr> </tr>
{% for cabecalho,lista in tabela_resumo_camara.lista_zip %} {% for label, values in tabela_resumo_camara.data_frame.iterrows %}
<tr> <tr>
<th>{{cabecalho}}</th> <th>{{ label }}</th>
{% for item in lista %} {% for value in values %}
<td>{{item}}</td> <td>{{ value }}</td>
{% endfor %} {% endfor %}
</tr> </tr>
{% endfor %} {% endfor %}
@ -24,18 +42,18 @@
<table class="responsive-table numeros"> <table class="responsive-table numeros">
<tr> <tr>
<th>{% trans 'Total de câmaras' %}</th> <th>{% blocktrans with label_tipo=label_tipo %}Total de {{ label_tipo }} do país{% endblocktrans %}</th>
<td>{{ tabela_resumo_camara.total_camaras }}</td> <td>{{ tabela_resumo_camara.total_camaras }}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans 'Câmaras conveniadas' %}</th> <th>{% blocktrans with label_tipo=label_tipo %}{{ label_tipo }} com convênios vigentes{% endblocktrans %}</th>
<td>{{ tabela_resumo_camara.total_camaras_projetos_vigentes }}</td> <td>{{ tabela_resumo_camara.total_camaras_convenios_vigentes }}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans 'Câmaras sem processo' %}</th> <th>{% blocktrans with label_tipo=label_tipo %}{{ label_tipo }} sem nenhum convênio{% endblocktrans %}</th>
<td>{{ tabela_resumo_camara.camaras_sem_processo }}</td> <td>{{ tabela_resumo_camara.camaras_sem_convenio }}</td>
</tr> </tr>
<tr> <tr>
@ -43,20 +61,20 @@
<a href="{% url "home_reportsemconvenio" %}?modo=H" target="_blank" aria-label="{% trans "Listar casas" %}" title="{% trans "Listar casas" %}"><i class="material-icons tiny">list</i></a> <a href="{% url "home_reportsemconvenio" %}?modo=H" target="_blank" aria-label="{% trans "Listar casas" %}" title="{% trans "Listar casas" %}"><i class="material-icons tiny">list</i></a>
<a href="{% url "home_reportsemconvenio" %}?modo=H&f=csv" aria-label="{% trans "Download csv" %}" title="{% trans "Download csv" %}"><i class="material-icons tiny">file_download</i></a> <a href="{% url "home_reportsemconvenio" %}?modo=H&f=csv" aria-label="{% trans "Download csv" %}" title="{% trans "Download csv" %}"><i class="material-icons tiny">file_download</i></a>
</th> </th>
<td>{{ tabela_resumo_camara.sem_convenio.hospedagem|length }}</td> <td>{{ tabela_resumo_camara.sem_convenio.hospedagem }}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans 'Casas sem convenio que utilizam somente serviço de registro' %} <th>{% trans 'Casas sem convenio que utilizam somente serviço de registro' %}
<a href="{% url "home_reportsemconvenio" %}?modo=R" target="_blank" aria-label="{% trans "Listar casas" %}" title="{% trans "Listar casas" %}"><i class="material-icons tiny">list</i></a> <a href="{% url "home_reportsemconvenio" %}?modo=R" target="_blank" aria-label="{% trans "Listar casas" %}" title="{% trans "Listar casas" %}"><i class="material-icons tiny">list</i></a>
<a href="{% url "home_reportsemconvenio" %}?modo=R&f=csv" aria-label="{% trans "Download csv" %}" title="{% trans "Download csv" %}"><i class="material-icons tiny">file_download</i></a> <a href="{% url "home_reportsemconvenio" %}?modo=R&f=csv" aria-label="{% trans "Download csv" %}" title="{% trans "Download csv" %}"><i class="material-icons tiny">file_download</i></a>
</th> </th>
<td>{{ tabela_resumo_camara.sem_convenio.registro|length }}</td> <td>{{ tabela_resumo_camara.sem_convenio.registro }}</td>
</tr> </tr>
<tr> <tr>
<th>{% trans 'Casas sem convenio que utilizam algum serviço de registro e/ou hospedagem' %} <th>{% trans 'Casas sem convenio que utilizam algum serviço de registro e/ou hospedagem' %}
<a href="{% url "home_reportsemconvenio" %}" target="_blank" aria-label="{% trans "Listar casas" %}" title="{% trans "Listar casas" %}"><i class="material-icons tiny">list</i></a> <a href="{% url "home_reportsemconvenio" %}" target="_blank" aria-label="{% trans "Listar casas" %}" title="{% trans "Listar casas" %}"><i class="material-icons tiny">list</i></a>
<a href="{% url "home_reportsemconvenio" %}?f=csv" aria-label="{% trans "Download csv" %}" title="{% trans "Download csv" %}"><i class="material-icons tiny">file_download</i></a> <a href="{% url "home_reportsemconvenio" %}?f=csv" aria-label="{% trans "Download csv" %}" title="{% trans "Download csv" %}"><i class="material-icons tiny">file_download</i></a>
</th> </th>
<td>{{ tabela_resumo_camara.sem_convenio.total|length }}</td> <td>{{ tabela_resumo_camara.sem_convenio.total }}</td>
</tr> </tr>
</table> </table>

29
sigi/apps/home/templates/home/dashboard/servicos_ativos_snippet.html

@ -0,0 +1,29 @@
{% load static i18n %}
<ul class="collapsible uf_selector">
<li>
<div class="collapsible-header">
{% if ano %}
{{ ano }}
{% else %}
{% trans "Todos os anos" %}
{% endif %}
</div>
<div class="collapsible-body">
<ul>
<li>
<a class="dashlink" href="{% url "home_chartservicosano" %}" data-target="chartservicosano-chart">
{% trans "Todos os anos" %}
</a>
</li>
{% for ano in anos %}
<li>
<a class="dashlink" href="{% url "home_chartservicosano" %}?ano={{ ano|safe }}" data-target="chartservicosano-chart">
{{ano|safe }}
</a>
</li>
{% endfor %}
</ul>
</div>
</li>
</ul>

18
sigi/apps/home/urls.py

@ -26,6 +26,11 @@ urlpatterns = [
views.chart_atualizacao_servicos, views.chart_atualizacao_servicos,
name="home_chartatualizacao", name="home_chartatualizacao",
), ),
path(
"home/chartservicosano/",
views.chart_servicos_ano,
name="home_chartservicosano",
),
path( path(
"home/chartperformance/", "home/chartperformance/",
views.chart_performance, views.chart_performance,
@ -82,16 +87,3 @@ urlpatterns = [
name="home_reportsemconvenio", name="home_reportsemconvenio",
), ),
] ]
# from django.conf.urls import patterns, url
# urlpatterns = patterns('sigi.apps.home.views',
# url(r'^$', 'index', name='sigi_index'),
# url(r'^home/chartseit/$', 'chart_seit', name="home_chartseit"),
# url(r'^home/chartconvenios/$', 'chart_convenios', name="home_chartconvenios"),
# url(r'^home/chartcarteira/$', 'chart_carteira', name="home_chartcarteira"),
# url(r'^home/chartperformance/$', 'chart_performance', name="home_chartperformance"),
# url(r'^home/report/semconvenio/$', 'report_sem_convenio', name="home_reportsemconvenio"),
# )

284
sigi/apps/home/views.py

@ -1,6 +1,9 @@
import calendar import calendar
import csv import csv
import datetime import datetime
import locale
import numpy as np
import pandas as pd
from itertools import cycle from itertools import cycle
from random import randint, seed from random import randint, seed
from django import forms from django import forms
@ -23,7 +26,7 @@ from django.template.loader import render_to_string
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.translation import gettext as _ from django.utils.translation import to_locale, get_language, gettext as _
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import ( from django.views.generic import (
@ -453,7 +456,41 @@ def card_add(request):
@never_cache @never_cache
@login_required @login_required
def resumo_convenios(request): def resumo_convenios(request):
context = {"tabela_resumo_camara": busca_informacoes_camara()} tipo = request.GET.get("tipo", "CM")
filtros = {
t.sigla: t.nome
for t in TipoOrgao.objects.filter(sigla__in=["CM", "AL"])
}
filtros["legislativo"] = _("Todo o legislativo")
filtros["outros"] = _("Demais órgãos")
if tipo == "CM":
label_tipo = _("Câmaras Municipais")
tipos = [
tipo,
]
elif tipo == "AL":
label_tipo = _("Assembleias Legislativas")
tipos = [
tipo,
]
elif tipo == "legislativo":
label_tipo = _("Órgãos do legislativo")
tipos = TipoOrgao.objects.filter(legislativo=True).values_list(
"sigla", flat=True
)
else:
label_tipo = _("Outros órgãos")
tipos = TipoOrgao.objects.filter(legislativo=False).values_list(
"sigla", flat=True
)
context = {
"tabela_resumo_camara": busca_informacoes_camara(tipos, label_tipo),
"filtros": filtros,
"tipo": filtros[tipo],
"label_tipo": label_tipo,
}
return render(request, "home/dashboard/resumo_convenios.html", context) return render(request, "home/dashboard/resumo_convenios.html", context)
@ -630,6 +667,78 @@ def chart_atualizacao_servicos(request):
return JsonResponse(chart) return JsonResponse(chart)
@never_cache
@login_required
def chart_servicos_ano(request):
ano = request.GET.get("ano", None)
anos = (
Servico.objects.filter(hospedagem_interlegis=True)
.order_by("data_ativacao__year")
.values_list("data_ativacao__year", flat=True)
.distinct("data_ativacao__year")
)
if ano:
dados = list(
Servico.objects.filter(
hospedagem_interlegis=True, data_ativacao__year=ano
)
.order_by("data_ativacao__month", "tipo_servico__sigla")
.values("data_ativacao__month", "tipo_servico__sigla")
.annotate(total=Count("id"))
)
date_field = "data_ativacao__month"
lang = to_locale(get_language()) + ".UTF-8"
locale.setlocale(locale.LC_ALL, lang)
map_function = lambda x: _(calendar.month_abbr[x])
else:
dados = list(
Servico.objects.filter(hospedagem_interlegis=True)
.order_by("data_ativacao__year", "tipo_servico__sigla")
.values("data_ativacao__year", "tipo_servico__sigla")
.annotate(total=Count("id"))
)
date_field = "data_ativacao__year"
map_function = str
labels_x = list({r[date_field] for r in dados})
labels_x.sort()
labels_x = list(map(map_function, labels_x))
series = {}
for d in dados:
sigla = d["tipo_servico__sigla"]
label = map_function(d[date_field])
if sigla not in series:
series[sigla] = dict(zip(labels_x, [0] * len(labels_x)))
series[sigla][label] = d["total"]
chart = {
"data": {
"datasets": [
{
"type": "bar",
"label": s,
"data": series[s],
"backgroundColor": getcolor(s),
}
for s in series
],
"labels": labels_x,
},
"options": {
"scales": {"x": {"stacked": True}, "y": {"stacked": True}},
"plugins": {"tooltip": {"mode": "index"}},
},
"actionblock": render_to_string(
"home/dashboard/servicos_ativos_snippet.html",
context={"anos": anos, "ano": ano},
request=request,
),
}
return JsonResponse(chart)
# Gerente ###################################################################### # Gerente ######################################################################
@ -836,17 +945,17 @@ def report_sem_convenio(request):
modo = request.GET.get("modo", None) modo = request.GET.get("modo", None)
fmt = request.GET.get("f", "pdf") fmt = request.GET.get("f", "pdf")
sc = sem_convenio() sc = sem_convenio(detalhe=True)
if modo == "H": if modo == "H":
casas = sc["hospedagem"] casas = sc["hospedagem"]
titulo = _( titulo = _(
"Casas sem convenio que utilizam algum serviço de " "hospedagem" "Casas sem convenio que utilizam algum serviço de hospedagem"
) )
elif modo == "R": elif modo == "R":
casas = sc["registro"] casas = sc["registro"]
titulo = _( titulo = _(
"Casas sem convenio que utilizam somente serviço de " "registro" "Casas sem convenio que utilizam somente serviço de registro"
) )
else: else:
casas = sc["total"] casas = sc["total"]
@ -911,109 +1020,100 @@ def report_sem_convenio(request):
) )
def busca_informacoes_camara(): def busca_informacoes_camara(tipos=["CM"], label_tipo=_("Câmaras Municipais")):
camaras = Orgao.objects.filter(tipo__sigla="CM") camaras = Orgao.objects.filter(tipo__sigla__in=tipos)
convenios = Convenio.objects.filter(casa_legislativa__tipo__sigla="CM") convenios = Convenio.objects.filter(casa_legislativa__tipo__sigla="CM")
projetos = Projeto.objects.all()
convenios_assinados = convenios.exclude(data_retorno_assinatura=None) convenios_assinados = convenios.exclude(data_retorno_assinatura=None)
convenios_em_andamento = convenios.filter(data_retorno_assinatura=None) convenios_em_andamento = convenios.filter(data_retorno_assinatura=None)
convenios_vencidos = convenios.filter(
convenios_sem_adesao = convenios.filter(data_adesao=None) data_termino_vigencia__lt=timezone.localdate()
convenios_com_adesao = convenios.exclude(data_adesao=None)
convenios_com_aceite = convenios.exclude(data_termo_aceite=None)
camaras_projetos_vigentes = camaras.exclude(convenio=None).exclude(
convenio__data_termino_vigencia__lt="2022-10-26"
) )
camaras_sem_processo = camaras.filter(convenio=None) camaras_projetos_vigentes = camaras.exclude(convenio=None).exclude(
convenio__in=convenios_vencidos
# Criacao das listas para o resumo de camaras por projeto
cabecalho_topo = [
"",
] # Cabecalho superior da tabela
lista_total = []
lista_nao_aderidas = []
lista_aderidas = []
lista_convenios_assinados = []
lista_convenios_em_andamento = []
lista_camaras_equipadas = []
for projeto in projetos:
conv_assinados_proj = convenios_assinados.filter(projeto=projeto)
conv_em_andamento_proj = convenios_em_andamento.filter(projeto=projeto)
total = camaras.filter(convenio__projeto=projeto).count()
conv_assinados = camaras.filter(
convenio__in=conv_assinados_proj
).count()
conv_andamento = camaras.filter(
convenio__in=conv_em_andamento_proj
).count()
if (total + conv_assinados + conv_andamento) > 0:
cabecalho_topo.append(projeto.sigla)
lista_total.append(total)
lista_convenios_assinados.append(conv_assinados)
lista_convenios_em_andamento.append(conv_andamento)
# Cabecalho da esquerda na tabela
cabecalho_esquerda = (
_("Câmaras municipais"),
_("Câmaras municipais com convênios assinados"),
_("Câmaras municipais convênios em andamento"),
) )
linhas = ( # Dataframe do resumo de camaras por projeto #
lista_total, dataset = {
lista_convenios_assinados, d.pop("convenio__projeto__sigla"): d
lista_convenios_em_andamento, for d in camaras.values("convenio__projeto__sigla").annotate(
) total=Count("id"),
assinados=Count("id", filter=Q(convenio__in=convenios_assinados)),
andamento=Count(
"id", filter=Q(convenio__in=convenios_em_andamento)
),
vigentes=Count("id", filter=Q(id__in=camaras_projetos_vigentes)),
vencidos=Count("id", filter=~Q(id__in=camaras_projetos_vigentes)),
)
}
# Unindo as duas listas para que o cabecalho da esquerda fique junto com sua if None in dataset:
# respectiva linha rec_none = dataset.pop(None)
lista_zip = zip(cabecalho_esquerda, linhas) camaras_sem_convenio = rec_none["total"]
else:
camaras_sem_convenio = 0
df = pd.DataFrame(dataset)
df.rename(
index={
"total": _(f"Total de {label_tipo} conveniados"),
"assinados": _(f"{label_tipo} com convênios assinados"),
"andamento": _(f"{label_tipo} com convênios em andamento"),
"vigentes": _(f"{label_tipo} com convênios vigentes"),
"vencidos": _(f"{label_tipo} com convênios vencidos"),
},
inplace=True,
)
# Retornando listas em forma de dicionario # Retornando listas em forma de dicionario
return { return {
"cabecalho_topo": cabecalho_topo, "data_frame": df,
"lista_zip": lista_zip,
"total_camaras": camaras.count(), "total_camaras": camaras.count(),
"total_camaras_projetos_vigentes": camaras_projetos_vigentes.count(), "total_camaras_convenios_vigentes": camaras_projetos_vigentes.count(),
"camaras_sem_processo": camaras_sem_processo.count(), "camaras_sem_convenio": camaras_sem_convenio,
"sem_convenio": sem_convenio(), "sem_convenio": sem_convenio(),
} }
def sem_convenio(): def sem_convenio(detalhe=False):
total = ( if detalhe:
Orgao.objects.exclude(servico=None) total = (
.filter(servico__data_desativacao=None, convenio=None) Orgao.objects.exclude(servico=None)
.order_by("municipio__uf__sigla", "nome") .filter(servico__data_desativacao=None, convenio=None)
.distinct("municipio__uf__sigla", "nome") .order_by("municipio__uf__sigla", "nome")
) .distinct("municipio__uf__sigla", "nome")
hospedagem = ( .prefetch_related("servico_set", "gerentes_interlegis")
Orgao.objects.exclude(servico=None)
.filter(
servico__data_desativacao=None,
servico__tipo_servico__modo="H",
convenio=None,
) )
.order_by("municipio__uf__sigla", "nome") hospedagem = (
.distinct("municipio__uf__sigla", "nome") Orgao.objects.exclude(servico=None)
) .filter(
reg_keys = set(total.values_list("pk", flat=True)).difference( servico__data_desativacao=None,
set(hospedagem.values_list("pk", flat=True)) servico__tipo_servico__modo="H",
) convenio=None,
registro = Orgao.objects.filter(pk__in=reg_keys).order_by( )
"municipio__uf__sigla", "nome" .order_by("municipio__uf__sigla", "nome")
) .distinct("municipio__uf__sigla", "nome")
return { .prefetch_related("servico_set", "gerentes_interlegis")
"total": total, )
"hospedagem": hospedagem, result = {
"registro": registro, "total": total,
} "hospedagem": hospedagem,
"registro": total.exclude(id__in=hospedagem),
}
else:
result = dict(
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,
),
)
)
result["registro"] = result["total"] - result["hospedagem"]
return result
def busca_informacoes_seit(mes_atual=None): def busca_informacoes_seit(mes_atual=None):

2
sigi/templates/material/admin/index.html

@ -7,7 +7,7 @@
{% endblock %} {% endblock %}
{% block extrahead %} {% block extrahead %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js" integrity="sha512-QSkVNOCYLtj73J4hbmVoOV6KVZuMluZlioC+trLpewV8qMjsWqlIQvkn1KGX2StWvPMdWGBqim1xlC8krl1EKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
{{ block.super }} {{ block.super }}
{% endblock %} {% endblock %}

Loading…
Cancel
Save