Browse Source

Relatórios de erros de importação Gescon. Gertiq #160537

pull/174/head
Sesóstris Vieira 7 months ago
parent
commit
3c21ce5369
  1. 4
      sigi/apps/casas/admin_urls.py
  2. 8
      sigi/apps/casas/forms.py
  3. 44
      sigi/apps/casas/templates/casas/cnpj_duplicado.html
  4. 19
      sigi/apps/casas/templates/casas/cnpj_duplicado_pdf.html
  5. 57
      sigi/apps/casas/templates/casas/cnpj_errado.html
  6. 19
      sigi/apps/casas/templates/casas/cnpj_errado_pdf.html
  7. 37
      sigi/apps/casas/templates/casas/snippets/cnpj_duplicado_snippet.html
  8. 38
      sigi/apps/casas/templates/casas/snippets/cnpj_errado_snippet.html
  9. 120
      sigi/apps/casas/views.py
  10. 8
      sigi/apps/convenios/admin.py
  11. 20
      sigi/apps/convenios/migrations/0036_convenio_erro_gescon.py
  12. 154
      sigi/apps/convenios/models.py
  13. 41
      sigi/apps/convenios/templates/convenios/erros_gescon.html
  14. 21
      sigi/apps/convenios/templates/convenios/erros_gescon_pdf.html
  15. 39
      sigi/apps/convenios/templates/convenios/snippets/erros_gescon_snippet.html
  16. 5
      sigi/apps/convenios/urls.py
  17. 82
      sigi/apps/convenios/views.py
  18. 6
      sigi/menu_conf.yaml
  19. 3
      sigi/settings.py

4
sigi/apps/casas/admin_urls.py

@ -1,7 +1,9 @@
from django.urls import path, include
from django.urls import path
from sigi.apps.casas import views
urlpatterns = [
path("carteira/", views.painel_relacionamento, name="casas_carteira"),
path("gerentes/", views.GerentesListView.as_view(), name="casas_gerentes"),
path("cnpjduplicado/", views.cnpj_duplicado, name="casas_cnpj_duplicado"),
path("cnpjerrado/", views.cnpj_errado, name="casas_cnpj_errado"),
]

8
sigi/apps/casas/forms.py

@ -105,3 +105,11 @@ class FuncionarioForm(forms.ModelForm):
widgets = {
"redes_sociais": MaterialAdminTextareaWidget,
}
class CnpjErradoForm(forms.Form):
has_convenio = forms.BooleanField(
label=_("Mostrar apenas órgãos com convênio"),
required=False,
initial=False,
)

44
sigi/apps/casas/templates/casas/cnpj_duplicado.html

@ -0,0 +1,44 @@
{% extends "admin/base_site.html" %}
{% load static i18n %}
{% block extrastyle %}
{{ block.super }}
<style type="text/css">
table {
width: auto;
}
.bordered {
border-top: 1px solid var(--body-fg);
}
</style>
<link rel="stylesheet" type="text/css" href="/static/css/calendario.css">
{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block content_title %}
<h5>{% blocktranslate with count=orgaos.count %}{{ count }} órgãos com CNPJ duplicado{% endblocktranslate %}</h5>
{% endblock %}
{% block content %}
<div class="fixed-action-btn">
<a class="btn-floating">
<i class="large material-icons">print</i>
</a>
<ul>
<li><a class="btn-floating" href="?fmt=pdf" title="{% trans 'Exportar para PDF' %}" ><i class="material-icons">picture_as_pdf</i></a></li>
<li><a class="btn-floating" href="?fmt=csv" title="{% trans 'Exportar para CSV' %}" ><i class="material-icons">file_download</i></a></li>
</ul>
</div>
{% include "casas/snippets/cnpj_duplicado_snippet.html" with mode="html" %}
{% endblock %}
{% block footer %}
{{ block.super }}
<script>
$(document).ready(function(){
M.FloatingActionButton.init($('.fixed-action-btn'), {hoverEnabled: false});
M.Modal.init($(".modal"));
})
</script>
{% endblock %}

19
sigi/apps/casas/templates/casas/cnpj_duplicado_pdf.html

@ -0,0 +1,19 @@
{% extends "pdf/base_report.html" %}
{% load static i18n %}
{% block page_size %}A4 landscape{% endblock %}
{% block extra_style %}
{{ block.super }}
.bordered td {
border-top: 1px solid #000;
}
{% endblock %}
{% block report_name %}
{% blocktranslate with count=orgaos.count %}{{ count }} órgãos com CNPJ duplicado{% endblocktranslate %}
{% endblock report_name %}
{% block main_content %}
{% include "casas/snippets/cnpj_duplicado_snippet.html" %}
{% endblock %}

57
sigi/apps/casas/templates/casas/cnpj_errado.html

@ -0,0 +1,57 @@
{% extends "admin/base_site.html" %}
{% load static i18n %}
{% block extrastyle %}
{{ block.super }}
<style type="text/css">
table {
width: auto;
}
.bordered {
border-top: 1px solid var(--body-fg);
}
</style>
<link rel="stylesheet" type="text/css" href="/static/css/calendario.css">
{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block content_title %}
<h5>{% blocktranslate with count=orgaos|length %}{{ count }} órgãos com CNPJ digitado errado{% endblocktranslate %}</h5>
{% endblock %}
{% block content %}
<form>
<div class="card">
<div class="card-content">
<label for="{{ form.has_convenio.id_for_label }}">
{{ form.has_convenio }}
<span>{{ form.has_convenio.label }}</span>
</label>
</div>
<div class="card-action">
<button class="waves-effect waves-light btn" type="submit">{% translate "Submit" %}</button>
</div>
</div>
<div class="fixed-action-btn">
<a class="btn-floating">
<i class="large material-icons">print</i>
</a>
<ul>
<li><button class="btn-floating" type="submit" name="fmt" value="pdf" title="{% trans 'Exportar para PDF' %}" ><i class="material-icons">picture_as_pdf</i></button></li>
<li><button class="btn-floating" type="submit" name="fmt" value="csv" title="{% trans 'Exportar para CSV' %}" ><i class="material-icons">file_download</i></button></li>
</ul>
</div>
</form>
{% include "casas/snippets/cnpj_errado_snippet.html" with mode="html" %}
{% endblock %}
{% block footer %}
{{ block.super }}
<script>
$(document).ready(function(){
M.FloatingActionButton.init($('.fixed-action-btn'), {hoverEnabled: false});
M.Modal.init($(".modal"));
})
</script>
{% endblock %}

19
sigi/apps/casas/templates/casas/cnpj_errado_pdf.html

@ -0,0 +1,19 @@
{% extends "pdf/base_report.html" %}
{% load static i18n %}
{% block page_size %}A4 landscape{% endblock %}
{% block extra_style %}
{{ block.super }}
.bordered td {
border-top: 1px solid #000;
}
{% endblock %}
{% block report_name %}
{% blocktranslate with count=orgaos|length %}{{ count }} órgãos com CNPJ digitado errado{% endblocktranslate %}
{% endblock report_name %}
{% block main_content %}
{% include "casas/snippets/cnpj_errado_snippet.html" %}
{% endblock %}

37
sigi/apps/casas/templates/casas/snippets/cnpj_duplicado_snippet.html

@ -0,0 +1,37 @@
{% load i18n %}
<div class="card">
<div class="card-content">
<table class="striped">
<thead>
<tr>
<th>{% translate "ID" %}</th>
<th>{% translate "CNPJ" %}</th>
<th>{% translate "Tipo de órgão" %}</th>
<th>{% translate "Sigla" %}</th>
<th>{% translate "Nome" %}</th>
<th>{% translate "Cidade" %}</th>
<th>{% translate "UF" %}</th>
</tr>
</thead>
<tbody>
{% for orgao in orgaos %}
<tr{% ifchanged orgao.cnpj %} class="bordered"{% endifchanged %}>
<td><a href="{% url 'admin:casas_orgao_change' orgao.id %}">{{ orgao.id|stringformat:"s" }}</a></td>
<td>{{ orgao.cnpj }}</td>
<td>{{ orgao.tipo.nome }}</td>
<td>{{ orgao.sigla }}</td>
<td>{{ orgao.nome }}</td>
<td>{{ orgao.municipio.nome }}</td>
<td>{{ orgao.municipio.uf.sigla }}</td>
</tr>
{% empty %}
<tr>
<td colspam="7">
{% translate "Nenhum órgão com CNPJ duplicado" %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

38
sigi/apps/casas/templates/casas/snippets/cnpj_errado_snippet.html

@ -0,0 +1,38 @@
{% load i18n %}
<div class="card">
<div class="card-content">
<table class="striped">
<thead>
<tr>
<th>{% translate "ID" %}</th>
<th>{% translate "CNPJ" %}</th>
<th>{% translate "Sigla" %}</th>
<th>{% translate "Nome" %}</th>
<th>{% translate "Cidade" %}</th>
<th>{% translate "UF" %}</th>
</tr>
</thead>
<tbody>
{% for orgao in orgaos %}
{% ifchanged orgao.tipo_nome %}
<tr><th colspan="6">{{ orgao.tipo_nome }}</th></tr>
{% endifchanged %}
<tr>
<td><a href="{% url 'admin:casas_orgao_change' orgao.id %}">{{ orgao.id|stringformat:"s" }}</a></td>
<td>{{ orgao.cnpj }}</td>
<td>{{ orgao.sigla }}</td>
<td>{{ orgao.nome }}</td>
<td>{{ orgao.municipio_nome }}</td>
<td>{{ orgao.uf_sigla }}</td>
</tr>
{% empty %}
<tr>
<td colspam="7">
{% translate "Nenhum órgão com CNPJ digitado errado" %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

120
sigi/apps/casas/views.py

@ -1,7 +1,5 @@
import csv
from functools import reduce
from django.db.models import Count, Q, Prefetch
from django.contrib.admin.sites import site
from django.db.models import Count, Q, Prefetch, F
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
@ -19,10 +17,10 @@ from django.views.generic import (
DeleteView,
ListView,
UpdateView,
DetailView,
)
from django_weasyprint.views import WeasyTemplateResponse
from rest_framework import generics, filters
from sigi.apps.casas.forms import FuncionarioForm
from sigi.apps.casas.forms import FuncionarioForm, CnpjErradoForm
from sigi.apps.casas.models import Funcionario, Orgao, TipoOrgao
from sigi.apps.casas.serializers import OrgaoAtendidoSerializer
from sigi.apps.home.mixins import ContatoInterlegisViewMixin
@ -36,6 +34,7 @@ from sigi.apps.ocorrencias.models import Ocorrencia
from sigi.apps.servicos.models import Servico, TipoServico
from sigi.apps.eventos.models import Evento, TipoEvento
from sigi.apps.convenios.models import Convenio
from sigi.apps.utils import valida_cnpj
def resumo_carteira(casas):
@ -339,6 +338,117 @@ def painel_relacionamento(request):
return render(request, "casas/painel.html", context)
@login_required
@staff_member_required
def cnpj_duplicado(request):
formato = request.GET.get("fmt", "html")
dups = (
Orgao.objects.exclude(cnpj="")
.order_by("cnpj")
.values("cnpj")
.annotate(tot=Count("cnpj"))
.filter(tot__gt=1)
.values("cnpj")
)
orgaos = (
Orgao.objects.filter(cnpj__in=dups)
.order_by("cnpj", "nome", "municipio__nome", "municipio__uf")
.prefetch_related("tipo", "municipio", "municipio__uf")
)
context = {
"orgaos": orgaos,
"title": _("Órgãos com CNPJ duplicado"),
}
if formato == "pdf":
return WeasyTemplateResponse(
filename="cnpj_duplicado.pdf",
request=request,
template="casas/cnpj_duplicado_pdf.html",
context=context,
content_type="application/pdf",
)
elif formato == "csv":
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = (
'attachment; filename="cnpj_duplicado.csv"'
)
fieldnames = [
"id",
"cnpj",
"tipo__nome",
"sigla",
"nome",
"municipio__nome",
"municipio__uf__sigla",
]
writer = csv.DictWriter(response, fieldnames)
writer.writeheader()
writer.writerows(orgaos.values(*fieldnames))
return response
return render(request, "casas/cnpj_duplicado.html", context=context)
@login_required
@staff_member_required
def cnpj_errado(request):
formato = request.GET.get("fmt", "html")
form = CnpjErradoForm(request.GET)
if form.is_valid():
has_convenio = form.cleaned_data.get("has_convenio", False)
else:
has_convenio = False
todos_orgaos = (
Orgao.objects.exclude(cnpj="")
.order_by("tipo", "cnpj", "nome")
.annotate(
tipo_nome=F("tipo__nome"),
municipio_nome=F("municipio__nome"),
uf_sigla=F("municipio__uf__sigla"),
)
)
if has_convenio:
todos_orgaos = todos_orgaos.exclude(convenio=None)
orgaos = []
for orgao in todos_orgaos:
if not valida_cnpj(orgao.cnpj):
orgaos.append(orgao)
context = {
"orgaos": orgaos,
"form": form,
"title": _("Órgãos com CNPJ digitado errado"),
}
if formato == "pdf":
return WeasyTemplateResponse(
filename="cnpj_errado.pdf",
request=request,
template="casas/cnpj_errado_pdf.html",
context=context,
content_type="application/pdf",
)
elif formato == "csv":
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = (
'attachment; filename="cnpj_errado.csv"'
)
fieldnames = [
"id",
"cnpj",
"tipo_nome",
"sigla",
"nome",
"municipio_nome",
"uf_sigla",
]
writer = csv.DictWriter(response, fieldnames)
writer.writeheader()
writer.writerows(
[{f: getattr(o, f) for f in fieldnames} for o in orgaos]
)
return response
return render(request, "casas/cnpj_errado.html", context=context)
class GerentesListView(PermissionRequiredMixin, ListView):
template_name = "admin/casas/gerentes_list.html"
_tipos = None

8
sigi/apps/convenios/admin.py

@ -1,6 +1,5 @@
from django.db.models import Q
from django.contrib import admin
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import timezone
from django.utils.translation import gettext as _
from django.utils.safestring import mark_safe
@ -14,12 +13,10 @@ from sigi.apps.convenios.models import (
Convenio,
EquipamentoPrevisto,
Anexo,
Tramitacao,
Gescon,
)
from sigi.apps.utils.mixins import AsciifyQParameter
from sigi.apps.servidores.models import Servidor
from sigi.apps.casas.admin import ConveniosInline, GerentesInterlegisFilter
from sigi.apps.casas.admin import GerentesInterlegisFilter
from sigi.apps.utils.mixins import (
ReturnMixin,
CartExportReportMixin,
@ -172,6 +169,7 @@ class ConvenioAdmin(
_("Gescon"),
{
"fields": (
"erro_gescon",
"atualizacao_gescon",
"observacao_gescon",
"link_gescon",
@ -181,6 +179,7 @@ class ConvenioAdmin(
)
readonly_fields = (
"data_sigi",
"erro_gescon",
"atualizacao_gescon",
"observacao_gescon",
"link_gescon",
@ -210,6 +209,7 @@ class ConvenioAdmin(
"conveniada",
"equipada",
"casa_legislativa__municipio__uf",
"erro_gescon",
)
ordering = (
"casa_legislativa__municipio__uf__sigla",

20
sigi/apps/convenios/migrations/0036_convenio_erro_gescon.py

@ -0,0 +1,20 @@
# Generated by Django 5.0.4 on 2024-05-15 11:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("convenios", "0035_convenio_data_extincao_convenio_motivo_extincao"),
]
operations = [
migrations.AddField(
model_name="convenio",
name="erro_gescon",
field=models.BooleanField(
default=False, max_length=1, verbose_name="erro no Gescon"
),
),
]

154
sigi/apps/convenios/models.py

@ -5,6 +5,7 @@ from hashlib import md5
from pathlib import Path
from django.db import models
from django.db.models import Q, F
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
from django.core.validators import FileExtensionValidator
from django.template import Template, Context
@ -20,7 +21,7 @@ from weasyprint import HTML
from sigi.apps.contatos.models import Municipio, UnidadeFederativa
from sigi.apps.parlamentares.models import Parlamentar
from sigi.apps.utils import to_ascii
from sigi.apps.casas.models import Funcionario, Orgao, TipoOrgao
from sigi.apps.casas.models import Funcionario, Orgao
from sigi.apps.servidores.models import Servidor, Servico
from sigi.apps.utils import editor_help, mask_cnpj
@ -327,6 +328,11 @@ class Convenio(models.Model):
atualizacao_gescon = models.DateTimeField(
_("Data de atualização pelo Gescon"), blank=True, null=True
)
erro_gescon = models.BooleanField(
_("erro no Gescon"),
max_length=1,
default=False,
)
observacao_gescon = models.TextField(
_("Observações da atualização do Gescon"), blank=True
)
@ -636,7 +642,7 @@ class Gescon(models.Model):
importados/atualizados)
"""
def mathnames(nome, orgaos):
def mathnames(nome, orgaos, all=False):
for o, nome_canonico in orgaos:
ratio = SequenceMatcher(
None, to_ascii(nome).lower(), nome_canonico
@ -644,9 +650,9 @@ class Gescon(models.Model):
if ratio > 0.9:
yield (o, ratio)
def get_semelhantes(nome, orgaos):
def get_semelhantes(nome, orgaos, all=False):
return sorted(
mathnames(nome, orgaos),
mathnames(nome, orgaos, all),
key=lambda m: m[1],
)
@ -700,6 +706,9 @@ class Gescon(models.Model):
requests.packages.urllib3.disable_warnings()
report_user = False
Convenio.objects.update(erro_gescon=False)
dominio = get_current_site(None).domain
for sigla_gescon, sigla_sigi in subespecies:
self.add_message(_(f"\n**Importando subespécie {sigla_gescon}**"))
@ -784,6 +793,7 @@ class Gescon(models.Model):
cnpj_masked = mask_cnpj(cnpj)
else:
cnpj = None
cnpj_masked = None
if contrato["nomeFornecedor"]:
nome = to_ascii(
@ -799,70 +809,58 @@ class Gescon(models.Model):
nome = None
# Buscar o Convenio pelo NUP #
try:
convenio = Convenio.objects.get(
projeto=projeto, num_processo_sf=sigad
)
except Convenio.DoesNotExist:
convenios = Convenio.objects.filter(
projeto=projeto, num_processo_sf=sigad
)
if convenios.count() == 0:
# Encontrou 0: Pode ser que só exista com o código Gescon
try:
convenio = Convenio.objects.get(
Q(projeto=projeto)
& Q(
Q(num_convenio=numero)
| Q(num_processo_sf=numero)
)
)
except Convenio.DoesNotExist:
# Encontrou 0: Não existe mesmo. Precisa ser criado.
# Para não esticar muito a profundidade do código,
# vou setar convenio para None e tratar o caso lá na
# frente.
convenio = None
except Convenio.MultipleObjectsReturned:
# Encontrou N: Reportar erro
self.add_message(
_(
f"\t* O contrato {numero} no Gescon pode ser "
"relacionado aos seguintes convênios do SIGI:"
+ ", ".join(
[
reverse(
"admin:convenios_convenio_change",
args=[c.id],
)
for c in Convenio.objects.filter(
Q(num_convenio=numero)
| Q(num_processo_sf=numero)
)
]
)
convenios = Convenio.objects.filter(
Q(projeto=projeto)
& Q(Q(num_convenio=numero) | Q(num_processo_sf=numero))
)
if convenios.count() > 1:
# Encontrou N: Marcamos todos como erro e reportamos
urls = ", ".join(
[
'<a href="{dominio}{uri}">{id}</a>'.format(
dominio=dominio,
uri=reverse(
"admin:convenios_convenio_change",
args=[c.id],
),
id=c.id,
)
)
erros += 1
continue
except Convenio.MultipleObjectsReturned:
for c in convenios
]
)
convenios.update(
erro_gescon=True,
observacao_gescon=_(
"Este convênio possui o mesmo número dos "
f"convenios {urls}"
),
)
self.add_message(
_(
f"\t* O contrato {numero} no Gescon pode ser "
"relacionado aos seguintes convênios do SIGI: "
+ ", ".join(
[
reverse(
"admin:convenios_convenio_change",
args=[c.id],
)
for c in Convenio.objects.filter(
num_processo_sf=sigad
)
]
)
f"\t* O contrato {numero} no Gescon pode "
"ser relacionado aos seguintes convênios "
f"do SIGI: {urls}"
)
)
erros += 1
continue
if convenio is not None:
# Encontrou 1: Basta atualizar
# Porém, talvez seja possível ser desambiguado pelo CNPJ do
# fornecedor
if cnpj_masked is not None:
convenios = convenios.filter(
casa_legislativa__cnpj=cnpj_masked
)
if convenios.count() != 1:
# Continua ambíguo. Não dá pra fazer nada.
continue
if convenios.count() == 1:
# Achou exatamente o único que deveria existir. Basta
# atualizar os dados
convenio = convenios.get()
convenio.projeto = projeto
convenio.num_processo_sf = sigad
convenio.num_convenio = numero
@ -876,10 +874,25 @@ class Gescon(models.Model):
]
convenio.data_pub_diario = contrato["publicacao"]
convenio.atualizacao_gescon = timezone.localtime()
convenio.erro_gescon = False
convenio.observacao_gescon = ""
convenio.id_contrato_gescon = (
contrato["codTextoContrato"] or ""
)
convenio.save()
atualizados += 1
# Corrigir o CNPJ do órgão se estiver diferente do Gescon
# O gescon é um pouquinho mais confiável, por enquanto.
if (
cnpj_masked
and convenio.casa_legislativa.cnpj != cnpj_masked
):
convenio.casa_legislativa.cnpj = cnpj_masked
convenio.casa_legislativa.save()
continue
# Não encontrou o convênio. Vamos tentar criar...
# Se chegou aqui, é porque não encontrou o convênio.
# Um novo convênio precisa ser criado.
# Primeiro, é preciso identificar qual órgão consta no
# contrato do Gescon
if (cnpj is None) and (nome is None):
@ -897,7 +910,7 @@ class Gescon(models.Model):
try:
orgao = Orgao.objects.get(cnpj=cnpj_masked)
except Orgao.MultipleObjectsReturned:
# Pode acontecer de uma cãmara usar o mesmo CNPJ
# Pode acontecer de uma câmara usar o mesmo CNPJ
# da prefeitura, e ambos terem convênio com o ILB.
# Podemos tentar desambiguar pelo nome mais
# semelhante.
@ -912,12 +925,12 @@ class Gescon(models.Model):
.order_by()
.annotate(uf_sigla=F("municipio__uf__sigla"))
],
all=True,
)[0][0]
except Orgao.DoesNotExist:
# Encontrou 0: Vamos seguir sem órgao e tentar
# encontrar pelo nome logo abaixo
orgao = None
if orgao is None:
# Não achou pelo CNPJ. Bora ver se acha por similaridade
# do nome
@ -936,7 +949,7 @@ class Gescon(models.Model):
)
erros += 1
continue
# Primeiro com o nome igual veio do GESCON
# Tentar primeiro com o nome igual veio do GESCON
semelhantes = get_semelhantes(
to_ascii(contrato["nomeFornecedor"]).lower(),
todos_orgaos,
@ -997,9 +1010,20 @@ class Gescon(models.Model):
observacao_gescon=_(
"Importado integralmente do Gescon"
),
id_contrato_gescon=(
contrato["codTextoContrato"] or ""
),
)
convenio.save()
novos += 1
# Corrigir o CNPJ do órgão se estiver diferente do Gescon
# O gescon é um pouquinho mais confiável, por enquanto.
if (
cnpj_masked
and convenio.casa_legislativa.cnpj != cnpj_masked
):
convenio.casa_legislativa.cnpj = cnpj_masked
convenio.casa_legislativa.save()
continue
if novos or erros or alertas or atualizados:

41
sigi/apps/convenios/templates/convenios/erros_gescon.html

@ -0,0 +1,41 @@
{% extends "admin/base_site.html" %}
{% load static i18n %}
{% block extrastyle %}
{{ block.super }}
<style type="text/css">
table {
width: auto;
}
</style>
<link rel="stylesheet" type="text/css" href="/static/css/calendario.css">
{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block content_title %}
<h5>
{% blocktranslate count counter=convenios.count %}
Um convênio com erro na importação do Gescon
{% plural %}
{{ counter }} convênios com erro na importação do Gescon
{% endblocktranslate %}
</h5>
{% endblock %}
{% block breadcrumbs %}
{% endblock %}
{% block content %}
{% include "convenios/snippets/erros_gescon_snippet.html" with mode="html" %}
{% endblock %}
{% block footer %}
{{ block.super }}
<script>
$(document).ready(function(){
M.FloatingActionButton.init($('.fixed-action-btn'), {hoverEnabled: false});
M.Modal.init($(".modal"));
})
</script>
{% endblock %}

21
sigi/apps/convenios/templates/convenios/erros_gescon_pdf.html

@ -0,0 +1,21 @@
{% extends "pdf/base_report.html" %}
{% load static i18n %}
{% block page_size %}A4 landscape{% endblock %}
{% block report_name %}
{% blocktranslate count counter=convenios.count %}
Um convênio com erro na importação do Gescon
{% plural %}
{{ counter }} convênios com erro na importação do Gescon
{% endblocktranslate %}
{% endblock report_name %}
{% block main_content %}
{% include "convenios/snippets/erros_gescon_snippet.html" %}
<div class="new-page"></div>
<div style="padding: 24px;">
<h1>{% translate "Resumo da última importação de dados do Gescon" %}</h1>
{{ ultima_importacao }}
</div>
{% endblock %}

39
sigi/apps/convenios/templates/convenios/snippets/erros_gescon_snippet.html

@ -0,0 +1,39 @@
{% load i18n %}
<div class="card">
<div class="card-content">
<table class="striped">
<thead>
<tr>
<th>{% translate "id SIGI" %}</th>
<th>{% translate "NUP sigad" %}</th>
<th>{% translate "Número" %}</th>
<th>{% translate "Projeto" %}</th>
<th>{% translate "Órgão conveniado" %}</th>
<th>{% translate "UF" %}</th>
<th>{% translate "Erro encontrado" %}</th>
</tr>
</thead>
<tbody>
{% for convenio in convenios %}
<tr>
<td>
<a href="{% url 'admin:convenios_convenio_change' convenio.id %}">{{ convenio.id|stringformat:"s" }}</a>
</td>
<td>{{ convenio.num_processo_sf }}</td>
<td>{{ convenio.num_convenio }}</td>
<td>{{ convenio.projeto.nome }}</td>
<td>{{ convenio.casa_legislativa }}</td>
<td>{{ convenio.casa_legislativa.municipio.uf.sigla }}</td>
<td>{{ convenio.observacao_gescon|safe }}</td>
</tr>
{% empty %}
<tr>
<td colspam="7">
{% translate "Nenhum convênio com erro de importação do Gescon." %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

5
sigi/apps/convenios/urls.py

@ -2,6 +2,11 @@ from django.urls import path
from sigi.apps.convenios import views
urlpatterns = [
path(
"errosgescon/",
views.report_erros_gescon,
name="convenios-report_erros_gescon",
),
path(
"reportsRegiao/<str:regiao>/",
views.report_regiao,

82
sigi/apps/convenios/views.py

@ -1,14 +1,8 @@
import csv
# from django.contrib import messages
from django.contrib import admin
from django.http.response import HttpResponseForbidden
# from django.conf import settings
# from django.core.paginator import Paginator, InvalidPage, EmptyPage
# from django.http import HttpResponse, HttpResponseRedirect
from docutils.core import publish_parts
from django.utils.safestring import mark_safe
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import render, get_list_or_404
from django.template import Context, loader
from django.utils.translation import gettext as _
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
@ -17,12 +11,70 @@ from sigi.apps.casas.models import Orgao
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.convenios.models import Convenio, Gescon, Projeto
# from sigi.apps.convenios.reports import (ConvenioReport,
# ConvenioReportSemAceite,
# ConvenioPorCMReport,
# ConvenioPorALReport,
# ConvenioReportSemAceiteAL,
# ConvenioReportSemAceiteCM)
@login_required
@staff_member_required
def report_erros_gescon(request):
formato = request.GET.get("fmt", "html")
convenios = (
Convenio.objects.filter(erro_gescon=True)
.order_by(
"num_processo_sf",
"projeto",
"num_convenio",
"casa_legislativa",
)
.prefetch_related(
"casa_legislativa", "casa_legislativa__municipio__uf"
)
)
rst = Gescon.load().ultima_importacao
parts = publish_parts(
rst,
writer_name="html5",
settings_overrides={
"input_encoding": "unicode",
"output_encoding": "unicode",
},
)
context = {
"convenios": convenios,
"ultima_importacao": mark_safe(parts["html_body"]),
"title": "Convênios com erros no Gescon",
}
if formato == "pdf":
return WeasyTemplateResponse(
filename="erros_gescon.pdf",
request=request,
template="convenios/erros_gescon_pdf.html",
context=context,
content_type="application/pdf",
)
elif formato == "csv":
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = (
'attachment; filename="erros_gescon.csv"'
)
fieldnames = [
"id",
"num_processo_sf",
"num_convenio",
"projeto__nome",
"casa_legislativa__nome",
"casa_legislativa__municipio__uf__sigla",
"observacao_gescon",
]
writer = csv.DictWriter(response, fieldnames)
writer.writeheader()
writer.writerows(convenios.values(*fieldnames))
response.write("\n\nResumo da última importação do Gescon\n\n")
response.write('"' + rst.replace("\n", '"\n"') + '"')
return response
return render(
request,
"convenios/erros_gescon.html",
context=context,
)
@login_required

6
sigi/menu_conf.yaml

@ -29,6 +29,12 @@ main_menu:
- title: Relatórios
icon: print
children:
- title: Erros importação Gescon
view_name: convenios-report_erros_gescon
- title: Órgãos com CNPJ duplicado
view_name: casas_cnpj_duplicado
- title: Órgãos com CNPJ errado
view_name: casas_cnpj_errado
- title: Eventos por UF
view_name: eventos_eventosporuf
- title: Solicitações de eventos por período

3
sigi/settings.py

@ -66,6 +66,7 @@ INSTALLED_APPS = [
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
"django_extensions",
"django_filters",
]
@ -81,6 +82,8 @@ MIDDLEWARE = [
"sigi.apps.utils.middleware.SigiAlertsMiddleware",
]
SITE_ID = 1
if DEBUG:
INSTALLED_APPS = [
"debug_toolbar",

Loading…
Cancel
Save