mirror of https://github.com/interlegis/sigi.git
Sesostris Vieira
3 years ago
54 changed files with 1779 additions and 896 deletions
@ -0,0 +1,16 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-06-18 13:14 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('casas', '0023_funcionario_cpf_funcionario_identidade'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.DeleteModel( |
||||
|
name='Presidente', |
||||
|
), |
||||
|
] |
@ -0,0 +1,10 @@ |
|||||
|
{% load i18n %} |
||||
|
{% if not anexos %} |
||||
|
<p>{% trans "Nenhum anexo no convênio" %}</p> |
||||
|
{% else %} |
||||
|
<div class="collection"> |
||||
|
{% for anexo in anexos %} |
||||
|
<a href="{{ anexo.arquivo.url }}" target="_blank" class="collection-item">{{ anexo }}</a> |
||||
|
{% endfor %} |
||||
|
</div> |
||||
|
{% endif %} |
@ -0,0 +1,75 @@ |
|||||
|
{% extends "admin/change_form.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block extrastyle %} |
||||
|
{{ block.super }} |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block form_top %} |
||||
|
<div class="row"> |
||||
|
<div class="col s12"> |
||||
|
<ul class="tabs"> |
||||
|
{% for fieldset in adminform %} |
||||
|
<li class="tab"> |
||||
|
<a href="#{{ fieldset.name|default:'geral'|slugify }}"> |
||||
|
{{ fieldset.name|default:_("Geral") }} |
||||
|
</a> |
||||
|
</li> |
||||
|
{% endfor %} |
||||
|
{% for inline_admin_formset in inline_admin_formsets %} |
||||
|
<li class="tab"> |
||||
|
<a href="#{{ inline_admin_formset.opts.verbose_name_plural|slugify }}"> |
||||
|
{{ inline_admin_formset.opts.verbose_name_plural|default:_("inline") }} |
||||
|
</a> |
||||
|
</li> |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block field_sets %} |
||||
|
{% for fieldset in adminform %} |
||||
|
<div id="{{ fieldset.name|default:'geral'|slugify }}" class="col s12" style="height: auto;"> |
||||
|
{% include "admin/includes/fieldset.html" %} |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block inline_field_sets %} |
||||
|
{% for inline_admin_formset in inline_admin_formsets %} |
||||
|
<div id="{{ inline_admin_formset.opts.verbose_name_plural|default:'inline'|slugify }}" class="col s12"> |
||||
|
{% include inline_admin_formset.opts.template %} |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
{% endblock %} |
||||
|
|
||||
|
|
||||
|
{% block footer %} |
||||
|
{{ block.super }} |
||||
|
<script type="text/javascript"> |
||||
|
const resize_tab_content = function($tab_parent, $tab) { |
||||
|
if ($tab_parent.height() != $tab.height()+24) { |
||||
|
$tab_parent.height($tab.height()+24); |
||||
|
} |
||||
|
} |
||||
|
$(document).ready(function(){ |
||||
|
M.Tabs.init($('.tabs'),{swipeable: true, onShow: function(tab) { |
||||
|
var $tab = $(tab); |
||||
|
resize_tab_content($tab.parent(), $tab); |
||||
|
}}); |
||||
|
$(".tabs-content").on("DOMSubtreeModified", function() { |
||||
|
var $tab_parent = $(this); |
||||
|
resize_tab_content($tab_parent, $tab_parent.children(".active")); |
||||
|
}) |
||||
|
}) |
||||
|
</script> |
||||
|
<style> |
||||
|
/* .tabs-content { |
||||
|
overflow-y: auto !important; |
||||
|
} */ |
||||
|
.carousel-item { |
||||
|
height: auto !important; |
||||
|
} |
||||
|
</style> |
||||
|
{% endblock %} |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,23 @@ |
|||||
|
.lista_parlamentares { |
||||
|
width: 100%; |
||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .12), 0 1px 5px 0 rgba(0, 0, 0, .2); |
||||
|
margin: .5rem 0 1rem 0 !important; |
||||
|
} |
||||
|
|
||||
|
.input-field>label { |
||||
|
position: relative; |
||||
|
font-size: 0.8rem; |
||||
|
} |
||||
|
|
||||
|
.suplente { |
||||
|
color: #a5d6a7; |
||||
|
} |
||||
|
|
||||
|
.inativo { |
||||
|
color: #9e9e9e; |
||||
|
} |
||||
|
|
||||
|
.presidente-foto .card-title { |
||||
|
position: relative; |
||||
|
bottom: 2em; |
||||
|
} |
@ -1,98 +1,152 @@ |
|||||
{% extends "admin/base_site.html" %} |
{% extends "admin/base_site.html" %} |
||||
{% load i18n static %} |
{% load i18n static %} |
||||
|
|
||||
|
{% block extrastyle %} |
||||
|
{{ block.super }} |
||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/convite.css' %}"> |
||||
|
{% endblock %} |
||||
|
|
||||
{% block content %} |
{% block content %} |
||||
{{ block.super }} |
{{ block.super }} |
||||
<form action="" method="post" name="convite" enctype="multipart/form-data">{% csrf_token %} |
<form action="" method="post" name="convite" enctype="multipart/form-data"> |
||||
<div class="row"> |
{% csrf_token %} |
||||
<div class="col s12"> |
<div class="row"> |
||||
<h5> |
<div class="col s12"> |
||||
{% blocktranslate with casa_nome=casa.nome evento_nome=evento.nome %} |
<h5> |
||||
Convidar {{ casa_nome }} para {{ evento_nome }} |
{% blocktranslate with casa_nome=casa.nome evento_nome=evento.nome %} |
||||
{% endblocktranslate %} |
Convidar {{ casa_nome }} para {{ evento_nome }} |
||||
</h5> |
{% endblocktranslate %} |
||||
|
</h5> |
||||
|
</div> |
||||
</div> |
</div> |
||||
</div> |
<div class="row"> |
||||
<div class="row"> |
<div class="col s12"> |
||||
<div class="col s12"> |
<div class="card"> |
||||
<div class="card"> |
<div class="card-content"> |
||||
<div class="card-content"> |
<span class="card-title">{% trans "Convite" %}</span> |
||||
<span class="card-title">{% trans "Convite" %}</span> |
{{ form_convite }} |
||||
{{ form_convite }} |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
<div class="row"> |
||||
<div class="row"> |
<div class="col s12"> |
||||
<div class="col s12"> |
<div class="card"> |
||||
<div class="card"> |
<div class="card-content"> |
||||
<div class="card-content"> |
<span class="card-title">{% trans "Casa" %}</span> |
||||
<span class="card-title">{% trans "Casa" %}</span> |
{{ form_casa }} |
||||
{{ form_casa }} |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
<div class="row"> |
||||
<div class="row"> |
<div class="col s12"> |
||||
<div class="col s12"> |
<div class="card"> |
||||
<div class="card"> |
<div class="card-content"> |
||||
<div class="card-content"> |
<span class="card-title">{% trans "Identifique o presidente" %}</span> |
||||
<span class="card-title">{% trans "Dados do presidente" %}</span> |
<div class="row"> |
||||
{{ form_presidente }} |
<div class="col s12"> |
||||
|
<div class="row"> |
||||
|
<div class="input-field col s12"> |
||||
|
<i class="material-icons prefix">search</i> |
||||
|
<input type="text" id="busca_parlamentar" class="autocomplete"{% if presidente %} value="{{ presidente.nome_completo }}"{% endif %}> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="center-align hide" id="load_presidente_form"> |
||||
|
<div class="preloader-wrapper small active"> |
||||
|
<div class="spinner-layer spinner-green-only"> |
||||
|
<div class="circle-clipper left"> |
||||
|
<div class="circle"></div> |
||||
|
</div><div class="gap-patch"> |
||||
|
<div class="circle"></div> |
||||
|
</div><div class="circle-clipper right"> |
||||
|
<div class="circle"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p>{% trans "Carregando dados do parlamentar..." %}</p> |
||||
|
</div> |
||||
|
<div id="presidente-form"> |
||||
|
{% if form_presidente %} |
||||
|
{% include "eventos/snippets/form_presidente_snippet.html" %} |
||||
|
{% endif %} |
||||
|
</div> |
||||
|
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
<div class="row"> |
||||
<div class="row"> |
<div class="col s12"> |
||||
<div class="col s12"> |
<div class="card"> |
||||
<div class="card"> |
<div class="card-content"> |
||||
<div class="card-content"> |
<span class="card-title"> |
||||
<span class="card-title"> |
{% trans "Dados do contato Interlegis" %} |
||||
{% trans "Dados do contato Interlegis" %} |
<a href="#" id="copiar-presidente" class="waves-effect waves-light btn-small light-green accent-1 right"> |
||||
<a href="#" id="copiar-presidente" class="waves-effect waves-light btn-small light-green accent-1 right"> |
<i class="material-icons left">content_copy</i> |
||||
<i class="material-icons left">content_copy</i> |
{% trans "Copiar dados do presidente" %} |
||||
{% trans "Copiar dados do presidente" %} |
</a> |
||||
</a> |
</span> |
||||
</span> |
{{ form_contato }} |
||||
{{ form_contato }} |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
<div class="row"> |
||||
<div class="row"> |
<div class="col s12"> |
||||
<div class="col s12"> |
<div class="card"> |
||||
<div class="card"> |
<div class="card-action"> |
||||
<div class="card-action"> |
<button class="btn waves-effect waves-light" type="submit" name="save"> |
||||
<button class="btn waves-effect waves-light" type="submit" name="save"> |
{% trans "Save" %} |
||||
{% trans "Save" %} |
<i class="material-icons right">send</i> |
||||
<i class="material-icons right">send</i> |
</button> |
||||
</button> |
{% for proj in projetos %} |
||||
{% for proj in projetos %} |
<button class="btn waves-effect waves-light" type="submit" name="save" value="{{ proj.id }}"> |
||||
<button class="btn waves-effect waves-light" type="submit" name="save" value="{{ proj.id }}"> |
{% blocktrans with sigla=proj.sigla %}Salvar e gerar minuta de {{ sigla}}{% endblocktrans %} |
||||
{% blocktrans with sigla=proj.sigla %}Salvar e gerar minuta de {{ sigla}}{% endblocktrans %} |
<i class="material-icons right">picture_as_pdf</i> |
||||
<i class="material-icons right">picture_as_pdf</i> |
</button> |
||||
</button> |
{% endfor %} |
||||
{% endfor %} |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</div> |
</form> |
||||
</form> |
|
||||
{% endblock %} |
{% endblock %} |
||||
|
|
||||
{% block footer %} |
{% block footer %} |
||||
{{ block.super }} |
{{ block.super }} |
||||
<script> |
<script> |
||||
$(document).ready(function() { |
$(document).ready(function() { |
||||
$("#copiar-presidente").click(function(event) { |
$("#copiar-presidente").click(function(event) { |
||||
event.preventDefault(); |
event.preventDefault(); |
||||
var dados = {{% for field in form_presidente %} |
var campos = [['nome_completo', 'nome'], ['cpf', 'cpf'], ['identidade', 'identidade'], ['telefones', 'nota'], ['email', 'email']]; |
||||
{{ field.name }}: $("#{{ field.id_for_label }}").val(),{% endfor %} |
for (var x=0; x<campos.length; x++) { |
||||
}; |
$(`#id_contato-${campos[x][1]}`).val($(`#id_presidente-${campos[x][0]}`).val()); |
||||
{% for field in form_contato %} |
} |
||||
$("#{{ field.id_for_label }}").val(dados.{{ field.name }}); |
}); |
||||
{% endfor %} |
$.ajax("{% url 'parlamentar-json' casa.id %}", { |
||||
|
dataType: 'json', |
||||
|
success: function(data) { |
||||
|
function complete(nome) { |
||||
|
$("#load_presidente_form").removeClass("hide") |
||||
|
$("div#presidente-form").html(""); |
||||
|
$.get(`/eventos/evento/presidente/${data[nome]["id"]}/`, function(html) { |
||||
|
$("div#presidente-form").html(html); |
||||
|
$("#load_presidente_form").addClass("hide") |
||||
|
}) |
||||
|
} |
||||
|
var options = {}; |
||||
|
for (nome in data) {options[nome] = data[nome]["foto"]}; |
||||
|
M.Autocomplete.init( |
||||
|
$('input#busca_parlamentar'), |
||||
|
{data: options, |
||||
|
onAutocomplete: complete }); |
||||
|
}, |
||||
|
error: function(jqXHR, textStatus) { |
||||
|
alert(`Erro ao carregar parlamentares, com status ${textStatus}`); |
||||
|
} |
||||
|
}) |
||||
}) |
}) |
||||
}) |
|
||||
</script> |
</script> |
||||
{% endblock %} |
{% endblock %} |
@ -0,0 +1,11 @@ |
|||||
|
{% load i18n %} |
||||
|
|
||||
|
{% if presidente.foto %} |
||||
|
<div class="presidente-foto"> |
||||
|
<img class="materialboxed" width="120" src="{{ presidente.foto.url }}" alt="{{ presidente.nome_completo }}"> |
||||
|
<script>$(document).ready(function(){M.Materialbox.init($('.materialboxed'));})</script> |
||||
|
{% endif %} |
||||
|
<span class="card-title">{% trans "Complemente os dados do presidente" %}</span> |
||||
|
{% if presidente.foto %}</div>{% endif %} |
||||
|
{{ form_presidente }} |
||||
|
<input type="hidden" name="id_presidente" value="{{ presidente.id|safe }}"> |
@ -0,0 +1,7 @@ |
|||||
|
from django.apps import AppConfig |
||||
|
from django.utils.translation import gettext_lazy as _ |
||||
|
|
||||
|
|
||||
|
class CasasConfig(AppConfig): |
||||
|
name = "sigi.apps.parlamentares" |
||||
|
verbose_name = _("parlamentares") |
@ -0,0 +1,40 @@ |
|||||
|
from requests import options |
||||
|
from django import forms |
||||
|
from django.utils.translation import gettext as _ |
||||
|
from sigi.apps.contatos.models import UnidadeFederativa |
||||
|
|
||||
|
|
||||
|
class ImportForm(forms.Form): |
||||
|
CODIFICACAO_CHOICES = ( |
||||
|
("iso8859-1", _("LATIN 1 (iso-8859-1)")), |
||||
|
("utf-8", _("UTF-8")), |
||||
|
) |
||||
|
UF_CHOICES = [ |
||||
|
("BR", _("Todo o Brasil")), |
||||
|
] + [(uf.sigla, uf.nome) for uf in UnidadeFederativa.objects.all()] |
||||
|
TIPO_CHOICES = [ |
||||
|
("V", _("Vereador")), |
||||
|
("D", _("Deputado Estadual")), |
||||
|
] |
||||
|
codificacao = forms.ChoiceField( |
||||
|
label=_("Codificação de caracteres"), |
||||
|
choices=CODIFICACAO_CHOICES, |
||||
|
help_text=_( |
||||
|
"Verifique no PDF do TSE a codificação de caracteres dos " |
||||
|
"arquivos" |
||||
|
), |
||||
|
) |
||||
|
arquivo_tse = forms.FileField(label=_("Arquivo do TSE"), required=False) |
||||
|
arquivo_redes = forms.FileField( |
||||
|
label=_("Arquivo de redes sociais"), required=False |
||||
|
) |
||||
|
arquivo_fotos = forms.FileField(label=_("Zip das fotos"), required=False) |
||||
|
tipo_candidatos = forms.ChoiceField( |
||||
|
label=_("Tipo de candidatos"), choices=TIPO_CHOICES |
||||
|
) |
||||
|
suplentes = forms.BooleanField( |
||||
|
label=_("Importar suplentes"), required=False |
||||
|
) |
||||
|
uf_importar = forms.ChoiceField( |
||||
|
label=_("Unidade Federativa"), choices=UF_CHOICES |
||||
|
) |
@ -0,0 +1,4 @@ |
|||||
|
from django.conf import settings |
||||
|
|
||||
|
import_path = settings.MEDIA_ROOT / "parlamentares/parlamentar/import" |
||||
|
json_path = import_path / "config.json" |
@ -0,0 +1,355 @@ |
|||||
|
import csv |
||||
|
import zipfile |
||||
|
from datetime import datetime |
||||
|
import json |
||||
|
import logging |
||||
|
from django.contrib.auth import get_user_model |
||||
|
from django.conf import settings |
||||
|
from django.db import transaction |
||||
|
from django.core.mail import send_mail |
||||
|
from django.template.loader import render_to_string |
||||
|
from django.utils.translation import gettext as _ |
||||
|
from django_extensions.management.jobs import MinutelyJob |
||||
|
from sigi.apps.casas.models import Orgao |
||||
|
from sigi.apps.parlamentares.jobs import import_path, json_path |
||||
|
from sigi.apps.parlamentares.models import Parlamentar, Partido |
||||
|
|
||||
|
|
||||
|
class Job(MinutelyJob): |
||||
|
help = "Importa parlamentares de arquivo do TSE" |
||||
|
|
||||
|
def execute(self): |
||||
|
json_data = self.get_json_data() |
||||
|
if json_data is None: |
||||
|
return |
||||
|
json_data["inicio_processamento"] = str(datetime.now()) |
||||
|
result_final = [] |
||||
|
# Importa parlamentares # |
||||
|
if "resultados" in json_data: |
||||
|
result = self.importa_parlamentares( |
||||
|
import_path / json_data["resultados"], json_data |
||||
|
) |
||||
|
if result["erros"]: |
||||
|
self.remove_files(json_data) |
||||
|
self.send_mail(result["erros"], json_data) |
||||
|
return |
||||
|
result_final.append(_("* IMPORTAÇÃO DOS PARLAMENTARES *")) |
||||
|
result_final.extend(result["infos"]) |
||||
|
if "redes_sociais" in json_data: |
||||
|
result = self.importa_redes( |
||||
|
import_path / json_data["redes_sociais"], |
||||
|
json_data["codificacao"], |
||||
|
) |
||||
|
result_final.append(_("* IMPORTAÇÃO DAS REDES SOCIAIS *")) |
||||
|
result_final.extend(result["infos"]) |
||||
|
result_final.append(_("* IMPORTAÇÃO DAS REDES SOCIAIS - ERROS *")) |
||||
|
result_final.extend(result["erros"]) |
||||
|
|
||||
|
if "fotos" in json_data: |
||||
|
result = self.importa_fotos(import_path / json_data["fotos"]) |
||||
|
result_final.append(_("* IMPORTAÇÃO DAS FOTOS *")) |
||||
|
result_final.extend(result["infos"]) |
||||
|
result_final.append(_("* IMPORTAÇÃO DAS FOTOS - ERROS *")) |
||||
|
result_final.extend(result["erros"]) |
||||
|
self.remove_files(json_data) |
||||
|
self.send_mail(result_final, json_data) |
||||
|
return |
||||
|
|
||||
|
def get_json_data(self): |
||||
|
if json_path.is_file(): |
||||
|
data = json.loads(json_path.read_text()) |
||||
|
json_path.unlink(missing_ok=True) |
||||
|
return data |
||||
|
return None |
||||
|
|
||||
|
def remove_files(self, json_data): |
||||
|
if "resultados" in json_data: |
||||
|
(import_path / json_data["resultados"]).unlink(missing_ok=True) |
||||
|
if "redes_sociais" in json_data: |
||||
|
(import_path / json_data["redes_sociais"]).unlink(missing_ok=True) |
||||
|
if "fotos" in json_data: |
||||
|
(import_path / json_data["fotos"]).unlink(missing_ok=True) |
||||
|
|
||||
|
def send_mail(self, result, json_data): |
||||
|
user = get_user_model().objects.get(id=int(json_data["user_id"])) |
||||
|
json_data["fim_processamento"] = str(datetime.now()) |
||||
|
json_data["user"] = user.get_full_name() |
||||
|
del json_data["user_id"] |
||||
|
result = list(dict.fromkeys(result)) |
||||
|
txt_message = "\n".join(result) |
||||
|
html_message = render_to_string( |
||||
|
"parlamentares/import_email.html", |
||||
|
{"result": result, "json_data": json_data}, |
||||
|
) |
||||
|
recipient_list = [a[1] for a in settings.ADMINS].append(user.email) |
||||
|
result_file = import_path / "result.html" |
||||
|
result_file.write_text(html_message, encoding="utf-8") |
||||
|
send_mail( |
||||
|
subject="Resultados da importação de dados de parlamentares", |
||||
|
message=txt_message, |
||||
|
recipient_list=recipient_list, |
||||
|
html_message=html_message, |
||||
|
) |
||||
|
|
||||
|
def importa_parlamentares(self, file_name, json_data): |
||||
|
def limpa_flag(): |
||||
|
# Limpa o flag de importação para garantir que nada seja apagado # |
||||
|
# indevidamente # |
||||
|
Parlamentar.objects.all().update(flag_importa="") |
||||
|
|
||||
|
def marcar_antigos(): |
||||
|
if json_data["sigla_uf"] == "BR": |
||||
|
Parlamentar.objects.filter( |
||||
|
casa_legislativa__tipo__sigla__in=tipo_casa |
||||
|
).update(flag_importa="E") |
||||
|
else: |
||||
|
Parlamentar.objects.filter( |
||||
|
casa_legislativa__municipio__uf__sigla=json_data[ |
||||
|
"sigla_uf" |
||||
|
], |
||||
|
casa_legislativa__tipo__sigla__in=tipo_casa, |
||||
|
).update(flag_importa="E") |
||||
|
|
||||
|
def apagar_antigos(): |
||||
|
Parlamentar.objects.filter(flag_importa="E").delete() |
||||
|
|
||||
|
def apagar_novos(): |
||||
|
Parlamentar.objects.filter(flag_importa="N").delete() |
||||
|
|
||||
|
if json_data["tipo_candidatos"] == "D": |
||||
|
tipo_casa = ["AL", "CT"] |
||||
|
cargos = ["7", "8"] # Deputado Estadual e Distrital |
||||
|
else: |
||||
|
tipo_casa = ["CM"] |
||||
|
cargos = ["13"] |
||||
|
|
||||
|
cod_situacao = ["1", "2", "3"] # Eleito, por qp, por média |
||||
|
if json_data["suplentes"]: |
||||
|
cod_situacao.append("5") # suplente |
||||
|
|
||||
|
result = {"infos": [], "erros": []} |
||||
|
|
||||
|
with open(file_name, "r", encoding=json_data["codificacao"]) as f: |
||||
|
if f.encoding != json_data["codificacao"]: |
||||
|
result["erros"].append( |
||||
|
f"Codificação de caracteres do arquivo {file_name} é " |
||||
|
f"{f.encoding}. Precisa converter para " |
||||
|
f"{json_data['codificacao']}." |
||||
|
) |
||||
|
reader = csv.DictReader(f, delimiter=";") |
||||
|
fields = { |
||||
|
"ANO_ELEICAO", |
||||
|
"SG_UE", |
||||
|
"NM_UE", |
||||
|
"CD_CARGO", |
||||
|
"SQ_CANDIDATO", |
||||
|
"NM_CANDIDATO", |
||||
|
"NM_URNA_CANDIDATO", |
||||
|
"NR_PARTIDO", |
||||
|
"NM_PARTIDO", |
||||
|
"CD_SIT_TOT_TURNO", |
||||
|
} |
||||
|
try: |
||||
|
fieldnames = reader.fieldnames |
||||
|
except Exception as e: |
||||
|
result["erros"].append(str(e)) |
||||
|
fieldnames = [] |
||||
|
|
||||
|
if not fields.issubset(set(fieldnames)): |
||||
|
result["erros"].append( |
||||
|
"Nao foram encontrados todos os campos necessários no " |
||||
|
"arquivo. São esperados os seguintes campos: " |
||||
|
+ ", ".join(fields) |
||||
|
) |
||||
|
|
||||
|
if result["erros"]: |
||||
|
return result |
||||
|
|
||||
|
limpa_flag() |
||||
|
marcar_antigos() |
||||
|
|
||||
|
skiped = 0 |
||||
|
imported = 0 |
||||
|
total = 0 |
||||
|
|
||||
|
apenas_verificar = False |
||||
|
|
||||
|
for row in reader: |
||||
|
total += 1 |
||||
|
if (total % 1000) == 0: |
||||
|
print(total) |
||||
|
if not ( |
||||
|
row["CD_CARGO"] in cargos |
||||
|
and row["CD_SIT_TOT_TURNO"] in cod_situacao |
||||
|
): |
||||
|
skiped += 1 |
||||
|
continue |
||||
|
cod_tse = row["SG_UE"] |
||||
|
legenda = int(row["NR_PARTIDO"]) |
||||
|
# Hack para 2022 - fusão de partidos # |
||||
|
if legenda in [17, 25]: |
||||
|
legenda = 44 |
||||
|
try: |
||||
|
if json_data["tipo_candidatos"] == "V": |
||||
|
casa = Orgao.objects.get( |
||||
|
municipio__codigo_tse=int(cod_tse), |
||||
|
tipo__sigla__in=tipo_casa, |
||||
|
) |
||||
|
else: |
||||
|
casa = Orgao.objects.get( |
||||
|
municipio__uf__sigla=cod_tse, |
||||
|
tipo__sigla__in=tipo_casa, |
||||
|
) |
||||
|
except: |
||||
|
# De agora em diante apenas procura erros, sem criar |
||||
|
# novos parlamentares, para agilizar o processo |
||||
|
apenas_verificar = True |
||||
|
result["erros"].append( |
||||
|
"Não foi encontrada a Casa Legislativa com " |
||||
|
f"o código TSE {cod_tse}. O nome do " |
||||
|
f"ente da federação é {row['NM_UE']}. " |
||||
|
"Corrija o cadastro do SIGI e tente novamente." |
||||
|
) |
||||
|
try: |
||||
|
partido = Partido.objects.get(legenda=legenda) |
||||
|
except: |
||||
|
# De agora em diante apenas procura erros, sem criar |
||||
|
# novos parlamentares, para agilizar o processo |
||||
|
apenas_verificar = True |
||||
|
result["erros"].append( |
||||
|
f"O partido {row['NM_PARTIDO']} de legenda " |
||||
|
f"{legenda} não foi encontrado no SIGI." |
||||
|
) |
||||
|
|
||||
|
if not apenas_verificar: |
||||
|
Parlamentar.objects.update_or_create( |
||||
|
flag_importa="N", |
||||
|
sequencial_tse=row["SQ_CANDIDATO"], |
||||
|
ano_eleicao=row["ANO_ELEICAO"], |
||||
|
nome_completo=row["NM_CANDIDATO"], |
||||
|
nome_parlamentar=row["NM_URNA_CANDIDATO"], |
||||
|
partido=partido, |
||||
|
casa_legislativa=casa, |
||||
|
status_mandato="S" |
||||
|
if row["CD_SIT_TOT_TURNO"] == "5" |
||||
|
else "E", |
||||
|
) |
||||
|
imported += 1 |
||||
|
if result["erros"]: |
||||
|
apagar_novos() |
||||
|
result["infos"] = [] |
||||
|
else: |
||||
|
apagar_antigos() |
||||
|
|
||||
|
limpa_flag() |
||||
|
|
||||
|
result["infos"].append(f"Total de registros lidos: {total}") |
||||
|
result["infos"].append(f"Total de registros ignorados: {skiped}") |
||||
|
result["infos"].append(f"Total de registros importados: {imported}") |
||||
|
|
||||
|
return result |
||||
|
|
||||
|
def importa_redes(self, file_name, codificacao): |
||||
|
result = {"infos": [], "erros": []} |
||||
|
with open(file_name, "r", encoding=codificacao) as f: |
||||
|
if f.encoding != codificacao: |
||||
|
result["erros"].append( |
||||
|
f"Codificação de caracteres do arquivo {file_name} é " |
||||
|
f"{f.encoding}. Precisa converter para {codificacao}." |
||||
|
) |
||||
|
reader = csv.DictReader(f, delimiter=";") |
||||
|
fields = { |
||||
|
"SQ_CANDIDATO", |
||||
|
"DS_URL", |
||||
|
} |
||||
|
try: |
||||
|
fieldnames = reader.fieldnames |
||||
|
except Exception as e: |
||||
|
result["erros"].append(str(e)) |
||||
|
fieldnames = [] |
||||
|
|
||||
|
if not fields.issubset(set(fieldnames)): |
||||
|
result["erros"].append( |
||||
|
"Nao foram encontrados todos os campos necessários no " |
||||
|
"arquivo. São esperados os seguintes campos: " |
||||
|
+ ", ".join(fields) |
||||
|
) |
||||
|
|
||||
|
if result["erros"]: |
||||
|
return result |
||||
|
|
||||
|
skiped = 0 |
||||
|
imported = 0 |
||||
|
total = 0 |
||||
|
|
||||
|
for row in reader: |
||||
|
total += 1 |
||||
|
try: |
||||
|
parlamentar = Parlamentar.objects.get( |
||||
|
sequencial_tse=row["SQ_CANDIDATO"] |
||||
|
) |
||||
|
if ( |
||||
|
row["DS_URL"] |
||||
|
not in parlamentar.redes_sociais.splitlines() |
||||
|
): |
||||
|
parlamentar.redes_sociais += "\n" + row["DS_URL"] |
||||
|
parlamentar.save() |
||||
|
imported += 1 |
||||
|
else: |
||||
|
skiped += 1 |
||||
|
except Parlamentar.DoesNotExist: |
||||
|
skiped += 1 |
||||
|
result["infos"].append(f"Total de registros lidos: {total}") |
||||
|
result["infos"].append(f"Total de registros ignorados: {skiped}") |
||||
|
result["infos"].append(f"Total de registros importados: {imported}") |
||||
|
return result |
||||
|
|
||||
|
def importa_fotos(self, file_name): |
||||
|
result = {"erros": [], "infos": []} |
||||
|
if not zipfile.is_zipfile(file_name): |
||||
|
result["erros"].append("Arquivo de fotos deve ser um ZIP") |
||||
|
return result |
||||
|
|
||||
|
with zipfile.ZipFile(file_name, mode="r") as zip_file: |
||||
|
if zip_file.testzip() is not None: |
||||
|
result["erros"].append("Arquivo de fotos está corrompido") |
||||
|
return result |
||||
|
|
||||
|
sequenciais = {n[3:14]: n for n in zip_file.namelist()} |
||||
|
print(f"Importar {len(sequenciais)} fotos") |
||||
|
parlamentares = Parlamentar.objects.filter( |
||||
|
sequencial_tse__in=sequenciais.keys() |
||||
|
) |
||||
|
|
||||
|
total = len(zip_file.namelist()) |
||||
|
imported = parlamentares.count() |
||||
|
skiped = total - imported |
||||
|
print(f"{imported} parlamentares encontrados") |
||||
|
|
||||
|
if imported <= 0: |
||||
|
result["erros"].append( |
||||
|
"Nenhuma das fotos corresponde a algum parlamentar" |
||||
|
) |
||||
|
return result |
||||
|
|
||||
|
relative_path = Parlamentar.foto.field.upload_to |
||||
|
foto_folder = settings.MEDIA_ROOT / relative_path |
||||
|
|
||||
|
for parlamentar in parlamentares: |
||||
|
foto_nome = sequenciais[parlamentar.sequencial_tse] |
||||
|
try: |
||||
|
zip_file.extract(foto_nome, foto_folder) |
||||
|
parlamentar.foto.name = str(f"{relative_path}/{foto_nome}") |
||||
|
parlamentar.save() |
||||
|
except Exception as e: |
||||
|
result["erros"].append(str(e)) |
||||
|
|
||||
|
result["infos"].extend( |
||||
|
[ |
||||
|
f"Total de fotos no arquivo: {total}", |
||||
|
f"Número de fotos importadas: {imported}", |
||||
|
f"Número de fotos ignoradas: {skiped}", |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
return result |
@ -0,0 +1,9 @@ |
|||||
|
from django_extensions.management.jobs import BaseJob |
||||
|
|
||||
|
|
||||
|
class Job(BaseJob): |
||||
|
help = "My sample job." |
||||
|
|
||||
|
def execute(self): |
||||
|
# executing empty sample job |
||||
|
pass |
@ -0,0 +1,98 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-05-28 13:03 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0003_auto_20210416_0841'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='partido', |
||||
|
name='legenda', |
||||
|
field=models.PositiveIntegerField(default=0, verbose_name='nº da legenda'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='cargo', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='coligacao', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='composicaocoligacao', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='legislatura', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='mandato', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='membromesadiretora', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='mesadiretora', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='parlamentar', |
||||
|
name='email', |
||||
|
field=models.EmailField(blank=True, max_length=254, verbose_name='e-mail'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='parlamentar', |
||||
|
name='foto', |
||||
|
field=models.ImageField(blank=True, height_field='foto_altura', upload_to='fotos/parlamentares', width_field='foto_largura'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='parlamentar', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='parlamentar', |
||||
|
name='sexo', |
||||
|
field=models.CharField(choices=[('M', 'Masculino'), ('F', 'Feminino')], max_length=1), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='partido', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='partido', |
||||
|
name='nome', |
||||
|
field=models.CharField(max_length=50, verbose_name='nome'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='partido', |
||||
|
name='sigla', |
||||
|
field=models.CharField(max_length=20, verbose_name='silga'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='sessaolegislativa', |
||||
|
name='id', |
||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='sessaolegislativa', |
||||
|
name='tipo', |
||||
|
field=models.CharField(choices=[('O', 'Ordinária'), ('E', 'Extraordinária')], default='O', max_length=1), |
||||
|
), |
||||
|
] |
@ -0,0 +1,122 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-05-28 13:44 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
("casas", "0023_funcionario_cpf_funcionario_identidade"), |
||||
|
( |
||||
|
"parlamentares", |
||||
|
"0004_partido_legenda_alter_cargo_id_alter_coligacao_id_and_more", |
||||
|
), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RemoveField( |
||||
|
model_name="parlamentar", |
||||
|
name="pagina_web", |
||||
|
), |
||||
|
migrations.RemoveField( |
||||
|
model_name="parlamentar", |
||||
|
name="sexo", |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="casa_legislativa", |
||||
|
field=models.ForeignKey( |
||||
|
default=1, |
||||
|
on_delete=django.db.models.deletion.CASCADE, |
||||
|
to="casas.orgao", |
||||
|
verbose_name="casa legislativa", |
||||
|
), |
||||
|
preserve_default=False, |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="cpf", |
||||
|
field=models.CharField( |
||||
|
blank=True, max_length=20, verbose_name="CPF" |
||||
|
), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="identidade", |
||||
|
field=models.CharField( |
||||
|
blank=True, |
||||
|
help_text="Informe o RG e o órgão emissor.", |
||||
|
max_length=30, |
||||
|
verbose_name="Identidade (RG)", |
||||
|
), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="observacoes", |
||||
|
field=models.TextField(blank=True, verbose_name="observações"), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="partido", |
||||
|
field=models.ForeignKey( |
||||
|
default=1, |
||||
|
on_delete=django.db.models.deletion.CASCADE, |
||||
|
to="parlamentares.partido", |
||||
|
verbose_name="partido", |
||||
|
), |
||||
|
preserve_default=False, |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="presidente", |
||||
|
field=models.BooleanField(default=False, verbose_name="presidente"), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="redes_sociais", |
||||
|
field=models.TextField( |
||||
|
blank=True, |
||||
|
help_text="Colocar um por linha", |
||||
|
verbose_name="redes sociais", |
||||
|
), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="telefones", |
||||
|
field=models.CharField( |
||||
|
blank=True, max_length=250, null=True, verbose_name="telefones" |
||||
|
), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="parlamentar", |
||||
|
name="ult_alteracao", |
||||
|
field=models.DateTimeField( |
||||
|
auto_now=True, null=True, verbose_name="última alteração" |
||||
|
), |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="Mandato", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="MembroMesaDiretora", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="Cargo", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="SessaoLegislativa", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="MesaDiretora", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="ComposicaoColigacao", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="Coligacao", |
||||
|
), |
||||
|
migrations.DeleteModel( |
||||
|
name="Legislatura", |
||||
|
), |
||||
|
] |
@ -0,0 +1,18 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-05-29 13:43 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0005_remove_coligacao_legislatura_and_more'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='partido', |
||||
|
name='sigla', |
||||
|
field=models.CharField(max_length=20, verbose_name='sigla'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,17 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-06-18 13:23 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0006_alter_partido_sigla'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='parlamentar', |
||||
|
options={'ordering': ('presidente', 'nome_completo'), 'verbose_name_plural': 'parlamentares'}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,18 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-06-20 23:56 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0007_alter_parlamentar_options'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='parlamentar', |
||||
|
name='foto', |
||||
|
field=models.ImageField(blank=True, height_field='foto_altura', upload_to='parlamentares/parlamentar/fotos', width_field='foto_largura'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,38 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-06-24 01:39 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0008_alter_parlamentar_foto'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='parlamentar', |
||||
|
name='ano_eleicao', |
||||
|
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Ano de eleição'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='parlamentar', |
||||
|
name='flag_importa', |
||||
|
field=models.CharField(blank=True, default='', editable=False, max_length=1), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='parlamentar', |
||||
|
name='sequencial_tse', |
||||
|
field=models.CharField(blank=True, default='', editable=False, max_length=20, verbose_name='Sequencial TSE'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='parlamentar', |
||||
|
name='status_mandato', |
||||
|
field=models.CharField(choices=[('E', 'Em exercício'), ('S', 'Suplente'), ('I', 'Inativo')], default='E', max_length=1, verbose_name='status do mandato'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='parlamentar', |
||||
|
name='foto', |
||||
|
field=models.ImageField(blank=True, height_field='foto_altura', max_length=200, upload_to='parlamentares/parlamentar/fotos', width_field='foto_largura'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,17 @@ |
|||||
|
# Generated by Django 4.0.4 on 2022-06-29 02:10 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('parlamentares', '0009_parlamentar_ano_eleicao_parlamentar_flag_importa_and_more'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='parlamentar', |
||||
|
options={'ordering': ('status_mandato', 'presidente', 'nome_completo'), 'verbose_name_plural': 'parlamentares'}, |
||||
|
), |
||||
|
] |
@ -1,219 +1,104 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
from django.db import models |
from django.db import models |
||||
from django.utils.translation import gettext as _ |
from django.utils.translation import gettext as _ |
||||
|
|
||||
from sigi.apps.casas.models import Orgao |
from sigi.apps.casas.models import Orgao |
||||
|
|
||||
|
|
||||
class Partido(models.Model): |
class Partido(models.Model): |
||||
nome = models.CharField(max_length=50) |
nome = models.CharField(_("nome"), max_length=50) |
||||
sigla = models.CharField(max_length=10) |
sigla = models.CharField(_("sigla"), max_length=20) |
||||
|
legenda = models.PositiveIntegerField(_("nº da legenda"), default=0) |
||||
|
|
||||
class Meta: |
class Meta: |
||||
ordering = ("nome",) |
ordering = ("nome",) |
||||
|
|
||||
def __unicode__(self): |
def __str__(self): |
||||
return "%s (%s)" % (unicode(self.nome), unicode(self.sigla)) |
return _(f"{self.sigla} - {self.nome}") |
||||
|
|
||||
|
|
||||
class Parlamentar(models.Model): |
class Parlamentar(models.Model): |
||||
SEXO_CHOICES = ( |
STATUS_CHOICE = ( |
||||
("M", _("Masculino")), |
("E", _("Em exercício")), |
||||
("F", _("Feminino")), |
("S", _("Suplente")), |
||||
|
("I", _("Inativo")), |
||||
|
) |
||||
|
casa_legislativa = models.ForeignKey( |
||||
|
Orgao, verbose_name=_("casa legislativa"), on_delete=models.CASCADE |
||||
|
) |
||||
|
partido = models.ForeignKey( |
||||
|
Partido, verbose_name=_("partido"), on_delete=models.CASCADE |
||||
|
) |
||||
|
ano_eleicao = models.PositiveIntegerField( |
||||
|
_("Ano de eleição"), blank=True, null=True |
||||
|
) |
||||
|
status_mandato = models.CharField( |
||||
|
_("status do mandato"), max_length=1, choices=STATUS_CHOICE, default="E" |
||||
) |
) |
||||
|
presidente = models.BooleanField(_("presidente"), default=False) |
||||
nome_completo = models.CharField(max_length=128) |
nome_completo = models.CharField(max_length=128) |
||||
nome_parlamentar = models.CharField(max_length=35, blank=True) |
nome_parlamentar = models.CharField(max_length=35, blank=True) |
||||
foto = models.ImageField( |
foto = models.ImageField( |
||||
upload_to="fotos/parlamentares", |
max_length=200, |
||||
|
upload_to="parlamentares/parlamentar/fotos", |
||||
width_field="foto_largura", |
width_field="foto_largura", |
||||
height_field="foto_altura", |
height_field="foto_altura", |
||||
blank=True, |
blank=True, |
||||
) |
) |
||||
foto_largura = models.SmallIntegerField(editable=False, null=True) |
foto_largura = models.SmallIntegerField(editable=False, null=True) |
||||
foto_altura = models.SmallIntegerField(editable=False, null=True) |
foto_altura = models.SmallIntegerField(editable=False, null=True) |
||||
sexo = models.CharField( |
|
||||
max_length=1, |
|
||||
choices=SEXO_CHOICES, |
|
||||
) |
|
||||
data_nascimento = models.DateField( |
data_nascimento = models.DateField( |
||||
_("data de nascimento"), |
_("data de nascimento"), |
||||
blank=True, |
blank=True, |
||||
null=True, |
null=True, |
||||
) |
) |
||||
email = models.EmailField(_("e-mail"), blank=True) |
cpf = models.CharField(_("CPF"), max_length=20, blank=True) |
||||
pagina_web = models.URLField(_("página web"), blank=True) |
identidade = models.CharField( |
||||
|
_("Identidade (RG)"), |
||||
class Meta: |
max_length=30, |
||||
ordering = ("nome_completo",) |
|
||||
verbose_name_plural = _("parlamentares") |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
if self.nome_parlamentar: |
|
||||
return self.nome_parlamentar |
|
||||
return self.nome_completo |
|
||||
|
|
||||
|
|
||||
class Mandato(models.Model): |
|
||||
SUPLENCIA_CHOICES = ( |
|
||||
("T", _("Titular")), |
|
||||
("S", _("Suplente")), |
|
||||
) |
|
||||
parlamentar = models.ForeignKey(Parlamentar, on_delete=models.CASCADE) |
|
||||
legislatura = models.ForeignKey( |
|
||||
"parlamentares.Legislatura", on_delete=models.CASCADE |
|
||||
) |
|
||||
partido = models.ForeignKey(Partido, on_delete=models.CASCADE) |
|
||||
cargo = models.ForeignKey("parlamentares.Cargo", on_delete=models.PROTECT) |
|
||||
inicio_mandato = models.DateField(_("início de mandato")) |
|
||||
fim_mandato = models.DateField(_("fim de mandato")) |
|
||||
is_afastado = models.BooleanField( |
|
||||
_("afastado"), |
|
||||
default=False, |
|
||||
help_text=_("Marque caso parlamentar não esteja ativo."), |
|
||||
) |
|
||||
|
|
||||
# suplencia = models.CharField( |
|
||||
# _('suplência'), |
|
||||
# max_length=1, |
|
||||
# choices=SUPLENCIA_CHOICES, |
|
||||
# ) |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
return str(self.id) |
|
||||
|
|
||||
|
|
||||
class Legislatura(models.Model): |
|
||||
casa_legislativa = models.ForeignKey(Orgao, on_delete=models.CASCADE) |
|
||||
numero = models.PositiveSmallIntegerField(_("número legislatura")) |
|
||||
data_inicio = models.DateField(_("início")) |
|
||||
data_fim = models.DateField(_("fim")) |
|
||||
data_eleicao = models.DateField(_("data da eleição")) |
|
||||
total_parlamentares = models.PositiveIntegerField( |
|
||||
_("Total de parlamentares") |
|
||||
) |
|
||||
|
|
||||
casa_legislativa.convenio_uf_filter = True |
|
||||
casa_legislativa.convenio_cl_tipo_filter = True |
|
||||
|
|
||||
class Meta: |
|
||||
unique_together = ("casa_legislativa", "numero") |
|
||||
ordering = ["casa_legislativa__municipio__uf__sigla", "-data_inicio"] |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
return _( |
|
||||
"%(number)sª legislatura da %(parliament)s (%(initial_year)s-%(final_year)s)" |
|
||||
) % dict( |
|
||||
number=self.numero, |
|
||||
parliament=self.casa_legislativa.__unicode__(), |
|
||||
initial_year=self.data_inicio.year, |
|
||||
final_year=self.data_fim.year, |
|
||||
) |
|
||||
|
|
||||
|
|
||||
class Coligacao(models.Model): |
|
||||
nome = models.CharField(max_length=50) |
|
||||
legislatura = models.ForeignKey(Legislatura, on_delete=models.CASCADE) |
|
||||
numero_votos = models.PositiveIntegerField( |
|
||||
_("número de votos"), |
|
||||
blank=True, |
blank=True, |
||||
null=True, |
help_text=_("Informe o RG e o órgão emissor."), |
||||
) |
) |
||||
|
telefones = models.CharField( |
||||
class Meta: |
_("telefones"), max_length=250, null=True, blank=True |
||||
ordering = ("legislatura", "nome") |
|
||||
verbose_name = _("coligação") |
|
||||
verbose_name_plural = _("coligações") |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
return self.nome |
|
||||
|
|
||||
|
|
||||
class ComposicaoColigacao(models.Model): |
|
||||
coligacao = models.ForeignKey( |
|
||||
Coligacao, on_delete=models.CASCADE, verbose_name=_("coligação") |
|
||||
) |
|
||||
partido = models.ForeignKey( |
|
||||
"parlamentares.Partido", on_delete=models.CASCADE |
|
||||
) |
) |
||||
|
email = models.EmailField(_("e-mail"), blank=True) |
||||
class Meta: |
redes_sociais = models.TextField( |
||||
verbose_name = _("composição da coligação") |
_("redes sociais"), help_text=_("Colocar um por linha"), blank=True |
||||
verbose_name_plural = _("composições das coligações") |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
return str(self.id) |
|
||||
|
|
||||
|
|
||||
class SessaoLegislativa(models.Model): |
|
||||
SESSAO_CHOICES = ( |
|
||||
("O", _("Ordinária")), |
|
||||
("E", _("Extraordinária")), |
|
||||
) |
|
||||
numero = models.PositiveSmallIntegerField( |
|
||||
_("número da sessão"), unique=True |
|
||||
) |
) |
||||
mesa_diretora = models.ForeignKey( |
ult_alteracao = models.DateTimeField( |
||||
"MesaDiretora", |
_("última alteração"), |
||||
on_delete=models.PROTECT, |
null=True, |
||||
verbose_name=_("Mesa Diretora"), |
blank=True, |
||||
|
editable=True, |
||||
|
auto_now=True, |
||||
) |
) |
||||
legislatura = models.ForeignKey(Legislatura, on_delete=models.CASCADE) |
observacoes = models.TextField(_("observações"), blank=True) |
||||
tipo = models.CharField(max_length=1, choices=SESSAO_CHOICES, default="O") |
sequencial_tse = models.CharField( |
||||
data_inicio = models.DateField(_("início")) |
_("Sequencial TSE"), |
||||
data_fim = models.DateField(_("fim")) |
max_length=20, |
||||
data_inicio_intervalo = models.DateField( |
blank=True, |
||||
_("início de intervalo"), blank=True, null=True |
default="", |
||||
|
editable=False, |
||||
) |
) |
||||
data_fim_intervalo = models.DateField( |
flag_importa = models.CharField( |
||||
_("fim de intervalo"), blank=True, null=True |
max_length=1, blank=True, default="", editable=False |
||||
) |
) |
||||
|
|
||||
class Meta: |
class Meta: |
||||
ordering = ("legislatura", "numero") |
ordering = ( |
||||
verbose_name = _("Sessão Legislativa") |
"status_mandato", |
||||
verbose_name_plural = _("Sessões Legislativas") |
"presidente", |
||||
|
"nome_completo", |
||||
def __unicode__(self): |
) |
||||
return str(self.numero) |
verbose_name_plural = _("parlamentares") |
||||
|
|
||||
|
|
||||
class MesaDiretora(models.Model): |
|
||||
casa_legislativa = models.ForeignKey( |
|
||||
"casas.Orgao", |
|
||||
on_delete=models.CASCADE, |
|
||||
verbose_name=_("Casa Legislativa"), |
|
||||
) |
|
||||
|
|
||||
class Meta: |
|
||||
verbose_name = _("Mesa Diretora") |
|
||||
verbose_name_plural = _("Mesas Diretoras") |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
return _("Mesa Diretora da %s") % unicode(self.casa_legislativa) |
|
||||
|
|
||||
|
|
||||
class Cargo(models.Model): |
|
||||
descricao = models.CharField(_("descrição"), max_length=30) |
|
||||
|
|
||||
class Meta: |
|
||||
ordering = ("descricao",) |
|
||||
|
|
||||
def __unicode__(self): |
|
||||
return self.descricao |
|
||||
|
|
||||
|
|
||||
class MembroMesaDiretora(models.Model): |
|
||||
parlamentar = models.ForeignKey( |
|
||||
"parlamentares.Parlamentar", on_delete=models.CASCADE |
|
||||
) |
|
||||
cargo = models.ForeignKey(Cargo, on_delete=models.PROTECT) |
|
||||
mesa_diretora = models.ForeignKey(MesaDiretora, on_delete=models.CASCADE) |
|
||||
|
|
||||
class Meta: |
def __str__(self): |
||||
ordering = ("parlamentar",) |
if self.nome_parlamentar: |
||||
unique_together = ("cargo", "mesa_diretora") |
return self.nome_parlamentar |
||||
verbose_name = _("membro de Mesa Diretora") |
return self.nome_completo |
||||
verbose_name_plural = _("membros de Mesa Diretora") |
|
||||
|
|
||||
def __unicode__(self): |
def save(self, *args, **kwargs): |
||||
return "%s (%s)" % (unicode(self.parlamentar), unicode(self.cargo)) |
if self.presidente: |
||||
|
self.casa_legislativa.parlamentar_set.filter( |
||||
|
presidente=True |
||||
|
).update(presidente=False) |
||||
|
return super().save(*args, **kwargs) |
||||
|
@ -0,0 +1,11 @@ |
|||||
|
{% extends "admin/cart/change_list_cart_export.html" %} |
||||
|
{% load admin_urls i18n %} |
||||
|
|
||||
|
{% block object-tools-items %} |
||||
|
<li> |
||||
|
<a class="btn-floating tooltipped waves-effect waves-light" href="{% url opts|admin_urlname:'import' %}{{cl.get_query_string}}" data-position="left" data-tooltip="{% trans "Importar dados do TSE" %}"> |
||||
|
<i class="material-icons">file_upload</i> |
||||
|
</a> |
||||
|
</li> |
||||
|
{{ block.super }} |
||||
|
{% endblock %} |
@ -1 +0,0 @@ |
|||||
{% extends "change_list_with_cart.html" %} |
|
@ -0,0 +1,94 @@ |
|||||
|
{% extends "admin/base_site.html" %} |
||||
|
{% load i18n admin_urls %} |
||||
|
|
||||
|
{% block extrastyle %} |
||||
|
{{ block.super }} |
||||
|
<style> |
||||
|
#content { |
||||
|
display: block; |
||||
|
} |
||||
|
.submit-row>a { |
||||
|
color: #fff; |
||||
|
} |
||||
|
</style> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block breadcrumbs %}{% endblock %} |
||||
|
{% block content_title %} |
||||
|
<h4>{% trans "Importar dados do TSE" %}</h4> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<form method="post" enctype="multipart/form-data"> |
||||
|
{% csrf_token %} |
||||
|
<div class="container"> |
||||
|
{% if last_result.exists %} |
||||
|
<div class="breadcrumbs"> |
||||
|
<a href="{{ MEDIA_URL }}parlamentares/parlamentar/import/result.html" target="_blank"> |
||||
|
<i class="material-icons left">visibility</i> |
||||
|
{% trans "Visualizar o resultado da última importação" %} |
||||
|
</a> |
||||
|
</div> |
||||
|
{% endif %} |
||||
|
{{ form }} |
||||
|
<div class="submit-row"> |
||||
|
<button class="btn waves-effect waves-light" type="submit" name="import"> |
||||
|
<i class="material-icons left">done</i> |
||||
|
{% trans "Agendar importação" %} |
||||
|
</button> |
||||
|
<a class="btn waves-effect waves-light" href="{% url opts|admin_urlname:'changelist' %}"> |
||||
|
<i class="material-icons left">navigate_before</i> |
||||
|
{% trans "Voltar" %} |
||||
|
</a> |
||||
|
</div> |
||||
|
</form> |
||||
|
<div class="container"> |
||||
|
<h6>{% trans "ATENÇÃO" %}</h6> |
||||
|
<ul class="collection"> |
||||
|
<li class="collection-item"> |
||||
|
{% blocktrans %} |
||||
|
A importação é um processo demorado, principalmente se o arquivo for |
||||
|
muito grande. Por isso a importação não será realizada imediatamente |
||||
|
agora, mas de forma assíncrona. Quando o sistema concluir o processo de |
||||
|
importação, um e-mail com um resumo dos resultados será enviado para |
||||
|
você e para os administradores do SIGI.{% endblocktrans %} |
||||
|
</li> |
||||
|
{% if last_result.exists %} |
||||
|
<li class="collection-item"> |
||||
|
{% blocktrans %} |
||||
|
O resumo dos resultados da última importação realizada pelo sistema |
||||
|
pode ser{% endblocktrans %} |
||||
|
<a href="{{ MEDIA_URL }}parlamentares/parlamentar/import/result.html" target="_blank"> |
||||
|
{% trans "visualizado aqui" %} |
||||
|
</a> |
||||
|
</li> |
||||
|
{% endif %} |
||||
|
<li class="collection-item"> |
||||
|
{% trans "Os arquivos de resultados das eleiçoes podem ser encontrados no" %} |
||||
|
<a href="https://dadosabertos.tse.jus.br/" target="_blank">{% trans "Portal de dados abertos do TSE" %}</a> |
||||
|
</li> |
||||
|
<li class="collection-item"> |
||||
|
{% blocktrans %} |
||||
|
Os arquivos no formato CSV devem ser |
||||
|
<em>EXTRAÍDOS</em> |
||||
|
do ZIP baixado do TSE. |
||||
|
Não envie o ZIP inteiro, pois o SIGI não consegue descompactar. |
||||
|
Já os arquivos que contêm as fotos |
||||
|
<em>DEVEM</em> |
||||
|
ser enviados em formato ZIP.{% endblocktrans %} |
||||
|
</li> |
||||
|
<li class="collection-item"> |
||||
|
{% blocktrans %} |
||||
|
O CSV do TSE vem com os caracteres codificados em 'LATIN 1' (iso-8859-1). |
||||
|
O SIGI trabalha com codificação UTF-8. O SIGI tenta fazer a conversão |
||||
|
se você selecionar LATIN 1, mas o ideal é que você faça a conversão |
||||
|
manualmente antes de importar. Para isso, pode usar o Excel ou |
||||
|
Libreoffice-calc.{% endblocktrans %} |
||||
|
<blockquote> |
||||
|
{% trans "Se estiver usando Linux, comande:" %} |
||||
|
<br> |
||||
|
<code>iconv -f iso8859-1 -t utf-8 arquivo_tse.csv -o arquivo_convertido.csv</code> |
||||
|
</blockquote> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
{% endblock %} |
@ -0,0 +1,36 @@ |
|||||
|
{% load i18n %} |
||||
|
<!DOCTYPE html> |
||||
|
{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %} |
||||
|
<html |
||||
|
lang="{{ LANGUAGE_CODE|default:" |
||||
|
en-us |
||||
|
" }}" |
||||
|
dir="{{ LANGUAGE_BIDI|yesno:'rtl,ltr,auto' }}" |
||||
|
> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
</head> |
||||
|
<body> |
||||
|
<h4>Resultado da importação de dados de parlamentares</h4> |
||||
|
<table> |
||||
|
{% for key, value in json_data.items %} |
||||
|
<tr> |
||||
|
<th>{{ key }}</th> |
||||
|
<td>{{ value }}</td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</table> |
||||
|
<br> |
||||
|
<ul> |
||||
|
{% for row in result %} |
||||
|
{% if row|first == '*' %} |
||||
|
<li> |
||||
|
<h5>{{ row }}</h5> |
||||
|
</li> |
||||
|
{% else %} |
||||
|
<li>{{ row }}</li> |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
</ul> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,37 @@ |
|||||
|
{% extends "admin/base_site.html" %} |
||||
|
{% load i18n admin_urls %} |
||||
|
|
||||
|
{% block extrastyle %} |
||||
|
{{ block.super }} |
||||
|
<style> |
||||
|
#content { |
||||
|
display: block; |
||||
|
} |
||||
|
.submit-row>a { |
||||
|
color: #fff; |
||||
|
} |
||||
|
</style> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block breadcrumbs %}{% endblock %} |
||||
|
{% block content_title %} |
||||
|
<h4>{% trans "Importação de dados do TSE agendada" %}</h4> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<div class="container"> |
||||
|
<p> |
||||
|
{% blocktrans %} |
||||
|
A importação foi agendada com sucesso e o arquivo do TSE |
||||
|
será processado em breve. Ao concluir a importação, o SIGI |
||||
|
enviará um e-mail para você e para os administradores do |
||||
|
sistema, avisando dos resultados do processo. |
||||
|
{% endblocktrans %} |
||||
|
</p> |
||||
|
</div> |
||||
|
<div class="submit-row"> |
||||
|
<a class="btn waves-effect waves-light" href="{% url opts|admin_urlname:'changelist' %}"> |
||||
|
<i class="material-icons left">navigate_before</i> |
||||
|
{% trans "Voltar" %} |
||||
|
</a> |
||||
|
</div> |
||||
|
{% endblock %} |
@ -1,26 +1,10 @@ |
|||||
# coding: utf-8 |
from django.urls import path, include |
||||
from django.conf.urls import patterns, url |
from sigi.apps.parlamentares import views |
||||
|
|
||||
urlpatterns = patterns( |
urlpatterns = [ |
||||
"sigi.apps.parlamentares.views", |
path( |
||||
# Reports labels parlamentares |
"parlamentar_json/<int:casa_id>/", |
||||
url(r"^parlamentar/labels/$", "labels_report", name="labels-report-all"), |
views.parlamentar_json, |
||||
url( |
name="parlamentar-json", |
||||
r"^parlamentar/(?P<id>\w+)/labels/$", |
|
||||
"labels_report", |
|
||||
name="labels-report-id", |
|
||||
), |
), |
||||
# Carrinho |
] |
||||
url( |
|
||||
r"^parlamentar/carrinho/$", |
|
||||
"visualizar_carrinho", |
|
||||
name="visualizar-carrinho", |
|
||||
), |
|
||||
url( |
|
||||
r"^parlamentar/carrinho/deleta_itens_carrinho$", |
|
||||
"deleta_itens_carrinho", |
|
||||
name="deleta-itens-carrinho", |
|
||||
), |
|
||||
# A view excluir_carrinho n existe ainda. |
|
||||
# url(r'^parlamentar/carrinho/exluir_carrinho$', 'excluir_carrinho', name='excluir-carrinho'), |
|
||||
) |
|
||||
|
Loading…
Reference in new issue