mirror of https://github.com/interlegis/sigi.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1488 lines
47 KiB
1488 lines
47 KiB
import calendar
|
|
import csv
|
|
import datetime
|
|
import io
|
|
import locale
|
|
import numpy as np
|
|
import pandas as pd
|
|
import xlsxwriter
|
|
from itertools import cycle
|
|
from random import randint, seed
|
|
from django import forms
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.admin.sites import site
|
|
from django.contrib.auth import views as auth_views
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.db.models import Q, Count, F
|
|
from django.http import (
|
|
HttpResponse,
|
|
HttpResponseForbidden,
|
|
HttpResponseRedirect,
|
|
JsonResponse,
|
|
)
|
|
from django.shortcuts import render, get_object_or_404, resolve_url
|
|
from django.template.loader import render_to_string
|
|
from django.urls import reverse, reverse_lazy
|
|
from django.utils import timezone
|
|
from django.utils.text import slugify
|
|
from django.utils.translation import to_locale, get_language, gettext as _
|
|
from django.views.decorators.cache import never_cache
|
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
|
from django.views.generic import (
|
|
TemplateView,
|
|
UpdateView,
|
|
ListView,
|
|
DeleteView,
|
|
CreateView,
|
|
)
|
|
from django_weasyprint.views import WeasyTemplateResponse
|
|
from sigi.apps.casas.models import Funcionario, TipoOrgao, Orgao
|
|
from sigi.apps.contatos.models import UnidadeFederativa
|
|
from sigi.apps.convenios.models import Convenio, Projeto
|
|
from sigi.apps.eventos.models import TipoEvento, Evento
|
|
from sigi.apps.home.models import Cards, Dashboard
|
|
from sigi.apps.ocorrencias.models import Ocorrencia
|
|
from sigi.apps.parlamentares.models import Parlamentar
|
|
from sigi.apps.servicos.models import TipoServico, Servico
|
|
from sigi.apps.servidores.models import Servidor
|
|
from sigi.apps.utils import to_ascii
|
|
|
|
|
|
getcolor = lambda s=None: (
|
|
f"#{randint(32,255):02x}{randint(32,255):02x}{randint(32,255):02x}"
|
|
if s is None
|
|
else f"{seed(s) or ''}#{randint(32,255):02x}{randint(32,255):02x}"
|
|
f"{randint(32,255):02x}"
|
|
)
|
|
|
|
gethighlight = lambda s=None: (
|
|
f"#{randint(32,255):02x}{randint(32,255):02x}{randint(32,255):02x}c0"
|
|
if s is None
|
|
else f"{seed(s) or ''}#{randint(32,255):02x}{randint(32,255):02x}"
|
|
f"{randint(32,255):02x}c0"
|
|
)
|
|
|
|
|
|
################################################################################
|
|
# Views para controle de acesso
|
|
################################################################################
|
|
|
|
|
|
class LoginView(auth_views.LoginView):
|
|
template_name = "registration/login.html"
|
|
|
|
def get_default_redirect_url(self):
|
|
if self.request.user.is_staff:
|
|
login_redirect_url = reverse("admin:index")
|
|
else:
|
|
login_redirect_url = settings.LOGIN_REDIRECT_URL
|
|
return resolve_url(self.next_page or login_redirect_url)
|
|
|
|
|
|
class LogoutView(auth_views.LogoutView):
|
|
template_name = "registration/logout.html"
|
|
|
|
|
|
class PasswordChangeView(auth_views.PasswordChangeView):
|
|
template_name = "material/admin/password_change.html"
|
|
|
|
|
|
class PasswordChangeDoneView(auth_views.PasswordChangeDoneView):
|
|
pass
|
|
|
|
|
|
class PasswordResetView(auth_views.PasswordResetView):
|
|
pass
|
|
|
|
|
|
class PasswordResetDoneView(auth_views.PasswordResetDoneView):
|
|
pass
|
|
|
|
|
|
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
|
|
pass
|
|
|
|
|
|
class PasswordResetCompleteView(auth_views.PasswordResetCompleteView):
|
|
pass
|
|
|
|
|
|
################################################################################
|
|
# Views para site público - acesso dos contatos Interlegis #
|
|
################################################################################
|
|
|
|
|
|
class HomeView(LoginRequiredMixin, TemplateView):
|
|
template_name = "home/public_site/index.html"
|
|
|
|
def get_context_data(self, **kwargs):
|
|
user = self.request.user
|
|
casa_id = self.request.GET.get(
|
|
"id", self.request.session.get("casa_id", None)
|
|
)
|
|
casas = {
|
|
c.id: c
|
|
for c in Orgao.objects.filter(funcionario__email=user.email)
|
|
}
|
|
if casa_id and int(casa_id) in casas:
|
|
casa = casas[int(casa_id)]
|
|
else:
|
|
if casas:
|
|
casa = list(casas.values())[0]
|
|
else:
|
|
casa = None
|
|
if casa:
|
|
self.request.session["casa_id"] = casa.id
|
|
ocorrencias = casa.ocorrencia_set.filter(
|
|
status__in=[
|
|
Ocorrencia.STATUS_ABERTO,
|
|
Ocorrencia.STATUS_REABERTO,
|
|
]
|
|
)
|
|
servicos = casa.servico_set.filter(data_desativacao=None)
|
|
context = super().get_context_data(**kwargs)
|
|
context["casas"] = casas.values()
|
|
context["casa"] = casa
|
|
context["ocorrencias"] = ocorrencias[:5]
|
|
context["servicos"] = servicos
|
|
return context
|
|
|
|
|
|
################################################################################
|
|
# Views e funções do mapa de atuação do Interlegis
|
|
################################################################################
|
|
|
|
|
|
@xframe_options_exempt
|
|
def openmap(request):
|
|
reptype = request.GET.get("reptype", None)
|
|
context = {"is_popup": bool(int(request.GET.get("embed", 0)))}
|
|
|
|
if reptype is None:
|
|
context["tipos_orgao"] = TipoOrgao.objects.filter(legislativo=True)
|
|
context["tipos_servico"] = TipoServico.objects.all()
|
|
context["tipos_convenio"] = Projeto.objects.all()
|
|
context["gerentes"] = Servidor.objects.exclude(casas_que_gerencia=None)
|
|
context["regioes"] = [
|
|
(s, n, UnidadeFederativa.objects.filter(regiao=s))
|
|
for s, n in UnidadeFederativa.REGIAO_CHOICES
|
|
]
|
|
context["pre_tipos_orgao"] = request.GET.getlist("tipo_orgao", None)
|
|
context["pre_tipos_servico"] = request.GET.getlist(
|
|
"tipo_servico", None
|
|
)
|
|
context["pre_tipos_convenio"] = request.GET.getlist(
|
|
"tipo_convenio", None
|
|
)
|
|
context["pre_ufs"] = request.GET.getlist("uf", None)
|
|
context["pre_gerentes"] = request.GET.getlist("gerente", None)
|
|
|
|
return render(request, "home/openmap.html", context)
|
|
else:
|
|
if request.user.is_anonymous():
|
|
return HttpResponseForbidden()
|
|
tipos_orgao = request.GET.getlist("tipo_orgao", [])
|
|
tipos_servico = request.GET.getlist("tipo_servico", [])
|
|
tipos_convenio = request.GET.getlist("tipo_convenio", [])
|
|
gerentes = request.GET.getlist("gerente", [])
|
|
ufs = request.GET.getlist("uf", [])
|
|
casas = openmapdata(request)
|
|
|
|
context["tipos_orgao"] = TipoOrgao.objects.filter(
|
|
legislativo=True, sigla__in=tipos_orgao
|
|
)
|
|
context["tipos_servico"] = TipoServico.objects.filter(
|
|
sigla__in=tipos_servico
|
|
)
|
|
context["tipos_convenio"] = Projeto.objects.filter(
|
|
sigla__in=tipos_convenio
|
|
)
|
|
context["gerentes"] = Servidor.objects.exclude(
|
|
casas_que_gerencia=None
|
|
).filter(id__in=gerentes)
|
|
context["ufs"] = UnidadeFederativa.objects.filter(sigla__in=ufs)
|
|
context["casas"] = casas
|
|
|
|
if reptype == "lista":
|
|
return WeasyTemplateResponse(
|
|
filename="Lista de Casas atendidas.pdf",
|
|
request=request,
|
|
template="home/lista_casas.html",
|
|
context=context,
|
|
content_type="application/pdf",
|
|
)
|
|
else:
|
|
fields = [
|
|
"cnpj",
|
|
"nome",
|
|
"municipio__uf__nome",
|
|
"municipio__uf__regiao",
|
|
"logradouro",
|
|
"bairro",
|
|
"cep",
|
|
"ult_alt_endereco",
|
|
"email",
|
|
]
|
|
if reptype in ("exporta_servico", "exporta"):
|
|
fields.extend(
|
|
[
|
|
"servico__tipo_servico__nome",
|
|
"servico__url",
|
|
"servico__data_ativacao",
|
|
"servico__data_desativacao",
|
|
]
|
|
)
|
|
if reptype in ("exporta_convenio", "exporta"):
|
|
fields.extend(
|
|
[
|
|
"convenio__num_convenio",
|
|
"convenio__num_processo_sf",
|
|
"convenio__projeto__sigla",
|
|
"convenio__data_adesao",
|
|
"convenio__data_termino_vigencia",
|
|
"convenio__data_retorno_assinatura",
|
|
]
|
|
)
|
|
if reptype in ("exporta_contato", "exporta"):
|
|
fields.extend(
|
|
[
|
|
"funcionario__nome",
|
|
"funcionario__setor",
|
|
"funcionario__email",
|
|
"funcionario__nota",
|
|
"funcionario__redes_sociais",
|
|
"funcionario__desativado",
|
|
"funcionario__ult_alteracao",
|
|
]
|
|
)
|
|
|
|
dados = casas.distinct().values(*fields)
|
|
response = HttpResponse(content_type="text/csv")
|
|
writer = csv.DictWriter(response, fieldnames=fields)
|
|
writer.writeheader()
|
|
writer.writerows(dados)
|
|
return response
|
|
|
|
|
|
def openmapdata(request):
|
|
tipos_orgao = request.GET.getlist("tipo_orgao", None)
|
|
tipos_servico = request.GET.getlist("tipo_servico", None)
|
|
tipos_convenio = request.GET.getlist("tipo_convenio", None)
|
|
ufs = request.GET.getlist("uf", None)
|
|
gerentes = request.GET.getlist("gerente", None)
|
|
reptype = request.GET.get("reptype", None)
|
|
|
|
dados = Orgao.objects.all()
|
|
|
|
if tipos_orgao:
|
|
dados = dados.filter(tipo__sigla__in=tipos_orgao)
|
|
else:
|
|
dados = dados.filter(tipo__legislativo=True)
|
|
|
|
if tipos_servico:
|
|
if "none" in tipos_servico:
|
|
dados = dados.filter(servico=None)
|
|
else:
|
|
dados = dados.filter(
|
|
servico__tipo_servico__sigla__in=tipos_servico,
|
|
servico__data_desativacao=None,
|
|
)
|
|
|
|
if tipos_convenio:
|
|
if "none" in tipos_convenio:
|
|
dados = dados.filter(convenio=None)
|
|
else:
|
|
dados = dados.filter(convenio__projeto__sigla__in=tipos_convenio)
|
|
|
|
if ufs:
|
|
dados = dados.filter(municipio__uf__sigla__in=ufs)
|
|
|
|
if gerentes:
|
|
if "none" in gerentes:
|
|
dados = dados.filter(gerentes_interlegis=None)
|
|
else:
|
|
dados = dados.filter(gerentes_interlegis__id__in=gerentes)
|
|
|
|
if not reptype:
|
|
dados = dados.order_by("nome", "id").distinct("nome", "id")
|
|
dados = dados.values_list(
|
|
"id", "nome", "municipio__latitude", "municipio__longitude"
|
|
)
|
|
return JsonResponse(list(dados), safe=False)
|
|
else:
|
|
dados = (
|
|
dados.order_by(
|
|
"municipio__uf__regiao", "municipio__uf__nome", "nome", "id"
|
|
)
|
|
.distinct(
|
|
"municipio__uf__regiao", "municipio__uf__nome", "nome", "id"
|
|
)
|
|
.prefetch_related(
|
|
"servico_set",
|
|
"convenio_set",
|
|
"municipio__uf",
|
|
"gerentes_interlegis",
|
|
)
|
|
)
|
|
return dados
|
|
|
|
|
|
def openmapdetail(request, orgao_id):
|
|
orgao = get_object_or_404(Orgao, id=orgao_id)
|
|
servicos = orgao.servico_set.filter(data_desativacao=None)
|
|
telefones = {
|
|
t.numero.replace(" ", "") for t in orgao.telefones.exclude(numero="")
|
|
}
|
|
telefones.add(orgao.telefone_geral.replace(" ", ""))
|
|
telefones.add(orgao.telefone.replace(" ", ""))
|
|
return render(
|
|
request,
|
|
"home/openmapdetail.html",
|
|
{"orgao": orgao, "servicos": servicos, "telefones": telefones},
|
|
)
|
|
|
|
|
|
def openmapsearch(request):
|
|
q = request.GET.get("q", "")
|
|
if len(q) < 3:
|
|
return JsonResponse({"result": "unsearchable"})
|
|
|
|
dados = Orgao.objects.filter(
|
|
tipo__legislativo=True, search_text__icontains=to_ascii(q)
|
|
)[:10]
|
|
dados = dados.values(
|
|
"id",
|
|
"nome",
|
|
"municipio__uf__sigla",
|
|
"municipio__latitude",
|
|
"municipio__longitude",
|
|
)
|
|
dados = [
|
|
{
|
|
"id": d["id"],
|
|
"label": f"{d['nome']} - {d['municipio__uf__sigla']}",
|
|
"lat": d["municipio__latitude"],
|
|
"lng": d["municipio__longitude"],
|
|
}
|
|
for d in dados
|
|
]
|
|
return JsonResponse(list(dados), safe=False)
|
|
|
|
|
|
@xframe_options_exempt
|
|
def minimapa(request):
|
|
return render(
|
|
request,
|
|
"home/minimapa.html",
|
|
context={
|
|
"mapa_valores": dict(
|
|
Orgao.objects.exclude(municipio__uf__sigla="ZZ")
|
|
.exclude(servico=None)
|
|
.exclude(~Q(servico__data_desativacao=None))
|
|
.filter(tipo__legislativo=True)
|
|
.order_by("municipio__uf__sigla")
|
|
.values_list("municipio__uf__sigla")
|
|
.annotate(orgaos_atendidos=Count("id", distinct=True))
|
|
)
|
|
},
|
|
)
|
|
|
|
|
|
@xframe_options_exempt
|
|
def minimapa_svg(request):
|
|
return render(
|
|
request,
|
|
"home/minimapa.svg",
|
|
context={
|
|
"mapa_valores": dict(
|
|
Orgao.objects.exclude(municipio__uf__sigla="ZZ")
|
|
.exclude(servico=None)
|
|
.exclude(~Q(servico__data_desativacao=None))
|
|
.filter(tipo__legislativo=True)
|
|
.order_by("municipio__uf__sigla")
|
|
.values_list("municipio__uf__sigla")
|
|
.annotate(orgaos_atendidos=Count("id", distinct=True))
|
|
)
|
|
},
|
|
)
|
|
|
|
|
|
################################################################################
|
|
# Views de visualização e edição do dashboard
|
|
################################################################################
|
|
|
|
|
|
@xframe_options_exempt
|
|
def card_snippet(request, card_code):
|
|
card = get_object_or_404(Cards, codigo=card_code)
|
|
if not card.default:
|
|
raise PermissionDenied()
|
|
return render(request, "home/dashboard/card.html", {"card": card})
|
|
|
|
|
|
@login_required
|
|
def card_add_tab(request, tab_slug):
|
|
total = 0
|
|
categoria = tab_slug
|
|
for card in Cards.objects.all():
|
|
if slugify(card.categoria) == tab_slug:
|
|
categoria = card.categoria
|
|
__, created = Dashboard.objects.update_or_create(
|
|
defaults={"ordem": card.ordem},
|
|
usuario=request.user,
|
|
card=card,
|
|
categoria=card.categoria,
|
|
)
|
|
if created:
|
|
total += 1
|
|
messages.info(request, _(f"{total} cards adicionados na aba {categoria}"))
|
|
return HttpResponseRedirect(reverse("admin:index"))
|
|
|
|
|
|
@login_required
|
|
def card_rename_tab(request):
|
|
dados = request.POST.copy()
|
|
dados.pop("csrfmiddlewaretoken")
|
|
categoria_atual = dados.pop("categoria_atual")[0]
|
|
categoria_nova = dados.pop("categoria_nova")[0]
|
|
if categoria_nova != "" and categoria_nova != categoria_atual:
|
|
Dashboard.objects.filter(
|
|
usuario=request.user, categoria=categoria_atual
|
|
).update(categoria=categoria_nova)
|
|
messages.success(request, _("Tab renomeada com sucesso"))
|
|
else:
|
|
messages.warning(request, _("Não foi possível renomear a tab"))
|
|
return HttpResponseRedirect(reverse("admin:index"))
|
|
|
|
|
|
@login_required
|
|
def card_reorder(request):
|
|
dados = request.GET.copy()
|
|
categoria = dados.pop("categoria")[0]
|
|
for codigo, nova_ordem in dados.items():
|
|
Dashboard.objects.filter(
|
|
usuario=request.user, card__codigo=codigo, categoria=categoria
|
|
).update(ordem=nova_ordem)
|
|
return JsonResponse({"result": _("Ordem alterada")})
|
|
|
|
|
|
@login_required
|
|
def card_remove(request, categoria, codigo):
|
|
count, *__ = Dashboard.objects.filter(
|
|
categoria=categoria, card__codigo=codigo
|
|
).delete()
|
|
return JsonResponse({"result": _(f"{count} card(s) removido(s)")})
|
|
|
|
|
|
@login_required
|
|
def card_add(request):
|
|
categoria = request.POST.get("categoria", None)
|
|
codigos = request.POST.getlist("card_id", None)
|
|
|
|
if categoria is None or codigos is None:
|
|
messages.error(request, _("Nenhum card adicionado!"))
|
|
else:
|
|
criados = 0
|
|
for codigo in codigos:
|
|
card = get_object_or_404(Cards, codigo=codigo)
|
|
dash, created = Dashboard.objects.get_or_create(
|
|
{"ordem": card.ordem},
|
|
usuario=request.user,
|
|
card=card,
|
|
categoria=categoria,
|
|
)
|
|
if created:
|
|
criados += 1
|
|
if criados > 0:
|
|
messages.success(
|
|
request, _(f"{criados} card(s) adicionado(s) na aba")
|
|
)
|
|
else:
|
|
messages.info(request, _("Estes cards já estão na aba"))
|
|
return HttpResponseRedirect(reverse("admin:index"))
|
|
|
|
|
|
################################################################################
|
|
# Cards do dashboard
|
|
################################################################################
|
|
|
|
|
|
# Geral ########################################################################
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def resumo_convenios(request):
|
|
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,
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
resumo = context["tabela_resumo_camara"]
|
|
df = resumo.pop("data_frame")
|
|
col = df.columns[0]
|
|
for key, value in resumo.items():
|
|
if hasattr(value, "__iter__") or hasattr(value, "__getitem__"):
|
|
value = value.items() if hasattr(value, "items") else value
|
|
for k, v in value:
|
|
df.loc[f"{key} - {k}"] = {col: v}
|
|
else:
|
|
df.loc[key] = {col: value}
|
|
with io.BytesIO() as output:
|
|
df.to_excel(output)
|
|
return HttpResponse(
|
|
output.getvalue(),
|
|
headers={
|
|
"Content-Type": (
|
|
"application/vnd.openxmlformats-officedocument."
|
|
"spreadsheetml.sheet"
|
|
),
|
|
"Content-Disposition": f'attachment; filename="resumo_convenios.xlsx"',
|
|
},
|
|
)
|
|
|
|
return render(request, "home/dashboard/resumo_convenios.html", context)
|
|
|
|
|
|
# Serviços #####################################################################
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def resumo_seit(request):
|
|
mes = request.GET.get("mes", None)
|
|
ano = request.GET.get("ano", None)
|
|
|
|
try:
|
|
mes = datetime.date(year=int(ano), month=int(mes), day=1)
|
|
tabela_resumo_seit = busca_informacoes_seit(mes)
|
|
except:
|
|
tabela_resumo_seit = busca_informacoes_seit()
|
|
|
|
context = {"tabela_resumo_seit": tabela_resumo_seit}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
resumo = context["tabela_resumo_seit"]
|
|
series = {}
|
|
mes_atual = resumo["mes_atual"].strftime("%m/%Y")
|
|
for s in resumo["servicos"]:
|
|
series[s["nome"]] = {
|
|
"total": s["total"],
|
|
mes_atual: s["novos_mes_atual"],
|
|
}
|
|
series[s["nome"]].update(
|
|
{m["mes"]: m["total"] for m in s["novos_por_mes"]}
|
|
)
|
|
df = pd.DataFrame(series)
|
|
with io.BytesIO() as output:
|
|
df.to_excel(output)
|
|
return HttpResponse(
|
|
output.getvalue(),
|
|
headers={
|
|
"Content-Type": (
|
|
"application/vnd.openxmlformats-officedocument."
|
|
"spreadsheetml.sheet"
|
|
),
|
|
"Content-Disposition": f'attachment; filename="resumo_seit.xlsx"',
|
|
},
|
|
)
|
|
|
|
return render(request, "home/dashboard/resumo_seit.html", context)
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def chart_seit(request):
|
|
hoje = timezone.localdate()
|
|
mes = request.GET.get("mes", hoje.month)
|
|
ano = request.GET.get("ano", hoje.year)
|
|
|
|
mes = datetime.date(year=int(ano), month=int(mes), day=1)
|
|
tabela_resumo_seit = busca_informacoes_seit(mes)
|
|
|
|
data = {
|
|
"type": "line",
|
|
"prevlink": reverse("home_chartseit")
|
|
+ (
|
|
f"?ano={tabela_resumo_seit['mes_anterior'].year}"
|
|
f"&mes={tabela_resumo_seit['mes_anterior'].month}"
|
|
),
|
|
"nextlink": reverse("home_chartseit")
|
|
+ (
|
|
f"?ano={tabela_resumo_seit['proximo_mes'].year}"
|
|
f"&mes={tabela_resumo_seit['proximo_mes'].month}"
|
|
),
|
|
"options": {
|
|
"bezierCurve": False,
|
|
"datasetFill": False,
|
|
"pointDot": False,
|
|
"responsive": True,
|
|
},
|
|
"data": {
|
|
"labels": [
|
|
f"{mes: %m/%Y}"
|
|
for mes in reversed(tabela_resumo_seit["meses"])
|
|
],
|
|
"datasets": [
|
|
{
|
|
"label": servico["nome"],
|
|
"borderColor": servico["cor"],
|
|
"backgroundColor": servico["cor"],
|
|
"data": [
|
|
mes["total"]
|
|
for mes in reversed(servico["novos_por_mes"])
|
|
],
|
|
}
|
|
for servico in tabela_resumo_seit["servicos"]
|
|
],
|
|
},
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=data, chart_type="line", file_name="chart_seit"
|
|
)
|
|
|
|
return JsonResponse(data)
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def chart_uso_servico(request):
|
|
ufs = UnidadeFederativa.objects.all()
|
|
sigla_uf = request.GET.get("uf", "_all")
|
|
|
|
if sigla_uf != "_all":
|
|
uf = get_object_or_404(UnidadeFederativa, sigla=sigla_uf)
|
|
else:
|
|
uf = None
|
|
|
|
counts = {
|
|
f"{key}_count": Count("servico", Q(servico__resultado_verificacao=key))
|
|
for key, *__ in Servico.RESULTADO_CHOICES
|
|
}
|
|
|
|
queryset = TipoServico.objects.exclude(string_pesquisa="").filter(
|
|
servico__data_desativacao=None
|
|
)
|
|
|
|
if uf is not None:
|
|
queryset = queryset.filter(servico__casa_legislativa__municipio__uf=uf)
|
|
|
|
queryset = queryset.annotate(**counts)
|
|
|
|
chart = {
|
|
"data": {
|
|
"datasets": [
|
|
{
|
|
"type": "bar",
|
|
"label": label,
|
|
"data": list(
|
|
queryset.values_list(f"{key}_count", flat=True)
|
|
),
|
|
"backgroundColor": getcolor(label),
|
|
}
|
|
for key, label in Servico.RESULTADO_CHOICES
|
|
],
|
|
"labels": list(queryset.values_list("sigla", flat=True)),
|
|
},
|
|
"actionblock": render_to_string(
|
|
"home/dashboard/ufs_snippet.html",
|
|
context={"ufs": ufs, "uf": uf},
|
|
request=request,
|
|
),
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=chart, chart_type="column", file_name="uso_servico"
|
|
)
|
|
|
|
return JsonResponse(chart)
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def chart_atualizacao_servicos(request):
|
|
intervalos = [
|
|
("Na semana", 7),
|
|
("No mês", 30),
|
|
("No trimestre", 3 * 30),
|
|
("No semestre", 6 * 30),
|
|
("No ano", 365),
|
|
("Mais de ano", None),
|
|
]
|
|
|
|
counts = {}
|
|
hoje = timezone.localdate()
|
|
ate = hoje
|
|
|
|
for label, dias in 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)
|
|
)
|
|
|
|
queryset = (
|
|
TipoServico.objects.exclude(string_pesquisa="")
|
|
.filter(servico__data_desativacao=None)
|
|
.annotate(**counts)
|
|
)
|
|
|
|
chart = {
|
|
"data": {
|
|
"datasets": [
|
|
{
|
|
"type": "bar",
|
|
"label": ts.sigla,
|
|
"data": [
|
|
getattr(ts, slugify(label))
|
|
for label, *__ in intervalos
|
|
],
|
|
"backgroundColor": getcolor(ts.nome),
|
|
}
|
|
for ts in queryset
|
|
],
|
|
"labels": [label for label, *__ in intervalos],
|
|
}
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=chart, chart_type="column", file_name="atualizacao_servicos"
|
|
)
|
|
|
|
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,
|
|
),
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart,
|
|
chart_type="column",
|
|
subtype="stacked",
|
|
file_name="servicos_ativados_ano",
|
|
)
|
|
|
|
return JsonResponse(chart)
|
|
|
|
|
|
# Gerente ######################################################################
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def chart_carteira(request):
|
|
gerentes = Servidor.objects.exclude(casas_que_gerencia=None).annotate(
|
|
total_casas=Count("casas_que_gerencia")
|
|
)
|
|
|
|
data = {
|
|
"type": "doughnut",
|
|
"data": {
|
|
"labels": [g.get_apelido() for g in gerentes],
|
|
"datasets": [
|
|
{
|
|
"label": "",
|
|
"data": [g.total_casas for g in gerentes],
|
|
"backgroundColor": [
|
|
gethighlight(g.get_apelido()) for g in gerentes
|
|
],
|
|
}
|
|
],
|
|
},
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=data, chart_type="doughnut", file_name="casas_por_gerente"
|
|
)
|
|
|
|
return JsonResponse(data)
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def chart_performance(request):
|
|
servidor = request.GET.get("servidor", None)
|
|
gerentes = Servidor.objects.exclude(casas_que_gerencia=None)
|
|
gerente = None
|
|
|
|
if servidor is None:
|
|
if (
|
|
request.user.servidor
|
|
and request.user.servidor.casas_que_gerencia.exists()
|
|
):
|
|
gerente = request.user.servidor
|
|
else:
|
|
servidor = "_all"
|
|
|
|
if servidor is not None and servidor != "_all":
|
|
gerente = get_object_or_404(Servidor, pk=servidor)
|
|
|
|
if gerente is None:
|
|
casas = Orgao.objects.exclude(gerentes_interlegis=None)
|
|
else:
|
|
casas = gerente.casas_que_gerencia
|
|
|
|
data = {
|
|
"type": "doughnut",
|
|
"data": {
|
|
"labels": [_("Utilizam serviços"), _("Não utilizam serviços")],
|
|
"datasets": [
|
|
{
|
|
"label": _("Uso dos serviços"),
|
|
"data": [
|
|
casas.exclude(servico=None).count(),
|
|
casas.filter(servico=None).count(),
|
|
],
|
|
"backgroundColor": ["#91e8e1", "#f7a35c"],
|
|
}
|
|
],
|
|
},
|
|
"actionblock": render_to_string(
|
|
"home/dashboard/gerentes_snippet.html",
|
|
context={"gerentes": gerentes, "gerente": gerente},
|
|
request=request,
|
|
),
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=data, chart_type="doughnut", file_name="performance_gerencia"
|
|
)
|
|
|
|
return JsonResponse(data)
|
|
|
|
|
|
# Eventos ######################################################################
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def eventos_status(request):
|
|
queryset = Evento.objects.values("status").annotate(total=Count("id", Q()))
|
|
statuses = dict(Evento.STATUS_CHOICES)
|
|
|
|
chart = {
|
|
"type": "doughnut",
|
|
"data": {
|
|
"datasets": [
|
|
{
|
|
"label": _("Eventos por status"),
|
|
"data": [e["total"] for e in queryset],
|
|
"backgroundColor": [
|
|
getcolor(statuses[e["status"]]) for e in queryset
|
|
],
|
|
}
|
|
],
|
|
"labels": [statuses[e["status"]] for e in queryset],
|
|
},
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=chart, chart_type="doughnut", file_name="eventos_status"
|
|
)
|
|
|
|
return JsonResponse(chart)
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def eventos_categoria(request):
|
|
queryset = (
|
|
TipoEvento.objects.filter(evento__status="R")
|
|
.values("categoria")
|
|
.annotate(total=Count("evento"))
|
|
)
|
|
categorias = dict(TipoEvento.CATEGORIA_CHOICES)
|
|
|
|
chart = {
|
|
"type": "doughnut",
|
|
"data": {
|
|
"datasets": [
|
|
{
|
|
"label": _("Eventos por categoria"),
|
|
"data": [e["total"] for e in queryset],
|
|
"backgroundColor": [
|
|
getcolor(categorias[e["categoria"]]) for e in queryset
|
|
],
|
|
}
|
|
],
|
|
"labels": [categorias[e["categoria"]] for e in queryset],
|
|
},
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=chart, chart_type="doughnut", file_name="eventos_categoria"
|
|
)
|
|
|
|
return JsonResponse(chart)
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def eventos_ano(request):
|
|
mes = request.GET.get("mes", timezone.localdate().month)
|
|
ano = request.GET.get("ano", timezone.localdate().year)
|
|
|
|
mes = datetime.date(year=int(ano), month=int(mes), day=1)
|
|
mes_anterior = mes - datetime.timedelta(days=1)
|
|
proximo_mes = mes + datetime.timedelta(
|
|
days=calendar.monthrange(mes.year, mes.month)[1]
|
|
)
|
|
|
|
meses = []
|
|
counts = {}
|
|
start = mes
|
|
|
|
for i in range(12):
|
|
meses.append(start)
|
|
counts[f"{start:%m/%Y}"] = Count(
|
|
"evento",
|
|
Q(
|
|
evento__data_inicio__year=start.year,
|
|
evento__data_inicio__month=start.month,
|
|
),
|
|
)
|
|
start = (start - datetime.timedelta(days=1)).replace(day=1)
|
|
|
|
queryset = (
|
|
TipoEvento.objects.filter(evento__status="R")
|
|
.values("categoria")
|
|
.annotate(**counts)
|
|
)
|
|
categorias = dict(TipoEvento.CATEGORIA_CHOICES)
|
|
|
|
chart = {
|
|
"type": "line",
|
|
"prevlink": reverse("eventos_ano")
|
|
+ f"?ano={mes_anterior.year}&mes={mes_anterior.month}",
|
|
"nextlink": reverse("eventos_ano")
|
|
+ f"?ano={proximo_mes.year}&mes={proximo_mes.month}",
|
|
"options": {
|
|
"bezierCurve": False,
|
|
"datasetFill": False,
|
|
"pointDot": False,
|
|
"responsive": True,
|
|
},
|
|
"data": {
|
|
"labels": [f"{mes: %m/%Y}" for mes in reversed(meses)],
|
|
"datasets": [
|
|
{
|
|
"label": categorias[rec["categoria"]],
|
|
"borderColor": getcolor(categorias[rec["categoria"]]),
|
|
"backgroundColor": getcolor(categorias[rec["categoria"]]),
|
|
"data": [rec[f"{mes:%m/%Y}"] for mes in reversed(meses)],
|
|
}
|
|
for rec in queryset
|
|
],
|
|
},
|
|
}
|
|
|
|
if request.GET.get("download", None) == "excel":
|
|
return ChartDownloadResponse(
|
|
chart=chart, chart_type="line", file_name="eventos_ano"
|
|
)
|
|
|
|
return JsonResponse(chart)
|
|
|
|
|
|
################################################################################
|
|
# Views de apoio e relatórios
|
|
################################################################################
|
|
|
|
|
|
@never_cache
|
|
@login_required
|
|
def report_sem_convenio(request):
|
|
modo = request.GET.get("modo", None)
|
|
fmt = request.GET.get("f", "pdf")
|
|
|
|
sc = sem_convenio(detalhe=True)
|
|
|
|
if modo == "H":
|
|
casas = sc["hospedagem"]
|
|
titulo = _(
|
|
"Casas sem convenio que utilizam algum serviço de hospedagem"
|
|
)
|
|
elif modo == "R":
|
|
casas = sc["registro"]
|
|
titulo = _(
|
|
"Casas sem convenio que utilizam somente serviço de registro"
|
|
)
|
|
else:
|
|
casas = sc["total"]
|
|
titulo = _(
|
|
"Casas sem convenio que utilizam algum serviço de registro "
|
|
"e/ou hospedagem"
|
|
)
|
|
|
|
if fmt == "csv":
|
|
response = HttpResponse(content_type="text/csv")
|
|
response["Content-Disposition"] = (
|
|
f"attachment; filename={ titulo }.csv"
|
|
)
|
|
writer = csv.writer(response)
|
|
writer.writerow([titulo])
|
|
writer.writerow([""])
|
|
writer.writerow(["casa", "uf", "gerentes", "serviços"])
|
|
for casa in casas:
|
|
writer.writerow(
|
|
[
|
|
casa.nome,
|
|
casa.municipio.uf.sigla,
|
|
casa.lista_gerentes(fmt="lista"),
|
|
(
|
|
", ".join(
|
|
casa.servico_set.filter(
|
|
data_desativacao__isnull=True
|
|
).values_list("tipo_servico__nome", flat=True)
|
|
)
|
|
),
|
|
]
|
|
)
|
|
return response
|
|
elif fmt == "json":
|
|
data = {
|
|
"titulo": titulo,
|
|
"casas": [
|
|
{
|
|
"nome": casa.nome,
|
|
"uf": casa.municipio.uf.sigla,
|
|
"gerentes": list(
|
|
casa.gerentes_interlegis.all().values_list(
|
|
"nome_completo", flat=True
|
|
)
|
|
),
|
|
"servicos": list(
|
|
casa.servico_set.filter(
|
|
data_desativacao__isnull=True
|
|
).values_list("tipo_servico__nome", flat=True)
|
|
),
|
|
}
|
|
for casa in casas
|
|
],
|
|
}
|
|
return JsonResponse(data, safe=False)
|
|
else:
|
|
context = {"casas": casas, "title": titulo}
|
|
return WeasyTemplateResponse(
|
|
filename=f"{ titulo }.pdf",
|
|
request=request,
|
|
template="home/sem_convenio.html",
|
|
context=context,
|
|
content_type="application/pdf",
|
|
)
|
|
|
|
|
|
def busca_informacoes_camara(tipos=["CM"], label_tipo=_("Câmaras Municipais")):
|
|
camaras = Orgao.objects.filter(tipo__sigla__in=tipos)
|
|
convenios = Convenio.objects.filter(
|
|
casa_legislativa__tipo__sigla__in=tipos
|
|
)
|
|
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()
|
|
)
|
|
|
|
# Retornando listas em forma de dicionario
|
|
return {
|
|
"data_frame": df,
|
|
"totais": ds_totais,
|
|
"sem_convenio": sem_convenio(),
|
|
}
|
|
|
|
|
|
def sem_convenio(detalhe=False):
|
|
if detalhe:
|
|
total = (
|
|
Orgao.objects.exclude(servico=None)
|
|
.filter(servico__data_desativacao=None, convenio=None)
|
|
.order_by("municipio__uf__sigla", "nome")
|
|
.distinct("municipio__uf__sigla", "nome")
|
|
.prefetch_related("servico_set", "gerentes_interlegis")
|
|
)
|
|
hospedagem = (
|
|
Orgao.objects.exclude(servico=None)
|
|
.filter(
|
|
servico__data_desativacao=None,
|
|
servico__tipo_servico__modo="H",
|
|
convenio=None,
|
|
)
|
|
.order_by("municipio__uf__sigla", "nome")
|
|
.distinct("municipio__uf__sigla", "nome")
|
|
.prefetch_related("servico_set", "gerentes_interlegis")
|
|
)
|
|
result = {
|
|
"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):
|
|
if mes_atual is None:
|
|
mes_atual = datetime.date.today().replace(day=1)
|
|
mes_anterior = mes_atual - datetime.timedelta(days=1)
|
|
proximo_mes = mes_atual + datetime.timedelta(
|
|
days=calendar.monthrange(mes_atual.year, mes_atual.month)[1]
|
|
)
|
|
|
|
meses = []
|
|
mes = mes_atual
|
|
for i in range(1, 13):
|
|
meses.append(mes)
|
|
mes = (mes - datetime.timedelta(days=1)).replace(day=1)
|
|
|
|
result = {
|
|
"mes_atual": mes_atual,
|
|
"mes_anterior": mes_anterior,
|
|
"proximo_mes": proximo_mes,
|
|
"meses": meses,
|
|
"titulos": [
|
|
"",
|
|
"Total de casas atendidas",
|
|
"Novas casas em %s/%s" % (mes_anterior.month, mes_anterior.year),
|
|
"Novas casas em %s/%s" % (mes_atual.month, mes_atual.year),
|
|
],
|
|
"servicos": [],
|
|
}
|
|
|
|
for tipo_servico in TipoServico.objects.all():
|
|
por_mes = []
|
|
for mes in meses:
|
|
por_mes.append(
|
|
{
|
|
"mes": f"{mes:%m/%Y}",
|
|
"total": tipo_servico.servico_set.filter(
|
|
data_ativacao__year=mes.year,
|
|
data_ativacao__month=mes.month,
|
|
).count(),
|
|
}
|
|
)
|
|
|
|
result["servicos"].append(
|
|
{
|
|
"nome": tipo_servico.nome,
|
|
"total": tipo_servico.servico_set.filter(
|
|
Q(data_ativacao__lt=proximo_mes)
|
|
& (
|
|
Q(data_desativacao=None)
|
|
| Q(data_desativacao__gt=proximo_mes)
|
|
)
|
|
).count(),
|
|
"novos_mes_anterior": tipo_servico.servico_set.filter(
|
|
data_ativacao__year=mes_anterior.year,
|
|
data_ativacao__month=mes_anterior.month,
|
|
).count(),
|
|
"novos_mes_atual": tipo_servico.servico_set.filter(
|
|
data_ativacao__year=mes_atual.year,
|
|
data_ativacao__month=mes_atual.month,
|
|
).count(),
|
|
"novos_por_mes": por_mes,
|
|
"cor": getcolor(tipo_servico.nome),
|
|
}
|
|
)
|
|
|
|
return result
|
|
|
|
|
|
def color_palete():
|
|
colors = cycle(
|
|
[
|
|
"#7cb5ec",
|
|
"#434348",
|
|
"#90ed7d",
|
|
"#f7a35c",
|
|
"#8085e9",
|
|
"#f15c80",
|
|
"#e4d354",
|
|
"#8085e8",
|
|
"#8d4653",
|
|
"#91e8e1",
|
|
]
|
|
)
|
|
|
|
highlights = cycle(
|
|
[
|
|
"#B0D3F4",
|
|
"#8E8E91",
|
|
"#BCF4B1",
|
|
"#FAC89D",
|
|
"#B3B6F2",
|
|
"#F79DB3",
|
|
"#EFE598",
|
|
"#B3B6F1",
|
|
"#BB9098",
|
|
"#BDF1ED",
|
|
]
|
|
)
|
|
|
|
return (colors, highlights)
|
|
|
|
|
|
def ChartDownloadResponse(chart, chart_type, subtype=None, file_name="chart"):
|
|
bytes = io.BytesIO()
|
|
workbook = xlsxwriter.Workbook(bytes, {"in_memory": True})
|
|
worksheet = workbook.add_worksheet()
|
|
worksheet.write_column("A2", chart["data"]["labels"])
|
|
col = 1
|
|
intervals = []
|
|
for ds in chart["data"]["datasets"]:
|
|
worksheet.write(0, col, ds["label"])
|
|
if type(ds["data"]) is dict:
|
|
dados = ds["data"].values()
|
|
else:
|
|
dados = ds["data"]
|
|
worksheet.write_column(1, col, dados)
|
|
intervals.append(
|
|
(
|
|
f"=Sheet1!${chr(65+col)}$1",
|
|
f"=Sheet1!${chr(65+col)}$2:${chr(65+col)}${len(ds['data'])+1}",
|
|
)
|
|
)
|
|
col += 1
|
|
if subtype:
|
|
workchart = workbook.add_chart(
|
|
{"type": chart_type, "subtype": subtype}
|
|
)
|
|
else:
|
|
workchart = workbook.add_chart({"type": chart_type})
|
|
for name, values in intervals:
|
|
workchart.add_series({"name": name, "values": values})
|
|
worksheet.insert_chart(0, col + 1, workchart)
|
|
workbook.close()
|
|
return HttpResponse(
|
|
bytes.getvalue(),
|
|
headers={
|
|
"Content-Type": (
|
|
"application/vnd.openxmlformats-officedocument."
|
|
"spreadsheetml.sheet"
|
|
),
|
|
"Content-Disposition": f'attachment; filename="{file_name}.xlsx"',
|
|
},
|
|
)
|
|
|
|
|
|
# @never_cache
|
|
# @login_required
|
|
# def index(request):
|
|
# context = {'gerentes': Servidor.objects.exclude(casas_que_gerencia=None)}
|
|
# return render(request, 'index.html', context)
|
|
|
|
# def grafico_convenio_projeto(convenios):
|
|
# colors, highlights = color_palete()
|
|
# projetos = Projeto.objects.all()
|
|
# lista_projetos = [{'label': projeto.sigla,
|
|
# 'value': convenios.filter(projeto=projeto).count(),
|
|
# 'color': colors.next(),
|
|
# 'highlight': highlights.next()}
|
|
# for projeto in projetos]
|
|
# # remove projetos sem convenio
|
|
# lista_projetos = [x for x in lista_projetos if x['value'] > 0]
|
|
|
|
# # print lista_projetos
|
|
# # total_convenios = "Total: " + str(convenios.count())
|
|
# # lista_projetos.insert(0, total_convenios)
|
|
# return lista_projetos
|
|
|
|
# @never_cache
|
|
# @login_required
|
|
# def chart_convenios(request):
|
|
# q = request.GET.get('q', 'all')
|
|
# convenios = Convenio.objects.all()
|
|
# if q == 'assinados':
|
|
# convenios = convenios.exclude(data_retorno_assinatura=None)
|
|
# data = {
|
|
# 'type': 'pie',
|
|
# 'options': {'responsive': False, 'maintainAspectRatio': False},
|
|
# 'data': grafico_convenio_projeto(convenios),
|
|
# }
|
|
# return JsonResponse(data)
|
|
|
|
# def busca_informacoes_diagnostico():
|
|
# return [
|
|
# {'title': _('Diagnósticos digitados'), 'count': Diagnostico.objects.count()},
|
|
# {'title': _('Diagnósticos publicados'), 'count': Diagnostico.objects.filter(publicado=True).count()},
|
|
# ]
|
|
|