Browse Source

Adiciona relatório para IPU

pull/160/head 3.0.18
Sesostris Vieira 2 years ago
parent
commit
3093f3dcab
  1. 120
      sigi/apps/servicos/templates/servicos/casas_atendidas.html
  2. 14
      sigi/apps/servicos/templates/servicos/navigator_snippet.html
  3. 44
      sigi/apps/servicos/urls.py
  4. 507
      sigi/apps/servicos/views.py
  5. 1
      sigi/urls.py

120
sigi/apps/servicos/templates/servicos/casas_atendidas.html

@ -0,0 +1,120 @@
{% load static i18n %}<!DOCTYPE html>
<html lang="pt_BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.2/font/bootstrap-icons.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<title>Órgãos Legislativos atendidos pelo Interlegis</title>
</head>
<body>
<div class="mb-5">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'openmap' %}">Interlegis</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{% url 'servicos_casas_atendidas' %}">{% trans "Tudo" %}</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{% url 'servicos_casas_atendidas' 'ZZ' %}">{% trans "Estrangeiros" %}</a>
</li>
{% for regiao, ufs in regioes %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-{{ regiao }}" role="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ regiao }}
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown-{{ regiao }}">
{% for uf in ufs %}
<li><a class="dropdown-item" href="{% url 'servicos_casas_atendidas' uf.sigla %}">{{ uf.nome }}</a></li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
<ul class="navbar-nav mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link btn btn-outline-primary" aria-current="page" href="?format=csv{% if search_param %}?search={{ search_param }}{% endif %}"><i class="bi bi-filetype-pdf"></i> {% trans "Download CSV" %}</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container mt-3">
<div class="alert alert-info" role="alert">
{% blocktranslate count counter=tot_orgaos %}
Um órgão encontrado
{% plural %}
{{ counter }} órgãos encontrados
{% endblocktranslate %}
{% if uf %}
{% blocktranslate with uf_name=uf.nome%} em {{ uf_name}}{% endblocktranslate %}
{% endif %}
{% if search_param %}
{% blocktranslate with exp=search_param %} que contém <em>{{ exp }}</em>.{% endblocktranslate %}
{% endif %}
</div>
<form class="d-flex">
<div class="input-group">
<input class="form-control" name="search"{% if search_param %} value="{{ search_param }}"{% endif %} type="search" placeholder="{% trans "Pesquisar" %}" aria-label="{% trans "Pesquisar" %}">
<button class="btn btn-secondary" type="submit"><i class="bi bi-search"></i></button>
</div>
</form>
{% include "servicos/navigator_snippet.html" %}
{% for srv in page_obj %}
{% ifchanged srv.casa_legislativa %}
{% if not forloop.first %}
</table></div></div></div>
{% endif %}
{% ifchanged srv.casa_legislativa.municipio.uf %}
<h6 class="mt-3">{% blocktranslate with nome_uf=srv.casa_legislativa.municipio.uf.nome%}Unidade da Federação: {{ nome_uf }}{% endblocktranslate %}</h6>
{% endifchanged %}
<div class="card text-dark bg-light shadow mb-3">
<div class="card-header">
<div class="d-inline-flex">
<div class="me-3 d-none d-lg-block">
{% if srv.casa_legislativa.foto %}
<img src="{{ srv.casa_legislativa.foto.url }}" style="height: 120px;" height="120"/>
{% else %}
<i class="bi bi-buildings" style="font-size: 5rem;"></i>
{% endif %}
</div>
<div class="d-block">
<strong>{{ srv.casa_legislativa.nome }}</strong><br/>
<small>{{ srv.casa_legislativa.cnpj}} - {{ srv.casa_legislativa.tipo.nome }}</small>
<address>
<strong>{{ srv.casa_legislativa.logradouro }} {{ srv.casa_legislativa.bairro }}</strong><br/>
{{ srv.casa_legislativa.cep }} - {{ srv.casa_legislativa.municipio.nome }}, {{ srv.casa_legislativa.municipio.uf.sigla }}<br/>
<a href="mailto:{{ srv.casa_legislativa.email }}" target="_blank">{{ srv.casa_legislativa.email }}</a> - <a href="tel:{{ srv.casa_legislativa.telefone|phone2numeric }}" target="_blank">{{ srv.casa_legislativa.telefone }}</a>
</address>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm">
<tr>
<th>{% trans "Tipo de serviço" %}</th>
<th>{% trans "Data de instalação" %}</th>
<th>{% trans "URL de acesso" %}</th>
</tr>
{% endifchanged %}
<tr>
<td>{{ srv.tipo_servico.nome }}</td>
<td>{{ srv.data_ativacao|date:"SHORT_DATE_FORMAT" }}</td>
<td><a href="{{ srv.url}}" target="_blank">{{ srv.url}}</a></td>
</tr>
{% endfor %}
</table></div></div></div>
{% include "servicos/navigator_snippet.html" %}
</div>
</div>
</body>
</html>

14
sigi/apps/servicos/templates/servicos/navigator_snippet.html

@ -0,0 +1,14 @@
{% load i18n %}
{% if paginator.num_pages > 1 %}
<div class="table-responsive">
<nav aria-label="Page navigation">
<ul class="pagination pagination-sm mt-3">
<li class="page-item{% if not page_obj.has_previous %} disabled{% endif %}"><a class="page-link" href="?page={% if page_obj.has_previous %}{{ page_obj.previous_page_number }}{% else %}1{% endif %}" aria-label="{% trans "Página anterior" %}"><i class="bi bi-chevron-double-left"></i></a></li>
{% for page in paginator.page_range %}
<li class="page-item{% if page == page_obj.number %} active{% endif %} "><a class="page-link" href="?page={{ page }}">{{ page }}</a></li>
{% endfor %}
<li class="page-item{% if not page_obj.has_next %} disabled{% endif %}"><a class="page-link" href="?page={% if page_obj.has_next %}{{ page_obj.next_page_number }}{% else %}1{% endif %}" aria-label="{% trans "Próxima página" %}"><i class="bi bi-chevron-double-right"></i></a></li>
</ul>
</nav>
</div>
{% endif %}

44
sigi/apps/servicos/urls.py

@ -1,34 +1,16 @@
# coding: utf-8
from django.conf.urls import patterns, url
from django.views.generic.base import TemplateView
from django.urls import path
from sigi.apps.servicos import views
from .views import MapaView
urlpatterns = patterns(
"sigi.apps.servicos.views",
url(r"^manifesta/$", "casa_manifesta_view", name="casa-manifesta-view"),
url(
r"^servico/carrinho/$",
"visualizar_carrinho",
name="visualizar-carrinho",
urlpatterns = [
path(
"casasatendidas/",
views.CasasAtendidasListView.as_view(),
name="servicos_casas_atendidas",
kwargs={"sigla_uf": "_all_"},
),
url(
r"^servico/carrinho/excluir_carrinho/$",
"excluir_carrinho",
name="excluir-carrinho",
), # tagerror
url(
r"^servico/carrinho/deleta_itens_carrinho$",
"deleta_itens_carrinho",
name="deleta-itens-carrinho",
), # tagerror
url(r"^servico/csv/$", "export_csv", name="servicos-csv"),
url(
r"^munatenjson/(?P<servico>\w+)/$",
"municipios_atendidos",
name="municipios-atendidos",
path(
"casasatendidas/<str:sigla_uf>/",
views.CasasAtendidasListView.as_view(),
name="servicos_casas_atendidas",
),
url(r"^mapa/(?P<servico>\w+)/$", MapaView.as_view(), name="servicos-mapa"),
# url(r'^listacasas/(?P<sigla>\w+)', 'casas_usam_servico', name="casas-usam-servico"),
)
]

507
sigi/apps/servicos/views.py

@ -1,422 +1,113 @@
# -*- coding: utf-8 -*-
import csv
import json as simplejson # XXX trocar isso por simplesmente import json e refatorar o codigo
from django import forms
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import EmptyPage, InvalidPage, Paginator
from django.db.models import Q
from django.forms.forms import BoundField
from django.http import HttpResponse
from django.http.response import HttpResponseRedirect
from django.shortcuts import render, render_to_response, get_object_or_404
from django.template.context import RequestContext
from django.shortcuts import render
from django.utils.translation import gettext as _
from django.views.generic.base import TemplateView
from django.views.generic import ListView
from import_export import resources
from import_export.fields import Field
from sigi.apps.casas.models import Orgao
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.convenios.views import normaliza_data, query_ordena
from sigi.apps.servicos.models import (
Servico,
TipoServico,
CasaManifesta,
CasaAtendida,
ServicoManifesto,
)
class MapaView(TemplateView):
template_name = "servicos/mapa.html"
def get_context_data(self, **kwargs):
context = super(MapaView, self).get_context_data(**kwargs)
context["servicos"] = TipoServico.objects.all()
return context
def municipios_atendidos(self, servico):
municipios = []
servico = servico.upper()
query = Q()
if servico != "ALL":
for sigla in servico.split("_"):
query = query | Q(tipo_servico__sigla=sigla)
query = Q(data_desativacao=None) & query
for casa in CasaAtendida.objects.all():
if casa.servico_set.filter(query).exists():
m = casa.municipio
municipio = {
"nome": casa.nome + ", " + m.uf.sigla,
"lat": str(m.latitude),
"lng": str(m.longitude),
"servicos": "<ul><li>"
+ "</li><li>".join(
[
s.tipo_servico.nome
for s in casa.servico_set.filter(query)
]
)
+ "</li></ul>",
}
municipios.append(municipio)
return HttpResponse(
simplejson.dumps(municipios), content_type="application/json"
)
class CasaManifestaProtoForm(forms.Form):
fieldsets = None
informante = forms.CharField(max_length=100, required=False)
cargo = forms.CharField(max_length=100, required=False)
email = forms.EmailField(required=False)
def set_fieldsets(self, fieldsets):
result = []
for name, lines in fieldsets:
field_lines = []
for line in lines:
if isinstance(line, str):
line = (line,)
field_line = []
for field_name in line:
field = self.fields[field_name]
bf = BoundField(self, field, field_name)
field_line.append(bf)
field_lines.append(field_line)
result.append(
{"name": name, "lines": field_lines},
)
self.fieldsets = result
def casa_manifesta_view(request):
if "casa_id" in request.GET:
casa_id = request.GET.get("casa_id")
casa = get_object_or_404(Orgao, pk=casa_id)
# Criar um formulário dinâmico
campos = {}
fieldsets = (
(
None,
("informante", "cargo", "email"),
),
)
for ts in TipoServico.objects.all():
campos["possui_%s" % ts.pk] = forms.BooleanField(
label=_("Possui o serviço de %s") % ts.nome, required=False
from sigi.apps.servicos.models import Servico
from sigi.apps.utils import to_ascii
class ServicoResource(resources.ModelResource):
telefone = Field(column_name="casa_legislativa__telefone")
class Meta:
model = Servico
fields = [
"casa_legislativa__cnpj",
"casa_legislativa__nome",
"casa_legislativa__tipo__nome",
"casa_legislativa__logradouro",
"casa_legislativa__bairro",
"casa_legislativa__cep",
"casa_legislativa__municipio__nome",
"casa_legislativa__municipio__uf__sigla",
"casa_legislativa__email",
"telefone",
"tipo_servico__nome",
"data_ativacao",
"url",
]
export_order = fields
def dehydrate_telefone(self, servico):
return servico.casa_legislativa.telefone
class CasasAtendidasListView(ListView):
model = Servico
template_name = "servicos/casas_atendidas.html"
paginate_by = 100
def get_queryset(self):
sigla = self.kwargs["sigla_uf"]
search_param = self.request.GET.get("search", None)
queryset = super().get_queryset()
queryset = (
queryset.filter(
data_desativacao=None, casa_legislativa__tipo__legislativo=True
)
campos["url_%s" % ts.pk] = forms.URLField(
label=_("Informe a URL"), required=False
.select_related(
"tipo_servico",
"casa_legislativa",
"casa_legislativa__municipio",
"casa_legislativa__municipio__uf",
"casa_legislativa__tipo",
)
campos["hospedagem_interlegis_%s" % ts.pk] = forms.BooleanField(
label=_("Serviço está hospedado no Interlegis"), required=False
.order_by(
"casa_legislativa__municipio__uf__nome",
"casa_legislativa__tipo__nome",
"casa_legislativa__nome",
"tipo_servico__nome",
)
fieldsets += (
(
ts.nome,
(
"possui_%s" % ts.pk,
"url_%s" % ts.pk,
"hospedagem_interlegis_%s" % ts.pk,
),
),
)
if search_param:
filter = [
Q(casa_legislativa__search_text__icontains=to_ascii(t.lower()))
for t in search_param.split()
]
queryset = queryset.filter(*filter)
if sigla != "_all_":
queryset = queryset.filter(
casa_legislativa__municipio__uf__sigla=sigla
)
return queryset
CasaManifestaForm = type("", (CasaManifestaProtoForm,), campos)
if request.method == "POST":
cmf = CasaManifestaForm(request.POST)
if cmf.is_valid():
thanks = []
cm, created = CasaManifesta.objects.get_or_create(
casa_legislativa=casa
)
cm.informante = cmf.cleaned_data["informante"]
cm.cargo = cmf.cleaned_data["cargo"]
cm.email = cmf.cleaned_data["email"]
cm.save()
thanks.append((_("Informante"), cmf.cleaned_data["informante"]))
thanks.append((_("Cargo"), cmf.cleaned_data["cargo"]))
thanks.append((_("E-mail"), cmf.cleaned_data["email"]))
for ts in TipoServico.objects.all():
if cmf.cleaned_data["possui_%s" % ts.pk]:
sm, created = ServicoManifesto.objects.get_or_create(
casa_manifesta=cm, servico=ts
)
sm.url = cmf.cleaned_data["url_%s" % ts.pk]
sm.hospedagem_interlegis = cmf.cleaned_data[
"hospedagem_interlegis_%s" % ts.pk
]
sm.save()
thanks.append(
(
ts.nome,
_(
"Possui o serviço acessível em %(url)s %(obs)s"
)
% dict(
url=sm.url,
obs=_("hospedado no Interlegis")
if sm.hospedagem_interlegis
else "",
),
)
)
else:
ServicoManifesto.objects.filter(
casa_manifesta=cm, servico=ts
).delete()
thanks.append((ts.nome, _("Não possui")))
extra_context = {"casa": casa, "thanks": thanks}
else:
extra_context = {"casa": casa, "cmf": cmf}
else:
try:
cm = casa.casamanifesta
values = {
"informante": cm.informante,
"cargo": cm.cargo,
"email": cm.email,
}
for sm in cm.servicomanifesto_set.all():
values["possui_%s" % sm.servico.pk] = True
values["url_%s" % sm.servico.pk] = sm.url
values[
"hospedagem_interlegis_%s" % sm.servico.pk
] = sm.hospedagem_interlegis
cmf = CasaManifestaForm(values)
except:
cmf = CasaManifestaForm()
cmf.set_fieldsets(fieldsets)
extra_context = {"casa": casa, "cmf": cmf}
elif "uf" in request.GET:
uf = request.GET.get("uf")
extra_context = {
"casa_list": Orgao.objects.filter(municipio__uf__sigla=uf)
}
else:
extra_context = {"uf_list": UnidadeFederativa.objects.all()}
return render_to_response(
"servicos/casa_manifesta.html",
extra_context,
context_instance=RequestContext(request),
)
def adicionar_servicos_carrinho(request, queryset=None, id=None):
if request.method == "POST":
ids_selecionados = request.POST.getlist("_selected_action")
if "carrinho_servicos" not in request.session:
request.session["carrinho_servicos"] = ids_selecionados
else:
lista = request.session["carrinho_servicos"]
# Verifica se id já não está adicionado
for id in ids_selecionados:
if id not in lista:
lista.append(id)
request.session["carrinho_servicos"] = lista
def carrinhoOrGet_for_qs(request):
"""
Verifica se existe convênios na sessão se não verifica get e retorna qs correspondente.
"""
if "carrinho_servicos" in request.session:
ids = request.session["carrinho_servicos"]
qs = Servico.objects.filter(pk__in=ids)
qs = qs.order_by(
"casa_legislativa__municipio__uf", "casa_legislativa__municipio"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
sigla = self.kwargs["sigla_uf"]
context["tot_orgaos"] = (
self.get_queryset()
.order_by()
.distinct("casa_legislativa__id")
.count()
)
qs = get_for_qs(request.GET, qs)
else:
qs = Servico.objects.all()
if request.GET:
qs = qs.order_by(
"casa_legislativa__municipio__uf", "casa_legislativa__municipio"
context["regioes"] = [
(
regiao,
UnidadeFederativa.objects.filter(regiao=r).exclude(sigla="ZZ"),
)
qs = get_for_qs(request.GET, qs)
return qs
def adicionar_servicos_carrinho(request, queryset=None, id=None):
if request.method == "POST":
ids_selecionados = request.POST.getlist("_selected_action")
if "carrinho_servicos" not in request.session:
request.session["carrinho_servicos"] = ids_selecionados
else:
lista = request.session["carrinho_servicos"]
# Verifica se id já não está adicionado
for id in ids_selecionados:
if id not in lista:
lista.append(id)
request.session["carrinho_servicos"] = lista
@login_required
def excluir_carrinho(request):
if "carrinho_servicos" in request.session:
del request.session["carrinho_servicos"]
messages.info(request, "O carrinho foi esvaziado")
return HttpResponseRedirect("../../")
@login_required
def deleta_itens_carrinho(request):
if request.method == "POST":
ids_selecionados = request.POST.getlist("_selected_action")
if "carrinho_servicos" in request.session:
lista = request.session["carrinho_servicos"]
for item in ids_selecionados:
lista.remove(item)
if lista:
request.session["carrinho_servicos"] = lista
else:
del lista
del request.session["carrinho_servicos"]
return HttpResponseRedirect(".")
@login_required
def visualizar_carrinho(request):
qs = carrinhoOrGet_for_qs(request)
paginator = Paginator(qs, 100)
# Make sure page request is an int. If not, deliver first page.
# Esteja certo de que o `page request` é um inteiro. Se não, mostre a primeira página.
try:
page = int(request.GET.get("page", "1"))
except ValueError:
page = 1
# Se o page request (9999) está fora da lista, mostre a última página.
try:
paginas = paginator.page(page)
except (EmptyPage, InvalidPage):
paginas = paginator.page(paginator.num_pages)
carrinhoIsEmpty = not ("carrinho_servicos" in request.session)
return render(
request,
"servicos/carrinho.html",
{
"carIsEmpty": carrinhoIsEmpty,
"paginas": paginas,
"query_str": "?" + request.META["QUERY_STRING"],
},
)
def get_for_qs(get, qs):
kwargs = {}
ids = 0
get._mutable = True
normaliza_data(get, "data_ativacao__gte")
normaliza_data(get, "data_ativacao__lte")
get._mutable = False
for k, v in get.iteritems():
if k not in ["page", "pop", "q", "_popup"]:
if not k == "o":
if k == "ot":
qs = query_ordena(qs, get["o"], get["ot"])
else:
kwargs[str(k)] = v
if str(k) == "ids":
ids = 1
break
qs = qs.filter(**kwargs)
if ids:
query = "id IN (" + kwargs["ids"].__str__() + ")"
qs = Servico.objects.extra(where=[query])
return qs
@login_required
def export_csv(request):
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = "attachment; filename=servicos.csv"
csv_writer = csv.writer(response)
servicos = carrinhoOrGet_for_qs(request)
if not servicos:
return HttpResponseRedirect("../")
atributos = [
_("Casa Legislativa"),
_("Contato Interlegis"),
_("Produto"),
_("Data de Ativação"),
]
if request.POST:
atributos = request.POST.getlist("itens_csv_selected")
col_titles = atributos
if _("Casa Legislativa") in col_titles:
pos = col_titles.index(_("Casa Legislativa")) + 1
col_titles.insert(pos, _("uf"))
pos += 1
col_titles.insert(pos, _("email"))
pos += 1
col_titles.insert(pos, _("telefone"))
if _("Contato Interlegis") in col_titles:
pos = col_titles.index(_("Contato Interlegis")) + 1
col_titles.insert(pos, _("Email do contato"))
csv_writer.writerow([s.encode("utf-8") for s in col_titles])
for servico in servicos:
lista = []
for atributo in atributos:
if _("Casa Legislativa") == atributo:
lista.append(servico.casa_legislativa.nome.encode("utf-8"))
lista.append(
servico.casa_legislativa.municipio.uf.sigla.encode("utf-8")
)
lista.append(servico.casa_legislativa.email.encode("utf-8"))
if servico.casa_legislativa.telefone is not None:
lista.append(servico.casa_legislativa.telefone)
else:
lista.append("")
elif _("Contato Interlegis") == atributo:
if servico.casa_legislativa.contato_interlegis is not None:
lista.append(servico.casa_legislativa.contato_interlegis)
lista.append(
servico.casa_legislativa.contato_interlegis.email.encode(
"utf-8"
)
)
else:
lista.append("")
lista.append("")
elif _("Produto") == atributo:
lista.append(servico.tipo_servico.nome.encode("utf-8"))
elif _("Data de Ativação") == atributo:
data = ""
if servico.data_ativacao:
data = servico.data_ativacao.strftime("%d/%m/%Y")
lista.append(data.encode("utf-8"))
else:
pass
csv_writer.writerow(lista)
for r, regiao in UnidadeFederativa.REGIAO_CHOICES
]
context["search_param"] = self.request.GET.get("search", None)
if sigla != "_all_":
context["uf"] = UnidadeFederativa.objects.get(sigla=sigla)
return context
return response
def render_to_response(self, context, **response_kwargs):
format = self.request.GET.get("format", "html")
if format == "csv":
servicos = self.get_queryset()
data = ServicoResource().export(servicos)
return HttpResponse(
data.csv,
content_type="text/csv",
headers={
"Content-Disposition": 'attachment;filename="orgaos_interlegis.csv"'
},
)
return super().render_to_response(context, **response_kwargs)

1
sigi/urls.py

@ -22,6 +22,7 @@ urlpatterns = [
path("casas/", include("sigi.apps.casas.urls")),
path("ocorrencias/", include("sigi.apps.ocorrencias.urls")),
path("parlamentares/", include("sigi.apps.parlamentares.urls")),
path("servicos/", include("sigi.apps.servicos.urls")),
path("admin/casas/", include("sigi.apps.casas.admin_urls")),
path("admin/eventos/", include("sigi.apps.eventos.admin_urls")),
path("admin/convenios/", include("sigi.apps.convenios.urls")),

Loading…
Cancel
Save