Browse Source

Merge branch 'stable/2.2'

unstable/3.0
Sesostris Vieira 4 years ago
parent
commit
ae57e58bd0
  1. 1
      .gitignore
  2. 36
      etc/migracao/migra.py
  3. 2
      locale/en/LC_MESSAGES/django.po
  4. 24
      moodlerouter.py
  5. 12
      scripts/importa_pesquisa.py
  6. 5592
      scripts/setgerentes/dados_gerentes.py
  7. 16
      scripts/setgerentes/set_gerentes.py
  8. 4
      scripts/verificacao_arquivos_faltando_media.py
  9. 388
      sigi/apps/casas/admin.py
  10. 39
      sigi/apps/casas/forms.py
  11. 36
      sigi/apps/casas/management/commands/importa_gerentes.py
  12. 26
      sigi/apps/casas/migrations/0003_auto_20200207_0919.py
  13. 20
      sigi/apps/casas/migrations/0004_auto_20201015_0810.py
  14. 21
      sigi/apps/casas/migrations/0005_casalegislativa_gerentes_interlegis.py
  15. 18
      sigi/apps/casas/migrations/0006_remove_casalegislativa_gerente_contas.py
  16. 128
      sigi/apps/casas/migrations/0007_auto_20201016_1632.py
  17. 45
      sigi/apps/casas/migrations/0008_auto_20210218_1007.py
  18. 20
      sigi/apps/casas/migrations/0009_auto_20210406_1055.py
  19. 18
      sigi/apps/casas/migrations/0010_auto_20210406_1101.py
  20. 18
      sigi/apps/casas/migrations/0011_auto_20210406_1135.py
  21. 18
      sigi/apps/casas/migrations/0012_auto_20210406_1420.py
  22. 18
      sigi/apps/casas/migrations/0013_auto_20210406_1428.py
  23. 31
      sigi/apps/casas/migrations/0014_auto_20210406_1945.py
  24. 28
      sigi/apps/casas/migrations/0015_auto_20210407_0801.py
  25. 20
      sigi/apps/casas/migrations/0016_auto_20210407_1559.py
  26. 45
      sigi/apps/casas/migrations/0017_auto_20210416_0841.py
  27. 20
      sigi/apps/casas/migrations/0018_orgao_sigla.py
  28. 26
      sigi/apps/casas/migrations/0019_auto_20210501_1058.py
  29. 18
      sigi/apps/casas/migrations/0020_auto_20210611_0946.py
  30. 291
      sigi/apps/casas/models.py
  31. 406
      sigi/apps/casas/reports.py
  32. 6
      sigi/apps/casas/templates/admin/casas/convenios_inline.html
  33. 164
      sigi/apps/casas/templates/admin/casas/ocorrencia_inline.html
  34. 6
      sigi/apps/casas/templates/casas/carrinho.html
  35. 57
      sigi/apps/casas/templates/casas/gerentes_interlegis.html
  36. 143
      sigi/apps/casas/templates/casas/gerentes_interlegis_pdf.html
  37. 81
      sigi/apps/casas/templates/casas/importar.html
  38. 18
      sigi/apps/casas/templates/casas/importar_result.html
  39. 2
      sigi/apps/casas/templates/casas/lista_casas_carteira_snippet.html
  40. 46
      sigi/apps/casas/templates/casas/portfolio.html
  41. 237
      sigi/apps/casas/templates/casas/report_complete_pdf.html
  42. 132
      sigi/apps/casas/templates/casas/report_pdf.html
  43. 4
      sigi/apps/casas/test_casas.py
  44. 47
      sigi/apps/casas/urls.py
  45. 624
      sigi/apps/casas/views.py
  46. 39
      sigi/apps/contatos/migrations/0003_auto_20210416_0841.py
  47. 24
      sigi/apps/contatos/migrations/0004_auto_20210611_0946.py
  48. 54
      sigi/apps/contatos/models.py
  49. 116
      sigi/apps/convenios/admin.py
  50. 0
      sigi/apps/convenios/management/__init__.py
  51. 0
      sigi/apps/convenios/management/commands/__init__.py
  52. 26
      sigi/apps/convenios/management/commands/duracao_act.py
  53. 20
      sigi/apps/convenios/migrations/0002_convenio_duracao.py
  54. 21
      sigi/apps/convenios/migrations/0003_auto_20210406_1945.py
  55. 78
      sigi/apps/convenios/migrations/0004_auto_20210407_1928.py
  56. 26
      sigi/apps/convenios/migrations/0005_auto_20210409_0842.py
  57. 33
      sigi/apps/convenios/migrations/0006_auto_20210416_0841.py
  58. 40
      sigi/apps/convenios/migrations/0007_auto_20210416_0918.py
  59. 34
      sigi/apps/convenios/migrations/0008_auto_20210422_1907.py
  60. 18
      sigi/apps/convenios/migrations/0009_auto_20210611_0946.py
  61. 255
      sigi/apps/convenios/models.py
  62. 36
      sigi/apps/convenios/templates/convenios/carrinho.html
  63. 68
      sigi/apps/convenios/templates/convenios/change_list.html
  64. 43
      sigi/apps/convenios/views.py
  65. 10
      sigi/apps/diagnosticos/forms.py
  66. 0
      sigi/apps/diagnosticos/management/__init__.py
  67. 0
      sigi/apps/diagnosticos/management/commands/__init__.py
  68. 275
      sigi/apps/diagnosticos/management/commands/ls_export.py
  69. 22
      sigi/apps/diagnosticos/migrations/0002_auto_20170407_1024.py
  70. 20
      sigi/apps/diagnosticos/migrations/0003_auto_20201101_2240.py
  71. 21
      sigi/apps/diagnosticos/migrations/0004_auto_20210406_1945.py
  72. 51
      sigi/apps/diagnosticos/migrations/0005_auto_20210416_0841.py
  73. 67
      sigi/apps/diagnosticos/models.py
  74. 6
      sigi/apps/diagnosticos/views.py
  75. 42
      sigi/apps/eventos/admin.py
  76. 18
      sigi/apps/eventos/migrations/0004_remove_evento_curso_moodle_id.py
  77. 27
      sigi/apps/eventos/migrations/0005_auto_20210406_1945.py
  78. 57
      sigi/apps/eventos/migrations/0006_auto_20210416_0841.py
  79. 38
      sigi/apps/eventos/migrations/0007_auto_20210417_0744.py
  80. 111
      sigi/apps/eventos/models.py
  81. 1
      sigi/apps/eventos/templates/admin/eventos/change_list.html
  82. 63
      sigi/apps/eventos/templates/eventos/carrinho.html
  83. 9
      sigi/apps/eventos/urls.py
  84. 166
      sigi/apps/eventos/views.py
  85. 6
      sigi/apps/financeiro/models.py
  86. 2
      sigi/apps/home/templates/home/sem_convenio.html
  87. 170
      sigi/apps/home/templatetags/menu_conf.yaml
  88. 59
      sigi/apps/home/views.py
  89. 21
      sigi/apps/inventario/migrations/0002_auto_20210406_1945.py
  90. 39
      sigi/apps/inventario/migrations/0003_auto_20210416_0841.py
  91. 20
      sigi/apps/inventario/models.py
  92. 3
      sigi/apps/mdl/admin.py
  93. 6007
      sigi/apps/mdl/base_models.py
  94. 116
      sigi/apps/mdl/migrations/0001_initial.py
  95. 360
      sigi/apps/mdl/models.py
  96. 3
      sigi/apps/mdl/views.py
  97. 21
      sigi/apps/metas/migrations/0002_auto_20210406_1945.py
  98. 21
      sigi/apps/metas/models.py
  99. 58
      sigi/apps/metas/static/metas/css/openmap.css
  100. 93
      sigi/apps/metas/templates/metas/lista_casas.html

1
.gitignore

@ -44,6 +44,7 @@ db.*
.project
.pydevproject
.settings
.vscode/
.vagrant
sigi/settings/prod.py

36
etc/migracao/migra.py

@ -60,7 +60,7 @@ def migra_assembleias(filename):
reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True)
header = reader.next()
tipo_casa = TipoCasaLegislativa.objects.filter(sigla='AL').get()
tipo_casa = TipoOrgao.objects.filter(sigla='AL').get()
for line in reader:
uf = UnidadeFederativa.objects.get(sigla=line[UF_COL])
@ -71,7 +71,7 @@ def migra_assembleias(filename):
bairro = aux_end[1].replace(' ', '', 1)
else:
bairro = ''
casa = CasaLegislativa(
casa = Orgao(
municipio=municipio,
nome=line[NOME_COL],
tipo=tipo_casa,
@ -85,7 +85,7 @@ def migra_assembleias(filename):
telefone=line[FONE_1_COL]
)
if line[UF_COL] == 'DF':
casa.tipo = TipoCasaLegislativa.objects.filter(sigla='CT').get()
casa.tipo = TipoOrgao.objects.filter(sigla='CT').get()
casa.save()
if line[FONE_2_COL]:
@ -141,7 +141,7 @@ def migra_casas(filename):
reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True)
header = reader.next()
tipo_casa = TipoCasaLegislativa.objects.filter(sigla='CM').get()
tipo_casa = TipoOrgao.objects.filter(sigla='CM').get()
linenum = 1
for line in reader:
@ -160,7 +160,7 @@ def migra_casas(filename):
bairro = ''
if(aux_end.__len__() > 1):
bairro = aux_end[1].replace(' ', '', 1)
casa = CasaLegislativa(
casa = Orgao(
municipio=municipio,
nome='Câmara Municipal de ' + line[NOME_COL],
tipo=tipo_casa,
@ -214,11 +214,11 @@ def migra_cnpj(filename):
linenum += 1
try:
casa = CasaLegislativa.objects.get(municipio__codigo_tse=line[COD_TSE_COL])
except CasaLegislativa.DoesNotExist:
casa = Orgao.objects.get(municipio__codigo_tse=line[COD_TSE_COL])
except Orgao.DoesNotExist:
print ERROR_MSG_1 % (filename, linenum)
continue
except CasaLegislativa.MultipleObjectsReturned:
except Orgao.MultipleObjectsReturned:
print ERROR_MSG_1 % (filename, linenum)
continue
except ValueError:
@ -271,12 +271,12 @@ def migra_convenios_casas(filename):
linenum += 1
try:
casa = CasaLegislativa.objects.get(municipio__codigo_ibge=line[COD_IBGE_COL])
except CasaLegislativa.DoesNotExist:
casa = Orgao.objects.get(municipio__codigo_ibge=line[COD_IBGE_COL])
except Orgao.DoesNotExist:
print "Erro ao inserir convênio. Casa não existe"
print ERROR_MSG_1 % (filename, linenum)
continue
except CasaLegislativa.MultipleObjectsReturned:
except Orgao.MultipleObjectsReturned:
print ERROR_MSG_1 % (filename, linenum)
continue
except ValueError:
@ -368,16 +368,16 @@ def migra_convenios_assembleias(filename):
reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True)
header = reader.next()
linenum = 1
tipo_casa = TipoCasaLegislativa.objects.filter(sigla='AL').get()
tipo_casa = TipoOrgao.objects.filter(sigla='AL').get()
for line in reader:
linenum += 1
try:
assembleia = CasaLegislativa.objects.get(municipio__uf__sigla=line[SIGLA_COL], tipo=tipo_casa)
except CasaLegislativa.DoesNotExist:
assembleia = Orgao.objects.get(municipio__uf__sigla=line[SIGLA_COL], tipo=tipo_casa)
except Orgao.DoesNotExist:
print ERROR_MSG_1 % (filename, linenum)
continue
except CasaLegislativa.MultipleObjectsReturned:
except Orgao.MultipleObjectsReturned:
print ERROR_MSG_1 % (filename, linenum)
continue
except ValueError:
@ -417,11 +417,11 @@ def popula():
projeto3 = Projeto(sigla='PML', nome='Projeto Modernização Legislativo')
projeto3.save()
tipo1 = TipoCasaLegislativa(sigla='CM', nome='Câmara Municipal')
tipo1 = TipoOrgao(sigla='CM', nome='Câmara Municipal')
tipo1.save()
tipo2 = TipoCasaLegislativa(sigla='AL', nome='Assembléia Legislativa')
tipo2 = TipoOrgao(sigla='AL', nome='Assembléia Legislativa')
tipo2.save()
tipo3 = TipoCasaLegislativa(sigla='CT', nome='Câmara Distrital')
tipo3 = TipoOrgao(sigla='CT', nome='Câmara Distrital')
tipo3.save()

2
locale/en/LC_MESSAGES/django.po

@ -901,7 +901,7 @@ msgid "Data de Aceite"
msgstr ""
#: sigi/apps/convenios/reports.py:143
msgid "CasaLegislativa: "
msgid "Orgao: "
msgstr ""
#: sigi/apps/convenios/reports.py:250

24
moodlerouter.py

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
class MoodleRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'mdl':
return 'moodle'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'mdl':
return 'moodle'
return None
def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == 'mdl' and obj2._meta.app_label == 'mdl':
return True
return None
def allow_migrate(self, db, model):
if model._meta.app_label == 'mdl':
return False
return None

12
scripts/importa_pesquisa.py

@ -26,11 +26,11 @@ import csv
import urlparse
from datetime import datetime
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.servidores.models import Servidor
def importa(file_list):
''' Este script importa dados de um arquivo CSV e dá carga no model casas.CasaLegislativa
''' Este script importa dados de um arquivo CSV e dá carga no model casas.Orgao
O arquivo CSV esperado tem um cabeçalho de campos na primeira linha, com os seguintes campos:
@ -74,11 +74,11 @@ def importa(file_list):
cidade = uf_cidade[5:]
if tem_portal.lower() == 'não':
inclusao = CasaLegislativa.INCLUSAO_DIGITAL_CHOICES[1][0]
inclusao = Orgao.INCLUSAO_DIGITAL_CHOICES[1][0]
elif pmodelo.lower() == 'não':
inclusao = CasaLegislativa.INCLUSAO_DIGITAL_CHOICES[3][0]
inclusao = Orgao.INCLUSAO_DIGITAL_CHOICES[3][0]
else:
inclusao = CasaLegislativa.INCLUSAO_DIGITAL_CHOICES[2][0]
inclusao = Orgao.INCLUSAO_DIGITAL_CHOICES[2][0]
l = url.splitlines()
url = ''
@ -102,7 +102,7 @@ def importa(file_list):
else:
servidor = servidor[0]
casa = CasaLegislativa.objects.filter(tipo_id=1, municipio__uf__sigla=uf, municipio__nome__iexact=cidade)
casa = Orgao.objects.filter(tipo_id=1, municipio__uf__sigla=uf, municipio__nome__iexact=cidade)
cc = casa.count()
if cc == 0:
row.append('Municipio nao foi encontrado')

5592
scripts/setgerentes/dados_gerentes.py

File diff suppressed because it is too large

16
scripts/setgerentes/set_gerentes.py

@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
from dados_gerentes import atrib, gerentes
from sigi.apps.casas.models import CasaLegislativa
def salvar():
for cod, abrev_gerente in atrib:
casas = CasaLegislativa.objects.filter(municipio__codigo_ibge=cod, tipo__sigla='CM')
if not casas:
print '############################# SEM CASA: ', cod
elif len(casas) > 1:
print '############################# VÁRIAS CASAS: ', cod, casas
else:
[c] = casas
c.gerente_contas = gerentes[abrev_gerente]
c.save()

4
scripts/verificacao_arquivos_faltando_media.py

@ -9,7 +9,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from terminaltables import AsciiTable
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.convenios.models import Anexo as AnexoConvenios
from sigi.apps.diagnosticos.models import Anexo as AnexoDiagnosticos
from sigi.apps.ocorrencias.models import Anexo as AnexoOcorrencias
@ -31,7 +31,7 @@ def url(obj):
# IMAGENS FALTANDO
imagens_faltando = [[u"SITUAÇÃO DO ARQUIVO DA FOTO ", "URL", "OBJETO"]]
for cl in (CasaLegislativa, Parlamentar, Servidor):
for cl in (Orgao, Parlamentar, Servidor):
for a in cl.objects.all():
if a.foto:
imagens_faltando.append([

388
sigi/apps/casas/admin.py

@ -1,24 +1,26 @@
# -*- coding: utf-8 -*-
from django.core.urlresolvers import reverse
from django.contrib import admin
from django.contrib.contenttypes import generic
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils.translation import ugettext as _
from image_cropping import ImageCroppingMixin
from sigi.apps.casas.forms import CasaLegislativaForm
from sigi.apps.casas.models import CasaLegislativa, Presidente, Funcionario, TipoCasaLegislativa
from sigi.apps.casas.forms import OrgaoForm
from sigi.apps.casas.models import Orgao, Presidente, Funcionario, TipoOrgao
from sigi.apps.casas.views import report_complete, labels_report, export_csv, \
labels_report_sem_presidente, report, \
adicionar_casas_carrinho
from sigi.apps.contatos.models import Telefone
from sigi.apps.convenios.models import Convenio
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.inventario.models import Bem
from sigi.apps.convenios.models import Convenio, Projeto
# from sigi.apps.diagnosticos.models import Diagnostico
# from sigi.apps.inventario.models import Bem
from sigi.apps.metas.models import PlanoDiretor
from sigi.apps.ocorrencias.models import Ocorrencia
from sigi.apps.parlamentares.models import Legislatura
from sigi.apps.servicos.models import Servico
# from sigi.apps.parlamentares.models import Legislatura
from sigi.apps.servicos.models import Servico, TipoServico
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils import queryset_ascii
from sigi.apps.utils.base_admin import BaseModelAdmin
@ -32,58 +34,118 @@ class TelefonesInline(generic.GenericTabularInline):
class PresidenteInline(admin.StackedInline):
model = Presidente
exclude = ['cargo', 'funcao']
fields = ('nome', 'sexo', 'data_nascimento', 'nota', 'email',
'tempo_de_servico', 'ult_alteracao', 'endereco', 'municipio',
'bairro', 'cep', 'redes_sociais',)
raw_id_fields = ('municipio',)
# fieldsets = ((None, {
# 'fields': (
# ('nome', 'sexo', 'data_nascimento'),
# ('nota', 'email', 'tempo_de_servico'),
# ('ult_alteracao',),
# )
# }),)
# exclude = ['setor', 'cargo', 'funcao']
readonly_fields = ('ult_alteracao',)
extra = 1
max_num = 1
inlines = (TelefonesInline)
verbose_name_plural = _(u'Presidente')
class FuncionariosInline(admin.StackedInline):
model = Funcionario
fieldsets = ((None, {
'fields': (('nome', 'sexo', 'nota', 'email'), ('cargo', 'funcao', 'setor', 'tempo_de_servico'), 'ult_alteracao')
}),)
fields = ('nome', 'sexo', 'data_nascimento', 'nota', 'email', 'cargo',
'funcao', 'setor', 'tempo_de_servico', 'ult_alteracao',
'endereco', 'municipio', 'bairro', 'cep', 'redes_sociais',
'desativado', 'observacoes')
raw_id_fields = ('municipio',)
# fieldsets = ((None, {
# 'fields': (
# ('nome', 'sexo', 'data_nascimento'),
# ('nota', 'email'),
# ('cargo', 'funcao', 'setor'),
# ('tempo_de_servico', 'ult_alteracao'),
# ('endereco', 'municipio'),
# ('bairro', 'cep'),
# ('redes_sociais'),
# ('desativado', 'observacoes'),
# )
# }),)
readonly_fields = ('ult_alteracao',)
extra = 1
inlines = (TelefonesInline,)
def get_queryset(self, request):
return self.model.objects.exclude(cargo=_(u"Presidente"))
return (self.model.objects.exclude(
cargo='Presidente').exclude(desativado=True)
)
class ConveniosInline(admin.StackedInline):
class ConveniosInline(admin.TabularInline):
model = Convenio
fieldsets = (
(None, {'fields': (('link_convenio', 'num_processo_sf', 'num_convenio', 'projeto', 'observacao'),
('data_adesao', 'data_retorno_assinatura', 'data_termo_aceite', 'data_pub_diario', 'data_devolucao_via', 'data_postagem_correio'),
(None, {'fields': (
('link_sigad', 'status_convenio', 'num_convenio',
'projeto', 'observacao'),
('data_adesao', 'data_retorno_assinatura', 'data_termo_aceite',
'data_pub_diario', 'data_devolucao_via', 'data_postagem_correio'),
('data_devolucao_sem_assinatura', 'data_retorno_sem_assinatura',),
('get_tramitacoes', 'get_anexos', 'get_equipamentos',),
)}
),
('get_anexos',),
('link_convenio',),
)}),
)
readonly_fields = ['get_tramitacoes', 'get_anexos', 'get_equipamentos', 'link_convenio', ]
readonly_fields = ['link_convenio', 'link_sigad', 'status_convenio',
'num_convenio', 'projeto', 'observacao', 'data_adesao',
'data_retorno_assinatura', 'data_termo_aceite',
'data_pub_diario', 'data_devolucao_via',
'data_postagem_correio', 'data_devolucao_sem_assinatura',
'data_retorno_sem_assinatura', 'get_anexos']
extra = 0
can_delete = False
template = 'admin/casas/convenios_inline.html'
def get_tramitacoes(self, obj):
return '<br/>'.join([t.__unicode__() for t in obj.tramitacao_set.all()])
get_tramitacoes.short_description = _(u'Tramitações')
get_tramitacoes.allow_tags = True
def has_add_permission(self, request):
return False
# def get_tramitacoes(self, obj):
# return '<br/>'.join([t.__unicode__() for t in obj.tramitacao_set.all()])
#
# get_tramitacoes.short_description = _(u'Tramitações')
# get_tramitacoes.allow_tags = True
#
def get_anexos(self, obj):
return '<br/>'.join(['<a href="%s" target="_blank">%s</a>' % (a.arquivo.url, a.__unicode__()) for a in obj.anexo_set.all()])
get_anexos.short_description = _(u'Anexos')
get_anexos.allow_tags = True
#
# def get_equipamentos(self, obj):
# return '<br/>'.join([e.__unicode__() for e in obj.equipamentoprevisto_set.all()])
#
# get_equipamentos.short_description = _(u'Equipamentos previstos')
# get_equipamentos.allow_tags = True
def status_convenio(self, obj):
if obj.pk is None:
return ""
status = obj.get_status()
if status in [u"Vencido", u"Desistência", u"Cancelado"]:
label = r"danger"
elif status == u"Vigente":
label = r"success"
elif status == u"Pendente":
label = r"warning"
else:
label = r"info"
return u'<p class="label label-{label}">{status}</p>'.format(label=label, status=status)
status_convenio.short_description = _(u"Status do convênio")
status_convenio.allow_tags = True
def get_equipamentos(self, obj):
return '<br/>'.join([e.__unicode__() for e in obj.equipamentoprevisto_set.all()])
get_equipamentos.short_description = _(u'Equipamentos previstos')
get_equipamentos.allow_tags = True
def link_convenio(self, obj):
if obj.pk is None:
return ""
from django.core.urlresolvers import reverse
url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.module_name), args=[obj.pk])
url = url + '?_popup=1'
return """<input id="edit_convenio-%s" type="hidden"/>
@ -94,64 +156,77 @@ class ConveniosInline(admin.StackedInline):
link_convenio.short_description = _(u'Editar convenio')
link_convenio.allow_tags = True
class LegislaturaInline(admin.TabularInline):
model = Legislatura
fields = ['numero', 'data_inicio', 'data_fim', 'data_eleicao', 'total_parlamentares', 'link_parlamentares', ]
readonly_fields = ['link_parlamentares', ]
def link_parlamentares(self, obj):
if obj.pk is None:
return ""
from django.core.urlresolvers import reverse
url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.module_name), args=[obj.pk])
url = url + '?_popup=1'
return """<input id="edit_legislatura-%s" type="hidden"/>
<a id="lookup_edit_legislatura-%s" href="%s" class="changelink" onclick="return showRelatedObjectLookupPopup(this)">
Editar
</a>""" % (obj.pk, obj.pk, url)
link_parlamentares.short_description = _(u'Parlamentares')
link_parlamentares.allow_tags = True
class DiagnosticoInline(admin.TabularInline):
model = Diagnostico
fields = ['data_visita_inicio', 'data_visita_fim', 'publicado', 'data_publicacao', 'responsavel', 'link_diagnostico', ]
readonly_fields = ['data_visita_inicio', 'data_visita_fim', 'publicado', 'data_publicacao', 'responsavel', 'link_diagnostico', ]
extra = 0
max_num = 0
can_delete = False
def link_diagnostico(self, obj):
def link_sigad(self, obj):
if obj.pk is None:
return ""
url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.module_name), args=["%s.pdf" % obj.pk])
return """<input id="edit_diagnostico-%s" type="hidden"/>
<a id="lookup_edit_diagnostico-%s" href="%s" class="button" target="_blank">
Abrir PDF
</a>""" % (obj.pk, obj.pk, url)
link_diagnostico.short_description = _(u'Ver PDF')
link_diagnostico.allow_tags = True
class BemInline(admin.TabularInline):
model = Bem
return obj.get_sigad_url()
link_sigad.short_description = _("Processo no Senado")
link_sigad.allow_tags = True
# class LegislaturaInline(admin.TabularInline):
# model = Legislatura
# fields = ['numero', 'data_inicio', 'data_fim', 'data_eleicao', 'total_parlamentares', 'link_parlamentares', ]
# readonly_fields = ['link_parlamentares', ]
# def link_parlamentares(self, obj):
# if obj.pk is None:
# return ""
# from django.core.urlresolvers import reverse
# url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.module_name), args=[obj.pk])
# url = url + '?_popup=1'
# return """<input id="edit_legislatura-%s" type="hidden"/>
# <a id="lookup_edit_legislatura-%s" href="%s" class="changelink" onclick="return showRelatedObjectLookupPopup(this)">
# Editar
# </a>""" % (obj.pk, obj.pk, url)
# link_parlamentares.short_description = _(u'Parlamentares')
# link_parlamentares.allow_tags = True
# class DiagnosticoInline(admin.TabularInline):
# model = Diagnostico
# fields = ['data_visita_inicio', 'data_visita_fim', 'publicado', 'data_publicacao', 'responsavel', 'link_diagnostico', ]
# readonly_fields = ['data_visita_inicio', 'data_visita_fim', 'publicado', 'data_publicacao', 'responsavel', 'link_diagnostico', ]
# extra = 0
# max_num = 0
# can_delete = False
# def link_diagnostico(self, obj):
# if obj.pk is None:
# return ""
# url = reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.module_name), args=["%s.pdf" % obj.pk])
# return """<input id="edit_diagnostico-%s" type="hidden"/>
# <a id="lookup_edit_diagnostico-%s" href="%s" class="button" target="_blank">
# Abrir PDF
# </a>""" % (obj.pk, obj.pk, url)
# link_diagnostico.short_description = _(u'Ver PDF')
# link_diagnostico.allow_tags = True
# class BemInline(admin.TabularInline):
# model = Bem
class ServicoInline(admin.TabularInline):
model = Servico
fields = ['url', 'contato_tecnico', 'contato_administrativo', 'hospedagem_interlegis', 'data_ativacao', 'data_alteracao', 'data_desativacao']
readonly_fields = ['url', 'contato_tecnico', 'contato_administrativo', 'hospedagem_interlegis', 'data_ativacao', 'data_alteracao', 'data_desativacao']
fields = ('link_url', 'contato_tecnico', 'contato_administrativo',
'hospedagem_interlegis', 'data_ativacao', 'data_alteracao',
'data_desativacao')
readonly_fields = ['link_url', 'contato_tecnico', 'contato_administrativo',
'hospedagem_interlegis', 'data_ativacao',
'data_alteracao', 'data_desativacao']
extra = 0
max_num = 0
can_delete = False
def link_url(self, servico):
if servico.data_desativacao is not None:
return servico.url
return u'<a href="{url}" target="_blank">{url}</a>'.format(url=servico.url)
link_url.short_description = _(u'URL do serviço')
link_url.allow_tags = True
class PlanoDiretorInline(admin.TabularInline):
model = PlanoDiretor
# class PlanoDiretorInline(admin.TabularInline):
# model = PlanoDiretor
class OcorrenciaInline(admin.TabularInline):
model = Ocorrencia
@ -160,7 +235,7 @@ class OcorrenciaInline(admin.TabularInline):
extra = 0
max_num = 0
can_delete = False
template = 'casas/ocorrencia_inline.html'
template = 'admin/casas/ocorrencia_inline.html'
def link_editar(self, obj):
if obj.pk is None:
@ -173,80 +248,171 @@ class OcorrenciaInline(admin.TabularInline):
link_editar.short_description = _(u'Editar')
link_editar.allow_tags = True
class GerentesContasFilter(admin.filters.RelatedFieldListFilter):
class GerentesInterlegisFilter(admin.filters.RelatedFieldListFilter):
def __init__(self, *args, **kwargs):
super(GerentesContasFilter, self).__init__(*args, **kwargs)
super(GerentesInterlegisFilter, self).__init__(*args, **kwargs)
gerentes = Servidor.objects.filter(casas_que_gerencia__isnull=False).order_by('nome_completo').distinct()
self.lookup_choices = [(x.id, x) for x in gerentes]
class CasaLegislativaAdmin(ImageCroppingMixin, BaseModelAdmin):
form = CasaLegislativaForm
class ConvenioFilter(admin.SimpleListFilter):
title = _(u"Tipo de convênio")
parameter_name = 'convenio'
def lookups(self, request, model_admin):
return (
('SC', _(u"Sem nenhum convênio")),
('CC', _(u"Com algum convênio"))
) + tuple([(p.pk, p.sigla) for p in Projeto.objects.all()])
def queryset(self, request, queryset):
if self.value() is not None:
if self.value() == 'SC':
queryset = queryset.filter(convenio=None)
elif self.value() == 'CC':
queryset = queryset.exclude(convenio=None)
else:
queryset = queryset.filter(convenio__projeto_id=self.value())
return queryset.distinct('municipio__uf__nome', 'nome')
class ServicoFilter(admin.SimpleListFilter):
title = _(u"Serviço")
parameter_name = 'servico'
def lookups(self, request, model_admin):
return (
('SS', _(u"Sem nenhum serviço")),
('CS', _(u"Com algum serviço")),
('CH', _(u"Com algum serviço de hospedagem")),
('CR', _(u"Apenas serviço de registro")),
) + tuple([(p.pk, p.nome) for p in TipoServico.objects.all()])
def queryset(self, request, queryset):
if self.value() is not None:
if self.value() == 'SS':
queryset = queryset.filter(servico=None)
elif self.value() == 'CS':
queryset = queryset.exclude(servico=None).filter(
servico__data_desativacao__isnull=True)
elif self.value() == 'CR':
queryset = queryset.exclude(servico__tipo_servico__modo='H') \
.exclude(servico=None)
elif self.value() == 'CH':
queryset = queryset.filter(
servico__tipo_servico__modo='H',
servico__data_desativacao__isnull=True
)
else:
queryset = queryset.filter(
servico__tipo_servico_id=self.value()
)
return queryset.distinct('municipio__uf__nome', 'nome')
@admin.register(Orgao)
class OrgaoAdmin(ImageCroppingMixin, BaseModelAdmin):
form = OrgaoForm
actions = ['adicionar_casas', ]
inlines = (TelefonesInline, PresidenteInline, FuncionariosInline, ConveniosInline, LegislaturaInline,
DiagnosticoInline, BemInline, ServicoInline, PlanoDiretorInline, OcorrenciaInline, )
list_display = ('nome', 'municipio', 'gerente_contas', 'get_convenios')
list_display_links = ('nome',)
list_filter = ('tipo', ('gerente_contas', GerentesContasFilter), 'municipio__uf__nome', 'convenio__projeto',
inlines = (TelefonesInline, PresidenteInline, FuncionariosInline,
ConveniosInline, ServicoInline, OcorrenciaInline,)
list_display = ('id', 'sigla', 'nome', 'get_uf', 'get_gerentes', 'get_convenios',
'get_servicos')
list_display_links = ('sigla', 'nome',)
list_filter = ('tipo', ('gerentes_interlegis', GerentesInterlegisFilter),
'municipio__uf__nome', ConvenioFilter, ServicoFilter,
'inclusao_digital',)
ordering = ('nome', 'municipio__uf')
queyrset = queryset_ascii
ordering = ('municipio__uf__nome', 'nome')
queryset = queryset_ascii
fieldsets = (
(None, {
'fields': ('tipo', 'nome', 'cnpj', 'num_parlamentares', 'gerente_contas')
'fields': ('tipo', 'nome', 'sigla', 'cnpj', 'num_parlamentares',
'gerentes_interlegis')
}),
(_(u'Endereço'), {
'fields': ('data_instalacao', 'logradouro', 'bairro',
'municipio', 'cep', 'ult_alt_endereco'),
}),
(_(u'Presença na Internet'), {
'fields': ('inclusao_digital', 'data_levantamento', 'pesquisador', 'pagina_web', 'email', 'obs_pesquisa',)
'fields': ('inclusao_digital', 'data_levantamento', 'pesquisador',
'pagina_web', 'email', 'obs_pesquisa',)
}),
(_(u'Outras informações'), {
'fields': ('observacoes', 'foto', 'recorte'),
'fields': ('observacoes', 'horario_funcionamento', 'foto',
'recorte'),
}),
)
raw_id_fields = ('municipio',)
readonly_fields = ['num_parlamentares', ]
search_fields = ('search_text', 'cnpj', 'bairro', 'logradouro',
readonly_fields = ['num_parlamentares', 'gerentes_interlegis',]
search_fields = ('search_text', 'sigla', 'cnpj', 'bairro', 'logradouro',
'cep', 'municipio__nome', 'municipio__uf__nome',
'municipio__codigo_ibge', 'pagina_web', 'observacoes')
def get_uf(self, obj):
return obj.municipio.uf.nome
get_uf.short_description = _(u'Unidade da Federação')
get_uf.admin_order_field = 'municipio__uf__nome'
def get_gerentes(self, obj):
return obj.lista_gerentes()
get_gerentes.short_description = _(u'Gerente Interlegis')
get_gerentes.allow_tags = True
def get_convenios(self, obj):
return '<ul>' + ''.join(['<li>%s</li>' % c.__unicode__() for c in obj.convenio_set.all()]) + '</ul>'
return '<ul>' + ''.join(['<li>%s</li>' % c.__unicode__()
for c in obj.convenio_set.all()]) + '</ul>'
get_convenios.short_description = _(u'Convênios')
get_convenios.allow_tags = True
def get_servicos(self, obj):
return u'<ul>' + u''.join(
[u'<li><a href="{url}" target="_blank">{servico}</a></li>'.format(
url=s.url, servico=s.__unicode__()) for s in
obj.servico_set.filter(data_desativacao__isnull=True)]) + u'</ul>'
get_servicos.short_description = _(u'Serviços')
get_servicos.allow_tags = True
def changelist_view(self, request, extra_context=None):
return super(CasaLegislativaAdmin, self).changelist_view(
return super(OrgaoAdmin, self).changelist_view(
request,
extra_context={'query_str': '?' + request.META['QUERY_STRING']}
)
def lookup_allowed(self, lookup, value):
return super(CasaLegislativaAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['municipio__uf__codigo_ibge__exact', 'convenio__projeto__id__exact']
return (super(OrgaoAdmin, self).lookup_allowed(lookup, value) or
lookup in ['tipo__legislativo__exact',
'tipo__sigla__exact',
'municipio__uf__codigo_ibge__exact',
'convenio__projeto__id__exact'])
def etiqueta(self, request, queryset):
return labels_report(request, queryset=queryset)
etiqueta.short_description = _(u"Gerar etiqueta(s) da(s) casa(s) selecionada(s)")
etiqueta.short_description = _(u"Gerar etiqueta(s) da(s) casa(s) "
u"selecionada(s)")
def etiqueta_sem_presidente(self, request, queryset):
return labels_report_sem_presidente(request, queryset=queryset)
etiqueta_sem_presidente.short_description = _(u"Gerar etiqueta(s) sem presidente da(s) casa(s) selecionada(s)")
etiqueta_sem_presidente.short_description = _(u"Gerar etiqueta(s) sem "
u"presidente da(s) casa(s) "
u"selecionada(s)")
def relatorio(self, request, queryset):
return report(request, queryset=queryset)
relatorio.short_description = _(u"Exportar a(s) casa(s) selecionada(s) para PDF")
relatorio.short_description = _(u"Exportar a(s) casa(s) selecionada(s) "
u"para PDF")
def relatorio_completo(self, request, queryset):
return report_complete(request, queryset=queryset)
relatorio_completo.short_description = _(u"Gerar relatório completo da(s) casa(s) selecionada(s)")
relatorio_completo.short_description = _(u"Gerar relatório completo da(s) "
u"casa(s) selecionada(s)")
def relatorio_csv(self, request, queryset):
return export_csv(request)
relatorio_csv.short_description = _(u"Exportar casa(s) selecionada(s) para CSV")
relatorio_csv.short_description = _(u"Exportar casa(s) selecionada(s) "
u"para CSV")
def adicionar_casas(self, request, queryset):
if 'carrinho_casas' in request.session:
@ -258,18 +424,20 @@ class CasaLegislativaAdmin(ImageCroppingMixin, BaseModelAdmin):
q2 = len(request.session['carrinho_casas'])
quant = q2 - q1
if quant:
self.message_user(request, str(q2 - q1) + " " + _(u"Casas Legislativas adicionadas no carrinho"))
self.message_user(request, str(q2 - q1) + " " +
_(u"Casas Legislativas adicionadas no carrinho"))
else:
self.message_user(request, _(u"As Casas Legislativas selecionadas já foram adicionadas anteriormente"))
self.message_user(request, _(u"As Casas Legislativas selecionadas "
u"já foram adicionadas anteriormente"))
return HttpResponseRedirect('.')
adicionar_casas.short_description = _(u"Armazenar casas no carrinho para exportar")
adicionar_casas.short_description = _(u"Armazenar casas no carrinho para "
u"exportar")
def get_actions(self, request):
actions = super(CasaLegislativaAdmin, self).get_actions(request)
actions = super(OrgaoAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
admin.site.register(CasaLegislativa, CasaLegislativaAdmin)
admin.site.register(TipoCasaLegislativa)
admin.site.register(TipoOrgao)

39
sigi/apps/casas/forms.py

@ -3,11 +3,17 @@ from django import forms
from django.utils.translation import ugettext as _
from localflavor.br.forms import BRZipCodeField
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.servidores.models import Servidor
class AtualizaCasaForm(forms.Form):
arquivo = forms.FileField(
required=True,
label=_(u"arquivo a importar"),
help_text=_(u"Envie um arquivo no formato CSV"),
)
class CasaLegislativaForm(forms.ModelForm):
class OrgaoForm(forms.ModelForm):
# cnpj = BRCNPJField(
# label=_(u'CNPJ'),
# required=False,
@ -16,12 +22,33 @@ class CasaLegislativaForm(forms.ModelForm):
cep = BRZipCodeField(label=_(u'CEP'), help_text=_(u'Formato') + ': <em>XXXXX-XXX</em>.')
class Meta:
model = CasaLegislativa
model = Orgao
fields = '__all__'
# def clean(self):
# cleaned_data = super(OrgaoForm, self).clean()
# tipo = cleaned_data.get('tipo')
# municipio = cleaned_data.get('municipio')
# if tipo.legislativo:
# if Orgao.objects.filter(tipo=tipo)
class PortfolioForm(forms.Form):
gerente_contas = forms.ModelChoiceField(queryset=Servidor.objects.all(), label=_(u"Atribuir casas para"))
ACAO_CHOICES = (
('ADD', _(u"Adicionar")),
('DEL', _(u"Remover"))
)
acao = forms.ChoiceField(
label=_(u"Ação"),
choices=ACAO_CHOICES,
initial='ADD',
widget=forms.RadioSelect
)
gerente = forms.ModelChoiceField(
queryset=Servidor.objects.all(),
label=_(u"Atribuir para")
)
def __init__(self, label=_(u"Atribuir casas para"), *args, **kwargs):
# O label precisa ser trocado dependendo da região que se está visualizando
def __init__(self, label=_(u"Atribuir para"), *args, **kwargs):
super(PortfolioForm, self).__init__(*args, **kwargs)
self.fields['gerente_contas'].label = label
self.fields['gerente'].label = label

36
sigi/apps/casas/management/commands/importa_gerentes.py

@ -25,7 +25,7 @@
import csv
import os
from django.core.management.base import BaseCommand, CommandError
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.servidores.models import Servidor
from sigi.apps.contatos.models import Municipio
@ -56,29 +56,43 @@ class Command(BaseCommand):
if not self.campos.issubset(reader.fieldnames):
raise CommandError(u"O arquivo não possui todos os campos obrigatórios")
CasaLegislativa.objects.update(gerente_contas=None)
Orgao.gerentes_interlegis.through.objects.all().delete()
erros = 0
for reg in reader:
try:
municipio = Municipio.objects.get(codigo_ibge=reg['cod_municipio'])
municipio = Municipio.objects.get(
codigo_ibge=reg['cod_municipio']
)
except Municipio.DoesNotExist:
self.stdout.write(u"(Linha %s): não existe Município com código IBGE '%s'" %
(reader.line_num, reg['cod_municipio'],))
self.stdout.write(u"{linha}: não existe Município com "
u"código IBGE {ibge}'".format(
linha=reader.line_num,
ibge=reg['cod_municipio'])
)
erros = erros + 1
continue
try:
gerente = Servidor.objects.get(user__username=reg['user_id'])
gerente = Servidor.objects.get(
user__username=reg['user_id']
)
except Servidor.DoesNotExist:
self.stdout.write(u"(Linha %s): não existe Servidor com userid '%s'" %
(reader.line_num, reg['user_id'],))
self.stdout.write(u"({linha}): não existe Servidor com "
u"userid {userid}".format(
linha=reader.line_num,
userid=reg['user_id'])
)
erros = erros + 1
continue
for casa in municipio.casalegislativa_set.filter(tipo__sigla__in=['AL', 'CM']):
casa.gerente_contas = gerente
for casa in municipio.orgao_set.filter(
tipo__sigla__in=['AL', 'CM']):
casa.gerentes_interlegis.add(gerente)
casa.save()
self.stdout.write(u"Importação concluída. %s erros em %s linhas" % (erros, reader.line_num,))
self.stdout.write(u"Importação concluída. {erros} erros em {linhas}"
u" linhas".format(erros=erros,
linhas=reader.line_num)
)

26
sigi/apps/casas/migrations/0003_auto_20200207_0919.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0002_auto_20150710_1247'),
]
operations = [
migrations.AddField(
model_name='casalegislativa',
name='horario_funcionamento',
field=models.CharField(max_length=100, verbose_name='Hor\xe1rio de funcionamento da Casa Legislativa', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='data_nascimento',
field=models.DateField(null=True, verbose_name='Data de nascimento', blank=True),
preserve_default=True,
),
]

20
sigi/apps/casas/migrations/0004_auto_20201015_0810.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0003_auto_20200207_0919'),
]
operations = [
migrations.AlterField(
model_name='casalegislativa',
name='gerente_contas',
field=models.ForeignKey(related_name='casas_que_gerencia_old', verbose_name=b'Gerente de contas', blank=True, to='servidores.Servidor', null=True),
preserve_default=True,
),
]

21
sigi/apps/casas/migrations/0005_casalegislativa_gerentes_interlegis.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('servidores', '0001_initial'),
('casas', '0004_auto_20201015_0810'),
]
operations = [
migrations.AddField(
model_name='casalegislativa',
name='gerentes_interlegis',
field=models.ManyToManyField(related_name='casas_que_gerencia', verbose_name=b'Gerentes Interlegis', to='servidores.Servidor'),
preserve_default=True,
),
]

18
sigi/apps/casas/migrations/0006_remove_casalegislativa_gerente_contas.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0005_casalegislativa_gerentes_interlegis'),
]
operations = [
migrations.RemoveField(
model_name='casalegislativa',
name='gerente_contas',
),
]

128
sigi/apps/casas/migrations/0007_auto_20201016_1632.py

@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0006_remove_casalegislativa_gerente_contas'),
]
operations = [
migrations.AddField(
model_name='funcionario',
name='desativado',
field=models.BooleanField(default=False, verbose_name='Desativado'),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='observacoes',
field=models.TextField(verbose_name='Observa\xe7\xf5es', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='bairro',
field=models.CharField(max_length=100, verbose_name='Bairro', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='cep',
field=models.CharField(max_length=32, verbose_name='CEP'),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='codigo_interlegis',
field=models.CharField(max_length=3, verbose_name='C\xf3digo Interlegis', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='email',
field=models.EmailField(max_length=128, verbose_name='E-mail', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='foto',
field=models.ImageField(upload_to=b'imagens/casas', width_field=b'foto_largura', height_field=b'foto_altura', blank=True, verbose_name='Foto'),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='inclusao_digital',
field=models.CharField(default=b'NAO PESQUISADO', max_length=30, verbose_name='Inclus\xe3o digital', choices=[(b'NAO PESQUISADO', 'N\xe3o pesquisado'), (b'NAO POSSUI PORTAL', 'N\xe3o possui portal'), (b'PORTAL MODELO', 'Possui Portal Modelo'), (b'OUTRO PORTAL', 'Possui outro portal')]),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='logradouro',
field=models.CharField(help_text='Avenida, rua, pra\xe7a, jardim, parque...', max_length=100, verbose_name='Logradouro'),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='municipio',
field=models.ForeignKey(verbose_name='Munic\xedpio', to='contatos.Municipio'),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='nome',
field=models.CharField(help_text='Exemplo: <em>C\xe2mara Municipal de Pains</em>.', max_length=60, verbose_name='Nome'),
preserve_default=True,
),
migrations.AlterField(
model_name='casalegislativa',
name='pagina_web',
field=models.URLField(help_text='Exemplo: <em>http://www.camarapains.mg.gov.br</em>.', verbose_name='P\xe1gina web', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='cargo',
field=models.CharField(max_length=100, null=True, verbose_name='Cargo', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='nota',
field=models.CharField(max_length=70, null=True, verbose_name='Telefones', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='setor',
field=models.CharField(default=b'outros', max_length=100, verbose_name='Setor', choices=[(b'presidente', 'Presidente'), (b'contato_interlegis', 'Contato Interlegis'), (b'infraestrutura_fisica', 'Infraestrutura F\xedsica'), (b'estrutura_de_ti', 'Estrutura de TI'), (b'organizacao_do_processo_legislativo', 'Organiza\xe7\xe3o do Processo Legislativo'), (b'producao_legislativa', 'Produ\xe7\xe3o Legislativa'), (b'estrutura_de_comunicacao_social', 'Estrutura de Comunica\xe7\xe3o Social'), (b'estrutura_de_recursos_humanos', 'Estrutura de Recursos Humanos'), (b'gestao', 'Gest\xe3o'), (b'outros', 'Outros')]),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='sexo',
field=models.CharField(default=b'M', max_length=1, verbose_name='Sexo', choices=[(b'M', 'Masculino'), (b'F', 'Feminino')]),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='tempo_de_servico',
field=models.CharField(max_length=50, null=True, verbose_name='Tempo de servi\xe7o', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='tipocasalegislativa',
name='nome',
field=models.CharField(max_length=100, verbose_name='Nome'),
preserve_default=True,
),
migrations.AlterField(
model_name='tipocasalegislativa',
name='sigla',
field=models.CharField(max_length=5, verbose_name='Sigla'),
preserve_default=True,
),
]

45
sigi/apps/casas/migrations/0008_auto_20210218_1007.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contatos', '0002_auto_20151104_0810'),
('casas', '0007_auto_20201016_1632'),
]
operations = [
migrations.AddField(
model_name='funcionario',
name='bairro',
field=models.CharField(max_length=100, verbose_name='Bairro', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='cep',
field=models.CharField(max_length=10, verbose_name='CEP', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='endereco',
field=models.CharField(max_length=100, verbose_name='Endere\xe7o', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='municipio',
field=models.ForeignKey(verbose_name='Municipio', to='contatos.Municipio', null=True),
preserve_default=True,
),
migrations.AddField(
model_name='funcionario',
name='redes_sociais',
field=models.TextField(help_text='Colocar um por linha', verbose_name='Redes sociais', blank=True),
preserve_default=True,
),
]

20
sigi/apps/casas/migrations/0009_auto_20210406_1055.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0008_auto_20210218_1007'),
]
operations = [
migrations.AlterField(
model_name='funcionario',
name='municipio',
field=models.ForeignKey(verbose_name='Municipio', blank=True, to='contatos.Municipio', null=True),
preserve_default=True,
),
]

18
sigi/apps/casas/migrations/0010_auto_20210406_1101.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0009_auto_20210406_1055'),
]
operations = [
migrations.RenameModel(
old_name='TipoCasaLegislativa',
new_name='TipoOrgao',
),
]

18
sigi/apps/casas/migrations/0011_auto_20210406_1135.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0010_auto_20210406_1101'),
]
operations = [
migrations.AlterModelOptions(
name='tipoorgao',
options={'verbose_name': 'Tipo de \xf3rg\xe3o', 'verbose_name_plural': 'Tipos de \xf3rg\xe3o'},
),
]

18
sigi/apps/casas/migrations/0012_auto_20210406_1420.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0011_auto_20210406_1135'),
]
operations = [
migrations.AlterModelOptions(
name='tipoorgao',
options={},
),
]

18
sigi/apps/casas/migrations/0013_auto_20210406_1428.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0012_auto_20210406_1420'),
]
operations = [
migrations.AlterModelOptions(
name='tipoorgao',
options={'verbose_name': 'Tipo de \xf3rg\xe3o', 'verbose_name_plural': 'Tipos de \xf3rg\xe3o'},
),
]

31
sigi/apps/casas/migrations/0014_auto_20210406_1945.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import image_cropping.fields
import sigi.apps.utils
class Migration(migrations.Migration):
dependencies = [
# ('metas', '0002_auto_20210406_1945'),
('contatos', '0002_auto_20151104_0810'),
('servidores', '0001_initial'),
# ('parlamentares', '0002_auto_20210406_1945'),
# ('servicos', '0005_auto_20210406_1945'),
('servicos', '0004_delete_casaatendida'),
# ('inventario', '0002_auto_20210406_1945'),
# ('convenios', '0003_auto_20210406_1945'),
# ('ocorrencias', '0003_auto_20210406_1945'),
# ('diagnosticos', '0004_auto_20210406_1945'),
# ('eventos', '0005_auto_20210406_1945'),
('casas', '0013_auto_20210406_1428'),
]
operations = [
migrations.RenameModel(
old_name='CasaLegislativa',
new_name='Orgao',
),
]

28
sigi/apps/casas/migrations/0015_auto_20210407_0801.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0014_auto_20210406_1945'),
]
operations = [
migrations.AlterModelOptions(
name='orgao',
options={'ordering': ('nome',), 'verbose_name': '\xd3rg\xe3o', 'verbose_name_plural': '\xd3rg\xe3os'},
),
migrations.AddField(
model_name='tipoorgao',
name='legislativo',
field=models.BooleanField(default=False, verbose_name='Poder legislativo'),
preserve_default=True,
),
migrations.AlterUniqueTogether(
name='orgao',
unique_together=set([]),
),
]

20
sigi/apps/casas/migrations/0016_auto_20210407_1559.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0015_auto_20210407_0801'),
]
operations = [
migrations.AlterField(
model_name='orgao',
name='gerentes_interlegis',
field=models.ManyToManyField(related_name='casas_que_gerencia', verbose_name='Gerentes Interlegis', to='servidores.Servidor', blank=True),
preserve_default=True,
),
]

45
sigi/apps/casas/migrations/0017_auto_20210416_0841.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('casas', '0016_auto_20210407_1559'),
]
operations = [
migrations.AlterField(
model_name='funcionario',
name='casa_legislativa',
field=models.ForeignKey(verbose_name='\xf3rg\xe3o', to='casas.Orgao'),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='municipio',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='Municipio', blank=True, to='contatos.Municipio', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='orgao',
name='municipio',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Munic\xedpio', to='contatos.Municipio'),
preserve_default=True,
),
migrations.AlterField(
model_name='orgao',
name='pesquisador',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='Pesquisador', blank=True, to='servidores.Servidor', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='orgao',
name='tipo',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Tipo', to='casas.TipoOrgao'),
preserve_default=True,
),
]

20
sigi/apps/casas/migrations/0018_orgao_sigla.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0017_auto_20210416_0841'),
]
operations = [
migrations.AddField(
model_name='orgao',
name='sigla',
field=models.CharField(max_length=30, verbose_name='sigla do \xf3rg\xe3o', blank=True),
preserve_default=True,
),
]

26
sigi/apps/casas/migrations/0019_auto_20210501_1058.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0018_orgao_sigla'),
]
operations = [
migrations.AlterField(
model_name='funcionario',
name='email',
field=models.CharField(max_length=250, verbose_name='e-mail', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='funcionario',
name='nota',
field=models.CharField(max_length=250, null=True, verbose_name='Telefones', blank=True),
preserve_default=True,
),
]

18
sigi/apps/casas/migrations/0020_auto_20210611_0946.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('casas', '0019_auto_20210501_1058'),
]
operations = [
migrations.AlterModelOptions(
name='tipoorgao',
options={'ordering': ('nome',), 'verbose_name': 'Tipo de \xf3rg\xe3o', 'verbose_name_plural': 'Tipos de \xf3rg\xe3o'},
),
]

291
sigi/apps/casas/models.py

@ -1,108 +1,170 @@
# -*- coding: utf-8 -*-
from datetime import datetime
import random
from string import ascii_uppercase
from unicodedata import normalize
from datetime import datetime
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.contrib.contenttypes import generic
from django.db import models
from image_cropping import ImageRatioField
from sigi.apps.contatos.models import Municipio
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils import SearchField
class TipoCasaLegislativa(models.Model):
class TipoOrgao(models.Model):
""" Modelo para representar o tipo da Casa Legislativa
Geralmente: Câmara Municipal, Assembléia Legislativa,
Câmara Distrital ou Legislativo Federal
"""
sigla = models.CharField(
max_length=5
)
nome = models.CharField(
max_length=100
)
sigla = models.CharField(_(u"Sigla"), max_length=5)
nome = models.CharField(_(u"Nome"), max_length=100)
legislativo = models.BooleanField(_(u"Poder legislativo"), default=False)
class Meta:
ordering = ('nome',)
verbose_name = _(u"Tipo de órgão")
verbose_name_plural = _(u"Tipos de órgão")
def __unicode__(self):
return self.nome
class CasaLegislativa(models.Model):
class Orgao(models.Model):
""" Modelo para representar uma Casa Legislativa
"""
INCLUSAO_DIGITAL_CHOICES = (
('NAO PESQUISADO', u'Não pesquisado'),
('NAO POSSUI PORTAL', u'Não possui portal'),
('PORTAL MODELO', u'Possui Portal Modelo'),
('OUTRO PORTAL', u'Possui outro portal'),
('NAO PESQUISADO', _(u'Não pesquisado')),
('NAO POSSUI PORTAL', _(u'Não possui portal')),
('PORTAL MODELO', _(u'Possui Portal Modelo')),
('OUTRO PORTAL', _(u'Possui outro portal')),
)
nome = models.CharField(
_(u"Nome"),
max_length=60,
help_text='Exemplo: <em>Câmara Municipal de Pains</em>.'
help_text=_(u'Exemplo: <em>Câmara Municipal de Pains</em>.')
)
sigla = models.CharField(
_(u"sigla do órgão"),
max_length=30,
blank=True
)
# Guarda um campo para ser usado em buscas em caixa baixa e sem acento
search_text = SearchField(field_names=['nome'])
# search_text.projeto_filter = True
tipo = models.ForeignKey(TipoCasaLegislativa, verbose_name="Tipo")
cnpj = models.CharField('CNPJ', max_length=32, blank=True)
observacoes = models.TextField(u'observações', blank=True)
tipo = models.ForeignKey(
TipoOrgao,
on_delete=models.PROTECT,
verbose_name=_(u"Tipo")
)
cnpj = models.CharField(_(u"CNPJ"), max_length=32, blank=True)
observacoes = models.TextField(_(u'observações'), blank=True)
horario_funcionamento = models.CharField(
_(u"Horário de funcionamento da Casa Legislativa"),
max_length=100,
blank=True,
)
# num_parlamentares = models.PositiveIntegerField('Número de parlamentares')
codigo_interlegis = models.CharField('Código Interlegis', max_length=3, blank=True)
codigo_interlegis = models.CharField(
_(u'Código Interlegis'),
max_length=3,
blank=True
)
# codigo_interlegis.ts_filter = True
gerente_contas = models.ForeignKey(Servidor, verbose_name="Gerente de contas", null=True, blank=True, related_name='casas_que_gerencia')
gerentes_interlegis = models.ManyToManyField(
Servidor,
verbose_name=_(u"Gerentes Interlegis"),
related_name='casas_que_gerencia',
blank=True,
)
# Informações de contato
logradouro = models.CharField(
_(u"Logradouro"),
max_length=100,
help_text='Avenida, rua, praça, jardim, parque...'
help_text=_(u'Avenida, rua, praça, jardim, parque...')
)
bairro = models.CharField(max_length=100, blank=True)
bairro = models.CharField(_(u"Bairro"), max_length=100, blank=True)
municipio = models.ForeignKey(
'contatos.Municipio',
verbose_name='município'
on_delete=models.PROTECT,
verbose_name=_(u'Município')
)
# municipio.uf_filter = True
cep = models.CharField(max_length=32)
email = models.EmailField('e-mail', max_length=128, blank=True)
cep = models.CharField(_(u"CEP"), max_length=32)
email = models.EmailField(_(u'E-mail'), max_length=128, blank=True)
pagina_web = models.URLField(
u'página web',
help_text='Exemplo: <em>http://www.camarapains.mg.gov.br</em>.',
_(u'Página web'),
help_text=_(u'Exemplo: <em>http://www.camarapains.mg.gov.br</em>.'),
blank=True,
)
inclusao_digital = models.CharField(
_(u"Inclusão digital"),
max_length=30,
choices=INCLUSAO_DIGITAL_CHOICES,
default=INCLUSAO_DIGITAL_CHOICES[0][0]
)
data_levantamento = models.DateTimeField(
_(u"Data/hora da pesquisa"),
null=True,
blank=True
)
pesquisador = models.ForeignKey(
Servidor,
on_delete=models.SET_NULL,
verbose_name=_(u"Pesquisador"),
null=True,
blank=True
)
obs_pesquisa = models.TextField(
_(u"Observações do pesquisador"),
blank=True
)
ult_alt_endereco = models.DateTimeField(
_(u'Última alteração do endereço'),
null=True,
blank=True,
editable=True
)
inclusao_digital = models.CharField(max_length=30, choices=INCLUSAO_DIGITAL_CHOICES, default=INCLUSAO_DIGITAL_CHOICES[0][0])
data_levantamento = models.DateTimeField(u"Data/hora da pesquisa", null=True, blank=True)
pesquisador = models.ForeignKey(Servidor, verbose_name=u"Pesquisador", null=True, blank=True)
obs_pesquisa = models.TextField(u"Observações do pesquisador", blank=True)
ult_alt_endereco = models.DateTimeField(u'Última alteração do endereço', null=True, blank=True, editable=True)
telefones = generic.GenericRelation('contatos.Telefone')
foto = models.ImageField(
_(u"Foto"),
upload_to='imagens/casas',
width_field='foto_largura',
height_field='foto_altura',
blank=True
)
recorte = ImageRatioField('foto', '400x300', verbose_name="Recorte", )
recorte = ImageRatioField('foto', '400x300', verbose_name=_("Recorte"))
foto_largura = models.SmallIntegerField(editable=False, null=True)
foto_altura = models.SmallIntegerField(editable=False, null=True)
data_instalacao = models.DateField(u'Data de instalação da Casa Legislativa', null=True, blank=True)
data_instalacao = models.DateField(
_(u'Data de instalação da Casa Legislativa'),
null=True,
blank=True
)
class Meta:
ordering = ('nome',)
unique_together = ('municipio', 'tipo')
verbose_name = 'Casa Legislativa'
verbose_name_plural = 'Casas Legislativas'
verbose_name = _(u'Órgão')
verbose_name_plural = _(u'Órgãos')
def lista_gerentes(self, fmt='html'):
if not self.gerentes_interlegis.exists():
return ""
if fmt == 'html':
return u"<ul><li>"+u"</li><li>".join(
[g.nome_completo for g in self.gerentes_interlegis.all()])+\
u"</li></ul>"
else:
return u", ".join([g.nome_completo for g in
self.gerentes_interlegis.all()])
@property
def num_parlamentares(self):
@ -156,7 +218,7 @@ class CasaLegislativa(models.Model):
if codigo == '':
if self.tipo.sigla == 'AL': # Assembléias são tratadas a parte
codigo = 'A' + self.municipio.uf.sigla
if CasaLegislativa.objects.filter(codigo_interlegis=codigo).count() <= 0:
if Orgao.objects.filter(codigo_interlegis=codigo).count() <= 0:
# Só grava o código se ele for inédito
self.codigo_interlegis = codigo
self.save()
@ -189,7 +251,7 @@ class CasaLegislativa(models.Model):
cityName = cityName.replace(' ', '')
ultima = len(cityName)
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
while Orgao.objects.filter(codigo_interlegis=codigo). \
count() > 0 and ultima > 0:
codigo = codigo[:2] + cityName[ultima - 1: ultima]
ultima -= 1
@ -198,11 +260,11 @@ class CasaLegislativa(models.Model):
# não gerou um código único, então vamos compor o nome usando as
# três primeiras consoantes.
if CasaLegislativa.objects.filter(codigo_interlegis=codigo).count() > 0:
if Orgao.objects.filter(codigo_interlegis=codigo).count() > 0:
codigo_cons = cityName.replace('A', '').replace('E', '').\
replace('I', '').replace('O', '').replace('U', '')[:3]
if len(codigo_cons) == 3 and \
CasaLegislativa.objects.filter(codigo_interlegis=codigo).count() > 0:
Orgao.objects.filter(codigo_interlegis=codigo).count() > 0:
codigo = codigo_cons
# Se ainda não gerou um nome único, vamos colocar dígitos no
@ -210,7 +272,7 @@ class CasaLegislativa(models.Model):
i = 'A'
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
while Orgao.objects.filter(codigo_interlegis=codigo). \
count() > 0 and i <= 'Z':
codigo = codigo[:2] + str(i)
i = chr(ord(i) + 1)
@ -221,7 +283,7 @@ class CasaLegislativa(models.Model):
i = 0
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
while Orgao.objects.filter(codigo_interlegis=codigo). \
count() > 0 and i < 100:
codigo = random.choice(cityName) + random.choice(cityName) + \
random.choice(cityName)
@ -232,10 +294,8 @@ class CasaLegislativa(models.Model):
i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
count() > 0:
codigo = random.choice(i) + random.choice(i) + \
random.choice(i)
while Orgao.objects.filter(codigo_interlegis=codigo).count() > 0:
codigo = random.choice(i) + random.choice(i) + random.choice(i)
self.codigo_interlegis = codigo
self.save()
@ -245,11 +305,22 @@ class CasaLegislativa(models.Model):
def __unicode__(self):
return self.nome
def clean(self):
if (hasattr(self, 'tipo') and hasattr(self, 'municipio')
and self.tipo.legislativo):
if Orgao.objects.filter(
tipo=self.tipo,
municipio=self.municipio).exclude(pk=self.pk).exists():
raise ValidationError(
_(u"Já existe um(a) %(tipo)s em %(municipio)s"),
code='integrity',
params={'tipo': self.tipo, 'municipio': self.municipio})
def save(self, *args, **kwargs):
address_changed = False
if self.pk is not None:
original = CasaLegislativa.objects.get(pk=self.pk)
original = Orgao.objects.get(pk=self.pk)
if (self.logradouro != original.logradouro or
self.bairro != original.bairro or
self.municipio != original.municipio or
@ -261,7 +332,7 @@ class CasaLegislativa(models.Model):
if address_changed:
self.ult_alt_endereco = datetime.now()
return super(CasaLegislativa, self).save(*args, **kwargs)
return super(Orgao, self).save(*args, **kwargs)
class Funcionario(models.Model):
@ -271,40 +342,98 @@ class Funcionario(models.Model):
"""
SETOR_CHOICES = [
("presidente", "Presidente"),
("contato_interlegis", "Contato Interlegis"),
("infraestrutura_fisica", "Infraestrutura Física"),
("estrutura_de_ti", "Estrutura de TI"),
("organizacao_do_processo_legislativo", "Organização do Processo Legislativo"),
("producao_legislativa", "Produção Legislativa"),
("estrutura_de_comunicacao_social", "Estrutura de Comunicação Social"),
("estrutura_de_recursos_humanos", "Estrutura de Recursos Humanos"),
("gestao", "Gestão"),
("outros", "Outros"),
("presidente", _(u"Presidente")),
("contato_interlegis", _(u"Contato Interlegis")),
("infraestrutura_fisica", _(u"Infraestrutura Física")),
("estrutura_de_ti", _(u"Estrutura de TI")),
("organizacao_do_processo_legislativo",
_(u"Organização do Processo Legislativo")),
("producao_legislativa", _(u"Produção Legislativa")),
("estrutura_de_comunicacao_social",
_(u"Estrutura de Comunicação Social")),
("estrutura_de_recursos_humanos", _(u"Estrutura de Recursos Humanos")),
("gestao", _(u"Gestão")),
("outros", _(u"Outros")),
]
SEXO_CHOICES = [
("M", "Masculino"),
("F", "Feminino")
("M", _(u"Masculino")),
("F", _(u"Feminino"))
]
casa_legislativa = models.ForeignKey(CasaLegislativa)
nome = models.CharField('nome completo', max_length=60, blank=False)
casa_legislativa = models.ForeignKey(
Orgao,
on_delete=models.CASCADE,
verbose_name=_(u"órgão"),
)
nome = models.CharField(_(u'nome completo'), max_length=60, blank=False)
# nome.alphabetic_filter = True
sexo = models.CharField(max_length=1, choices=SEXO_CHOICES, default="M")
nota = models.CharField(max_length=70, null=True, blank=True)
email = models.CharField('e-mail', max_length=75, blank=True)
telefones = generic.GenericRelation('contatos.Telefone')
endereco = generic.GenericRelation('contatos.Endereco')
cargo = models.CharField(max_length=100, null=True, blank=True)
funcao = models.CharField(u'função', max_length=100, null=True, blank=True)
setor = models.CharField(max_length=100, choices=SETOR_CHOICES, default="outros")
tempo_de_servico = models.CharField(u'tempo de serviço', max_length=50, null=True, blank=True)
ult_alteracao = models.DateTimeField(u'Última alteração', null=True, blank=True, editable=True, auto_now=True)
sexo = models.CharField(
_(u"Sexo"),
max_length=1,
choices=SEXO_CHOICES,
default="M"
)
data_nascimento = models.DateField(
_(u"Data de nascimento"),
blank=True,
null=True
)
nota = models.CharField(
_(u"Telefones"),
max_length=250,
null=True,
blank=True
)
email = models.CharField(_(u'e-mail'), max_length=250, blank=True)
# endereco = generic.GenericRelation('contatos.Endereco')
endereco = models.CharField(_(u'Endereço'), max_length=100, blank=True)
municipio = models.ForeignKey(
Municipio,
on_delete=models.SET_NULL,
verbose_name=_(u'Municipio'),
null=True,
blank=True,
)
bairro = models.CharField(_(u'Bairro'), max_length=100, blank=True)
cep = models.CharField(_(u'CEP'), max_length=10, blank=True)
redes_sociais = models.TextField(
_(u'Redes sociais'),
help_text=_(u'Colocar um por linha'),
blank=True
)
cargo = models.CharField(_(u"Cargo"), max_length=100, null=True, blank=True)
funcao = models.CharField(
_(u'função'),
max_length=100,
null=True,
blank=True
)
setor = models.CharField(
_(u"Setor"),
max_length=100,
choices=SETOR_CHOICES,
default="outros"
)
tempo_de_servico = models.CharField(
_(u'Tempo de serviço'),
max_length=50,
null=True,
blank=True
)
ult_alteracao = models.DateTimeField(
_(u'Última alteração'),
null=True,
blank=True,
editable=True,
auto_now=True
)
desativado = models.BooleanField(_(u"Desativado"), default=False)
observacoes = models.TextField(_(u"Observações"), blank=True)
class Meta:
ordering = ('nome',)
verbose_name = 'contato da Casa Legislativa'
verbose_name_plural = 'contatos da Casa Legislativa'
verbose_name = _(u'contato da Casa Legislativa')
verbose_name_plural = _(u'contatos da Casa Legislativa')
def __unicode__(self):
return self.nome

406
sigi/apps/casas/reports.py

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
from django.templatetags.static import static
from django.utils.translation import ugettext as _
from geraldo import Report, DetailBand, Label, ObjectValue, ReportGroup, ReportBand, landscape, SubReport, BAND_WIDTH, SystemField
from geraldo.graphics import Image
from django.templatetags.static import static
from django.utils.translation import ugettext as _
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
@ -51,7 +52,7 @@ class CasasLegislativasLabels(Report):
Usage example::
>>> from geraldo.generators import PDFGenerator
>>> queryset = CasaLegislativa.objects.filter(municipio__uf__sigla='MG')
>>> queryset = Orgao.objects.filter(municipio__uf__sigla='MG')
>>> report = LabelsReport(queryset)
>>> report.generate_by(PDFGenerator, filename='./inline-detail-report.pdf')
@ -176,402 +177,3 @@ class CasasLegislativasLabelsSemPresidente(CasasLegislativasLabels):
display_inline=True,
default_style={'fontName': 'Helvetica', 'fontSize': self.tamanho_fonte})
class CasasLegislativasReport(ReportDefault):
title = _(u'Relatório de Casas Legislativas')
height = 80 * cm
page_size = landscape(A4)
class band_page_header(ReportDefault.band_page_header):
label_top = ReportDefault.band_page_header.label_top
label_left = [0.3, 1, 5.5, 11, 17, 22]
elements = list(ReportDefault.band_page_header.elements)
elements = [
Image(filename=static('img/logo-interlegis.jpg'),
left=23.5 * cm, right=1 * cm, top=0.1 * cm, bottom=1 * cm,
width=4.2 * cm, height=3 * cm,
),
Image(filename=static('img/logo-senado.png'),
left=1 * cm, right=1 * cm, top=0.1 * cm, bottom=1 * cm,
width=3 * cm, height=3 * cm,
),
Label(text=_(u"SENADO FEDERAL"), top=1 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 14, 'alignment': TA_CENTER}
),
Label(text=_(u"SINTER - Secretaria Especial do Interlegis"), top=1.5 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 13, 'alignment': TA_CENTER}
),
SystemField(
expression='%(report_title)s', top=2.5 * cm, left=0, width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold', 'fontSize': 14, 'alignment': TA_CENTER}
),
Label(
text=_(u"UF"),
left=label_left[0] * cm,
top=label_top,
),
Label(
text=_(u"Municipio"),
left=label_left[1] * cm,
top=label_top,
),
Label(
text=_(u"Presidente"),
left=label_left[2] * cm,
top=label_top,
),
Label(
text=_(u"Endereço"),
left=label_left[3] * cm,
top=label_top,
),
Label(
text=_(u"Endereço na Internet"),
left=label_left[4] * cm,
top=label_top,
),
Label(
text=_(u"Email"),
left=label_left[5] * cm,
top=label_top,
),
]
class band_page_footer(ReportDefault.band_page_footer):
pass
class band_detail(ReportDefault.band_detail):
label_left = [0.3, 1, 5.5, 11, 17, 22]
elements = [
ObjectValue(
attribute_name='municipio.uf.sigla',
left=label_left[0] * cm,
width=1 * cm,
),
ObjectValue(
attribute_name='municipio.nome',
left=label_left[1] * cm,
),
ObjectValue(
attribute_name='presidente',
left=label_left[2] * cm,
),
ObjectValue(
attribute_name='logradouro',
left=label_left[3] * cm,
get_value=lambda instance: instance.logradouro + ' - ' + instance.bairro,
),
ObjectValue(
attribute_name='pagina_web',
left=label_left[4] * cm,
),
ObjectValue(
attribute_name='email',
left=label_left[5] * cm,
),
]
groups = [
ReportGroup(attribute_name='municipio.uf',
band_header=ReportBand(
height=0.7 * cm,
elements=[
ObjectValue(attribute_name='municipio.uf')
],
borders={'top': True},
)
)
]
class CasasSemConvenioReport(CasasLegislativasReport):
title = _(u'Relatório de Casas Legislativas sem Convênio')
class InfoCasaLegislativa(ReportDefault):
title = _(u'Casa Legislativa')
class band_summary(ReportBand):
pass
class band_page_footer(ReportBand):
height = 1 * cm
elements = [
SystemField(expression=_(u'%(now:%d/%m/%Y)s às %(now:%H:%M)s'), top=0.3 * cm),
]
class band_detail(ReportDefault.band_detail):
posicao_left = [
0, 1.3, # Tipo
0, 1.8, # Regiao
5.5, 6.8, # U.F.
0, 2.3, # Municipio
0, 2.4, # Endereco
0, 1.6, # Bairro
0, 1.3, # CEP
0, 1.6, # CNPJ
0, 2.3, # Telefone
0, 2.7, # Presidente
]
posicao_top = [
0.5, # Tipo
1.3, # Regiao
1.3, # U.F.
2.1, # Municipio
2.9, # Logradouro
3.7, # Bairro
4.5, # CEP
5.3, # CNPJ
6.1, # Telefone
6.9, # Presidente
]
height = 30 * cm
display_inline = True
default_style = {'fontName': 'Helvetica', 'fontSize': 14}
elements = [
Label(
text=label_text(_(u"Tipo")),
left=posicao_left[0] * cm,
top=posicao_top[0] * cm,
),
ObjectValue(
attribute_name='tipo.nome',
left=posicao_left[1] * cm,
top=posicao_top[0] * cm,
width=6 * cm,
),
Label(
text=label_text(_(u"Região")),
left=posicao_left[2] * cm,
top=posicao_top[1] * cm,
),
ObjectValue(
attribute_name='municipio.uf.regiao',
left=posicao_left[3] * cm,
top=posicao_top[1] * cm,
get_value=lambda instance:
{'SL': _(u'Sul'), 'SD': _(u'Sudeste'), 'CO': _(u'Centro-Oeste'), 'NE': _(u'Nordeste'), 'NO': _(u'Norte'), }
[instance.municipio.uf.regiao]
),
Label(
text=label_text(_(u"UF")),
left=posicao_left[4] * cm,
top=posicao_top[2] * cm,
),
ObjectValue(
attribute_name='municipio.uf',
left=posicao_left[5] * cm,
top=posicao_top[2] * cm,
),
Label(
text=label_text(_(u"Município")),
left=posicao_left[6] * cm,
top=posicao_top[3] * cm,
),
ObjectValue(
attribute_name='municipio.nome',
left=posicao_left[7] * cm,
top=posicao_top[3] * cm,
width=20 * cm,
),
# Linha 3
Label(
text=label_text(_(u"Endereço")),
left=posicao_left[8] * cm,
top=posicao_top[4] * cm,
),
ObjectValue(
attribute_name='logradouro',
left=posicao_left[9] * cm,
top=posicao_top[4] * cm,
width=20 * cm,
),
Label(
text=label_text(_(u"Bairro")),
left=posicao_left[10] * cm,
top=posicao_top[5] * cm,
),
ObjectValue(
attribute_name='bairro',
left=posicao_left[11] * cm,
top=posicao_top[5] * cm,
),
Label(
text=label_text(_(u"CEP")),
left=posicao_left[12] * cm,
top=posicao_top[6] * cm,
),
ObjectValue(
attribute_name='cep',
left=posicao_left[13] * cm,
top=posicao_top[6] * cm,
),
Label(
text=label_text(_(u"CNPJ")),
left=posicao_left[14] * cm,
top=posicao_top[7] * cm,
),
ObjectValue(
attribute_name='cnpj',
left=posicao_left[15] * cm,
top=posicao_top[7] * cm,
),
Label(
text=label_text(_(u"Telefone")),
left=posicao_left[16] * cm,
top=posicao_top[8] * cm,
),
ObjectValue(
attribute_name='telefone',
left=posicao_left[17] * cm,
top=posicao_top[8] * cm,
),
Label(
text=label_text(_(u"Presidente")),
left=posicao_left[18] * cm,
top=posicao_top[9] * cm,
),
ObjectValue(
attribute_name='presidente',
left=posicao_left[19] * cm,
top=posicao_top[9] * cm,
width=20 * cm,
),
]
# Telefones
tel_top = 2 * cm
tel_left = [0, 3, 5]
# Contato
cont_top = 2 * cm
cont_left = [0, 6, 9]
# Convenios
convenio_top = 2 * cm
convenio_left = [0, 1.8, 4.5, 8, 10.5, 13, 15.5, 18]
subreports = [
# Telefones
SubReport(
queryset_string='%(object)s.telefones.all()',
band_header=ReportBand(
default_style={'fontName': 'Helvetica', 'fontSize': 12},
height=2.5 * cm,
elements=[
Label(
text=_(u"Telefone(s)"),
style={'fontSize': 14, 'alignment': TA_CENTER},
width=BAND_WIDTH,
top=1 * cm,
),
Label(text=_(u"Número"), left=tel_left[0] * cm, top=tel_top),
Label(text=_(u"Tipo"), left=tel_left[1] * cm, top=tel_top),
Label(text=_(u"Nota"), left=tel_left[2] * cm, top=tel_top),
],
borders={'bottom': True},
),
band_detail=ReportBand(
default_style={'fontName': 'Helvetica', 'fontSize': 11},
height=0.5 * cm,
elements=[
ObjectValue(attribute_name='__unicode__', left=tel_left[0] * cm),
ObjectValue(attribute_name='tipo', left=tel_left[1] * cm,
get_value=lambda instance:
{'F': _(u'Fixo'), 'M': _(u'Móvel'), 'X': _(u'Fax'), 'I': _(u'Indefinido')}[instance.tipo],
),
ObjectValue(attribute_name='nota', left=tel_left[2] * cm),
],
#borders = {'all':True},
),
),
# Contatos
SubReport(
queryset_string='%(object)s.funcionario_set.all()',
band_header=ReportBand(
default_style={'fontName': 'Helvetica', 'fontSize': 12},
height=2.5 * cm,
elements=[
Label(
text=_(u"Contato(s)"),
style={'fontSize': 14, 'alignment': TA_CENTER},
width=BAND_WIDTH,
top=1 * cm,
),
Label(text=_(u"Nome"), left=cont_left[0] * cm, top=cont_top),
Label(text=_(u"Nota"), left=cont_left[1] * cm, top=cont_top),
Label(text=_(u"E-mail"), left=cont_left[2] * cm, top=cont_top),
],
borders={'bottom': True, 'top': True},
),
band_detail=ReportBand(
default_style={'fontName': 'Helvetica', 'fontSize': 11},
height=0.5 * cm,
elements=[
ObjectValue(attribute_name='nome', left=cont_left[0] * cm),
ObjectValue(attribute_name='nota', left=cont_left[1] * cm),
ObjectValue(attribute_name='email', left=cont_left[2] * cm),
],
#borders = {'all':True},
),
),
# Convenios
SubReport(
queryset_string='%(object)s.convenio_set.all()',
band_header=ReportBand(
default_style={'fontName': 'Helvetica', 'fontSize': 12},
height=2.5 * cm,
elements=[
Label(
text=_(u"Convênio(s)"),
style={'fontSize': 14, 'alignment': TA_CENTER},
width=BAND_WIDTH,
top=1 * cm,
),
Label(text=_(u"Projeto"), left=convenio_left[0] * cm, top=convenio_top),
Label(text=_(u"Nº Convenio"), left=convenio_left[1] * cm, top=convenio_top),
Label(text=_(u"Nº Processo SF"), left=convenio_left[2] * cm, top=convenio_top),
Label(text=_(u"Adesão"), left=convenio_left[3] * cm, top=convenio_top),
Label(text=_(u"Convênio"), left=convenio_left[4] * cm, top=convenio_top),
Label(text=_(u"Equipada"), left=convenio_left[5] * cm, top=convenio_top),
Label(text=_(u"Data D.O."), left=convenio_left[6] * cm, top=convenio_top),
],
borders={'bottom': True}
),
band_detail=ReportBand(
default_style={'fontName': 'Helvetica', 'fontSize': 11},
height=0.5 * cm,
elements=[
ObjectValue(attribute_name='projeto.sigla', left=convenio_left[0] * cm),
ObjectValue(attribute_name='num_convenio', left=convenio_left[1] * cm),
ObjectValue(attribute_name='num_processo_sf', left=convenio_left[2] * cm),
ObjectValue(attribute_name='data_adesao', left=convenio_left[3] * cm,
get_value=lambda instance:
instance.data_adesao.strftime('%d/%m/%Y') if instance.data_adesao is not None else '-'
),
ObjectValue(attribute_name='data_retorno_assinatura', left=convenio_left[4] * cm,
get_value=lambda instance:
instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura is not None else '-'
),
ObjectValue(attribute_name='data_termo_aceite', left=convenio_left[5] * cm,
get_value=lambda instance:
instance.data_termo_aceite.strftime('%d/%m/%Y') if instance.data_termo_aceite is not None else '-'
),
ObjectValue(attribute_name='data_pub_diario', left=convenio_left[6] * cm,
get_value=lambda instance:
instance.data_pub_diario.strftime('%d/%m/%Y') if instance.data_pub_diario is not None else '-'
),
],
#borders = {'all':True},
),
)
]

6
sigi/apps/casas/templates/casas/ocorrencia_inline.html → sigi/apps/casas/templates/admin/casas/convenios_inline.html

@ -65,9 +65,9 @@
{% endif %}
</tr>
{% endfor %}
<tr><td colspan="{{ inline_admin_formset.formset.fields|length }}">
<a href="/ocorrencias/ocorrencia/add/?casa_legislativa={{original.pk|safe}}">
<span class="glyphicon glyphicon-plus"></span> Adicionar ocorrência
<tr><td colspan="100">
<a href="{% url 'admin:convenios_convenio_add' %}?casa_legislativa={{original.pk|safe}}">
<span class="glyphicon glyphicon-plus"></span>{% blocktrans with inline_admin_formset.opts.verbose_name|capfirst as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}
</a>
</td></tr>
</tbody>

164
sigi/apps/casas/templates/admin/casas/ocorrencia_inline.html

@ -0,0 +1,164 @@
{% load i18n admin_static admin_modify bootstrapped_goodies_tags %}
<div class="_inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }}
<fieldset class="module">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.non_form_errors }}
<table class="table table-striped table-bordered">
<thead><tr>
{% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %}
<th{% if forloop.first %} colspan="2"{% endif %}{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}
{% if field.help_text %}<i class="glyphicon glyphicon-comment help help-tooltip" style="margin-left: 4px;" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}"></i>{% endif %}
</th>
{% endif %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
</tr></thead>
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
<tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="form-row {% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<td class="original">
{% if inline_admin_formset.opts.sortable_field_name %}
<span class="btn btn-default btn-xs drag-handler pull-left"><i class="glyphicon glyphicon-move"></i></span>
{% endif %}
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}
{% if inline_admin_form.show_url %}<a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %}
{% if inline_admin_form.has_auto_field or inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endspaceless %}
</td>
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
<td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{% if field.errors %}
<div class="alert alert-danger">{{ field.errors|striptags }}</div>
{% endif %}
{% dab_field_rendering field.field %}
{% endif %}
</td>
{% endfor %}
{% endfor %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
{% endif %}
</tr>
{% endfor %}
<tr><td colspan="100">
<a href="{% url 'admin:ocorrencias_ocorrencia_add' %}?casa_legislativa={{original.pk|safe}}">
<span class="glyphicon glyphicon-plus"></span>{% blocktrans with inline_admin_formset.opts.verbose_name|capfirst as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}
</a>
</td></tr>
</tbody>
</table>
</fieldset>
</div>
</div>
<script type="text/javascript">
(function($) {
$(document).ready(function($) {
var rows = "#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr";
var alternatingRows = function(row) {
$(rows).not(".add-row").removeClass("row1 row2")
.filter(":even").addClass("row1").end()
.filter(rows + ":odd").addClass("row2");
}
var reinitDateTimeShortCuts = function() {
// Reinitialize the calendar and clock widgets by force
if (typeof DateTimeShortcuts != "undefined") {
$(".datetimeshortcuts").remove();
DateTimeShortcuts.init();
}
}
var updateSelectFilter = function() {
// If any SelectFilter widgets are a part of the new form,
// instantiate a new SelectFilter instance for it.
if (typeof SelectFilter != "undefined"){
$(".selectfilter").each(function(index, value){
var namearr = value.name.split('-');
SelectFilter.init(value.id, namearr[namearr.length-1], false, "{% static "admin/" %}");
});
$(".selectfilterstacked").each(function(index, value){
var namearr = value.name.split('-');
SelectFilter.init(value.id, namearr[namearr.length-1], true, "{% static "admin/" %}");
});
}
}
var initPrepopulatedFields = function(row) {
row.find('.prepopulated_field').each(function() {
var field = $(this);
var input = field.find('input, select, textarea');
var dependency_list = input.data('dependency_list') || [];
var dependencies = [];
$.each(dependency_list, function(i, field_name) {
dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
});
if (dependencies.length) {
input.prepopulate(dependencies, input.attr('maxlength'));
}
});
}
$(rows).formset({
prefix: "{{ inline_admin_formset.formset.prefix }}",
addText: "{% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|title %}Add another {{ verbose_name }}{% endblocktrans %}",
formCssClass: "dynamic-{{ inline_admin_formset.formset.prefix }}",
deleteCssClass: "inline-deletelink",
deleteText: "{% trans "Remove" %}",
emptyCssClass: "empty-form",
removed: alternatingRows,
added: (function(row) {
initPrepopulatedFields(row);
reinitDateTimeShortCuts();
updateSelectFilter();
alternatingRows(row);
})
});
});
})(django.jQuery);
// listener for jquery 1.7.2
(function($) {
{% if inline_admin_formset.opts.sortable_field_name %}
$('tbody').sortable({
// items: '.dynamic-{{ inline_admin_formset.formset.prefix }}',
handle: '.drag-handler',
items: ".form-row"
});
$("#{{ opts.model_name }}_form").submit(function(e) {
var sortable_field_name = "{{ inline_admin_formset.opts.sortable_field_name }}",
i = 0;
var initial_form_count = $('#id_{{ inline_admin_formset.formset.prefix }}-INITIAL_FORMS').val();
$('#{{ inline_admin_formset.formset.prefix }}-group table > tbody').find(".form-row").each(function(i, e) {
// make sure we don't assign a position unless extra has been moved
if ($(this).find("input[name$='" + sortable_field_name + "']").val() || (i <= initial_form_count - 1 )) {
$(this).find("input[name$='" + sortable_field_name + "']").val(i);
i++;
}
});
});
{% endif %}
})(jQuery);
</script>

6
sigi/apps/casas/templates/casas/carrinho.html

@ -186,6 +186,12 @@
value="Última alteração de endereco" class="action-select" checked="checked" />
<label>{% trans 'Data da última alteração de endereço' %}</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Servicos SEIT" class="action-select" checked="checked" />
<label>{% trans 'Serviços SEIT' %}</label>
</li>
</ul>
</fieldset>

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

@ -0,0 +1,57 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_static %}
{% load static from staticfiles %}
{% block coltype %}colMS{% endblock %}
{% block content_title %}<h1>{% blocktrans %}Gerentes Interlegis{% endblocktrans %}</h1>{% endblock %}
{% block content %}
<div id="navbar-object-tools" class="nav">
<ul class="nav navbar-nav navbar-left">
<li><a href="?fmt=pdf">
<span class="glyphicon glyphicon-print"></span>
Relatório PDF
</a></li>
<li><a href="?fmt=csv&casas=yes">
<span class="glyphicon glyphicon-list-alt"></span>
CSV com casas
</a></li>
<li><a href="?fmt=csv&casas=no">
<span class="glyphicon glyphicon-list-alt"></span>
CSV sem casas
</a></li>
</ul>
</div>
<div id="content" class="colM">
{% for linha in gerentes %}
<div class="panel panel-primary">
<div class="panel-heading">
<p>{{ linha.gerente.nome_completo }} <span class="badge">{{ linha.gerente.casas_que_gerencia.count }}</span></p>
</div>
<div class="panel-body">
<ul class="nav nav-pills" role="tablist">
{% for uf in linha.ufs %}
<li role="presentation">
<a href="#tab{{ linha.gerente.id }}-{{ uf.0 }}" aria-controls="tab{{ linha.gerente.id }}-{{ uf.0 }}" role="tab" data-toggle="tab">{{ uf.1 }} <span class="badge">{{ uf.2|length }}</span></a>
</li>
{% endfor %}
</ul>
<div class="tab-content">
{% for uf in linha.ufs %}
<div role="tabpanel" class="tab-pane" id="tab{{ linha.gerente.id }}-{{ uf.0 }}">
<ul class="list-group list-inline">
{% for casa in uf.2 %}
<li class="list-group-item list-inline-item">
<a href="{% url 'admin:casas_orgao_change' casa.id %}" target="_blank">{{ casa }}</a></li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}

143
sigi/apps/casas/templates/casas/gerentes_interlegis_pdf.html

@ -0,0 +1,143 @@
{% load static from staticfiles %}
{% load i18n %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Casa Legislativa</title>
<style type="text/css">
table {
padding: 3px;
line-height: 1em;
-fs-table-paginate: paginate;
}
thead {
display: table-header-group;
}
th {
font-weight: bold;
text-align: left;
}
th, td {
border-bottom: 1px solid #ddd;
vertical-align: top;
}
td.logo {
text-align: center;
}
td.header_text p {
margin: 0px;
font-size: 1.4em;
}
td.header_text {
width: 550px;
}
ul {
list-style-type: none;
padding-left: 15px;
}
li {
padding-left: 5px;
color: #999;
}
li.selected {
list-style-type: disc;
color: #000;
font-weight: bold;
}
p.strong {
margin-left: 25px;
line-height: 1em;
}
h1 {
font-size: 2em;
text-align: center;
}
h2 {
font-size: 1.7em;
}
h3 {
margin-top: 10px;
margin-bottom: 0px;
}
body {
font-family: "Helvetica, Arial, sans-serif";
font-size: 1.3em;
line-height: 1em;
}
div.new_page {
page-break-before: always;
}
div.same_page_ {
-pdf-keep-with-next: true;
}
.text-right {
text-align: right;
}
@page {
margin: 4cm 1cm 1cm 2cm;
font-family: "Helvetica, Arial, sans-serif";
font-size: 2em;
@frame header {
-pdf-frame-content: header;
top: 1cm;
}
@frame footer {
-pdf-frame-content: footer;
bottom: 0cm;
margin-left: 9cm;
margin-right: 9cm;
height: 1cm;
}
}
</style>
</head>
<body>
<div id="header">
<table>
<tr>
<td class="logo"><img src="{% static 'img/logo-senado.jpg' %}"/></td>
<td class="header_text">
<p><strong>{% trans 'SENADO FEDERAL' %}</strong></p>
<p><strong>{% trans 'ILB - Interlegis' %}</strong></p>
<p>{% trans 'Gerentes Interlegis' %}</p>
</td>
<td class="logo"><img src="{% static 'img/logo-interlegis.jpg' %}"/></td>
</tr>
</table>
</div>
<table>
<thead>
<tr>
<th>Gerente Interlegis</th>
<th>UF</th>
<th>Número de casas</th>
</tr>
</thead>
{% for linha in gerentes %}
{% for uf in linha.ufs %}
<tr>
{% if forloop.first %}
<td>{{ linha.gerente.nome_completo }}</td>
{% else %}
<td>&nbsp;</td>
{% endif %}
<td>{{ uf.1 }}</td>
<td class="text-right">{{ uf.2.count }}</td>
</tr>
{% endfor %}
<tr>
<td colspan="2"><strong>Total de casas atendidas por {{ linha.gerente.nome_completo }}</strong></td>
<td class="text-right"><strong>{{ linha.gerente.casas_que_gerencia.count }}</strong></td>
</tr>
{% endfor %}
</table>
<div id="footer">
{%block page_foot%}
{% trans 'Página' %} <pdf:pagenumber>
{%endblock%}
</div>
</body>
</html>

81
sigi/apps/casas/templates/casas/importar.html

@ -0,0 +1,81 @@
{% extends "admin/base_site.html" %}
{% load i18n bootstrap3 %}
{% block content_title %}
<h1 class="pull-left">{% trans 'Importar dados para atualização de órgãos' %}</h1>
{% endblock %}
{% block content %}
{% if error %}
<div class="alert alert-danger" role="alert">
{{ error }}
</div>
{% endif %}
<div id="content-main">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
{% bootstrap_form form %}
</div>
<input type="submit" value="Importar" class="btn btn-primary"/>
</form>
<div id="data-hints">
<h3>Padrões do arquivo:</h3>
<ul class="list-group">
<li class="list-group-item">O arquivo deve ter o formato de texto, no padrão CSV</li>
<li class="list-group-item">Deve-se usar pt-br.UTF-8 como codificação do arquivo</li>
<li class="list-group-item">A primeira linha do arquivo teve conter o cabeçalho das colunas, conforme explicado a seguir</li>
<li class="list-group-item">Cada linha subsequente deve referir-se a um e somente um órgão</li>
<li class="list-group-item">Campos deixados em branco serão ignorados</li>
</ul>
<hr/>
<h3>Colunas do arquivo:</h3>
<ul class="list-group">
<li class="list-group-item">O arquivo deve possuir no mínimo as colunas marcadas como obrigatórias.
A primeira linha deve conter os cabeçalhos, que devem ser grafados
EXATAMENTE como descrito na tabela abaixo (minúsculas, sem acentos, sem espaços).</li>
<li class="list-group-item">É desejável que as colunas estejam na mesma ordem definida aqui.</li>
<li class="list-group-item">Colunas adicionais podem estar presentes, e serão ignoradas</li>
</ul>
<table class="table table-striped table-condensed">
<thead class="thead-light">
<tr>
<th>Obrigatório</th>
<th>Título do campo</th>
<th>Conteúdo esperado</th>
</tr>
</thead>
<tbody>
<tr><th>*</th><th>tipo</th><td>Deve conter CM para Câmara Municipal ou AL para Assembleia Legislativa</td></tr>
<tr><th>*</th><th>municipio</th><td>O nome do município. Não use abreviações!!!</td></tr>
<tr><th>*</th><th>uf</th><td>A sigla da Unidade da Federação (Estado) em letras maiúsculas (ex: MG, SP, PA)</td></tr>
<tr><th></th><th>orgao_endereco</th><td>O novo endereço do órgão.</td></tr>
<tr><th></th><th>orgao_bairro</th><td>O novo bairro do órgão</td></tr>
<tr><th></th><th>orgao_cep</th><td>O novo CEP do órgão</td></tr>
<tr><th></th><th>orgao_email</th><td>O novo e-mail institucional do órgão</td></tr>
<tr><th></th><th>orgao_portal</th><td>O novo endereço do portal institucional do órgão</td></tr>
<tr><th></th><th>orgao_telefones</th><td>Os telefones do órgão. Pode conter quantos telefones forem necessários, separando-os por ';'. Use a formatação padrão de telefones, mas não use ';' entre os dígitos de um telefone, senão o sistema interpretará como dois telefones diferentes. </td></tr>
<tr><th></th><th>presidente_nome</th><td>O nome completo do presidente</td></tr>
<tr><th></th><th>presidente_data_nascimento</th><td>A data de nascimento do presidente no formato DD/MM/AAAA</td></tr>
<tr><th></th><th>presidente_telefones</th><td>Os telefones ou whatsapp do presidente. Pode conter quantos telefones forem necessários, separando-os por ';'. Use a formatação padrão de telefones, mas não use ';' entre os dígitos de um telefone, senão o sistema interpretará como dois telefones diferentes.</td></tr>
<tr><th></th><th>presidente_emails</th><td>Os e-mails do presidente. Pode conter quantos e-mails forem necessários. Utilize ';' para separar um e-mail do outro</td></tr>
<tr><th></th><th>presidente_endereco</th><td>O novo endereço do presidente</td></tr>
<tr><th></th><th>presidente_municipio</th><td>O nome do município onde mora o presidente</td></tr>
<tr><th></th><th>presidente_bairro</th><td>O nome do bairro onde mora o presidente</td></tr>
<tr><th></th><th>presidente_cep</th><td>O novo CEP do presidente</td></tr>
<tr><th></th><th>presidente_redes_sociais</th><td>As redes sociais do presidente. Pode conter quantas redes sociais forem necessárias. Utilize espaço para separar uma rede da outra.</td></tr>
<tr><th></th><th>contato_nome</th><td>O nome completo do contato</td></tr>
<tr><th></th><th>contato_data_nascimento</th><td>A data de nascimento do contato no formato DD/MM/AAAA</td></tr>
<tr><th></th><th>contato_telefones</th><td>Os telefones ou whatsapp do contato. Pode conter quantos telefones forem necessários, separando-os por ';'. Use a formatação padrão de telefones, mas não use ';' entre os dígitos de um telefone, senão o sistema interpretará como dois telefones diferentes.</td></tr>
<tr><th></th><th>contato_emails</th><td>Os e-mails do contato. Pode conter quantos e-mails forem necessários. Utilize ';' para separar um e-mail do outro</td></tr>
<tr><th></th><th>contato_endereco</th><td>O novo endereço do contato</td></tr>
<tr><th></th><th>contato_municipio</th><td>O nome do município onde mora o contato</td></tr>
<tr><th></th><th>contato_bairro</th><td>O nome do bairro onde mora o contato</td></tr>
<tr><th></th><th>contato_cep</th><td>O novo CEP do contato</td></tr>
<tr><th></th><th>contato_redes_sociais</th><td>As redes sociais do contato. Pode conter quantas redes sociais forem necessárias. Utilize espaço para separar uma rede da outra.</td></tr>
<tbody>
</table>
</div>
</div>
{% endblock %}

18
sigi/apps/casas/templates/casas/importar_result.html

@ -0,0 +1,18 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% block content_title %}
<h1 class="pull-left">Importação de órgãos concluída com {% if com_erros %}erros{% else %}sucesso!{% endif %}</h1>
{% endblock %}
{% block content %}
<div id="content-main">
<p>{{ total }} registros importados do arquivo {{ file_name }}</p>
{% if com_erros %}
<p>{{ com_erros }} registros apresentaram erros</p>
<p><a href="{{ MEDIA_URL }}temp/{{ result_file }}">Download do arquivo de erros</a></p>
{% endif %}
<p><a href="{% url 'importar-casas' %}">Importar outro arquivo</a></p>
</div>
{% endblock %}

2
sigi/apps/casas/templates/casas/lista_casas_carteira_snippet.html

@ -64,7 +64,7 @@
</tr>
{% for casa in page_obj.object_list %}
<tr>
<td><a href="{% url 'admin:casas_casalegislativa_change' casa.pk %}">{{ casa.nome }}</a></td>
<td><a href="{% url 'admin:casas_orgao_change' casa.pk %}">{{ casa.nome }}</a></td>
<td>{{ casa.municipio.uf.get_regiao_display }}</td>
<td>{{ casa.municipio.uf }}</td>
<td>{{ casa.municipio.microrregiao.mesorregiao }}</td>

46
sigi/apps/casas/templates/casas/portfolio.html

@ -5,6 +5,32 @@
{% block extrastyle %}
<style type="text/css">
/* Tooltip container */
.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}
/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;
/* Position the tooltip text - see examples below! */
position: absolute;
z-index: 1;
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
}
</style>
{{ block.super }}
{% endblock %}
@ -22,10 +48,18 @@
<div class="alert alert-danger">{{ e }}</div>
{% endfor %}
<div class="nav">
<ul class="object-tools pull-left nav nav-pills">
{% for t in tipos_casas %}
<li{% if tipo == t.sigla %} class="active"{% endif %}><a href="?tipo={{ t.sigla }}" data-toggle="tooltip" title="{{ t.nome }}">{{ t.sigla }}</a></li>
{% endfor %}
</ul>
</div>
<div class="nav">
<ul class="object-tools pull-left nav nav-pills">
{% for key, value in regioes %}
<li{% if regiao == key %} class="active"{% endif %}><a href="?regiao={{ key }}">{{ value }}</a></li>
<li{% if regiao == key %} class="active"{% endif %}><a href="?regiao={{ key }}{% if tipo %}&tipo={{ tipo|safe }}{% endif %}">{{ value }}</a></li>
{% endfor %}
</ul>
</div>
@ -34,7 +68,7 @@
<div class="nav">
<ul class="object-tools pull-left nav nav-tabs">
{% for uf in ufs %}
<li{% if uf_id == uf.pk %} class="active"{% endif %}><a href="?uf={{ uf.pk|safe }}">{{ uf.nome }}</a></li>
<li{% if uf_id == uf.pk %} class="active"{% endif %}><a href="?uf={{ uf.pk|safe }}{% if tipo %}&tipo={{ tipo|safe }}{% endif %}">{{ uf.nome }}</a></li>
{% endfor %}
</ul>
</div>
@ -44,7 +78,7 @@
<div class="nav">
<ul class="object-tools pull-left nav nav-pills">
{% for meso in mesorregioes %}
<li{% if meso_id == meso.pk %} class="active"{% endif %}><a href="?meso={{ meso.pk|safe }}">{{ meso.nome }}</a></li>
<li{% if meso_id == meso.pk %} class="active"{% endif %}><a href="?meso={{ meso.pk|safe }}{% if tipo %}&tipo={{ tipo|safe }}{% endif %}">{{ meso.nome }}</a></li>
{% endfor %}
</ul>
</div>
@ -54,7 +88,7 @@
<div class="nav">
<ul class="object-tools pull-left nav nav-pills">
{% for micro in microrregioes %}
<li{% if micro_id == micro.pk %} class="active"{% endif %}><a href="?micro={{ micro.pk|safe }}">{{ micro.nome }}</a></li>
<li{% if micro_id == micro.pk %} class="active"{% endif %}><a href="?micro={{ micro.pk|safe }}{% if tipo %}&tipo={{ tipo|safe }}{% endif %}">{{ micro.nome }}</a></li>
{% endfor %}
</ul>
</div>
@ -64,7 +98,7 @@
<form action="" method="post" id="atribui_gerente_form">
{% csrf_token %}
{{ form }}
<input type="submit" name="_save" value="Atribuir" class="btn btn-default" />
<input type="submit" name="_save" class="btn btn-default"/>
</form>
{% endif %}
@ -85,7 +119,7 @@
<td>{{ casa.municipio.uf }}</td>
<td>{{ casa.municipio.microrregiao.mesorregiao }}</td>
<td>{{ casa.municipio.microrregiao.nome }}</td>
<td>{{ casa.gerente_contas }}</td>
<td>{{ casa.lista_gerentes|safe }}</td>
</tr>
{% endfor %}
</table>

237
sigi/apps/casas/templates/casas/report_complete_pdf.html

@ -0,0 +1,237 @@
{% load smart_if %}
{% load static from staticfiles %}
{% load i18n %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Casa Legislativa</title>
<style type="text/css">
table {
padding: 3px;
line-height: 1em;
-fs-table-paginate: paginate;
}
thead {
display: table-header-group;
}
th {
font-weight: bold;
text-align: left;
}
th, td {
border-bottom: 1px solid #ddd;
}
.identificacao th {
width: 20%;
}
div#capa h3 {
text-align: center;
margin-top: 5px;
margin-bottom: 0px;
}
div#capa p {
text-align: center;
}
td.logo {
text-align: center;
}
td.header_text p {
margin: 0px;
font-size: 1.4em;
}
td.header_text {
width: 550px;
}
ul {
list-style-type: none;
padding-left: 15px;
}
li {
padding-left: 5px;
color: #999;
}
li.selected {
list-style-type: disc;
color: #000;
font-weight: bold;
}
p.strong {
margin-left: 25px;
line-height: 1em;
}
h1 {
font-size: 2em;
text-align: center;
}
h2 {
font-size: 1.7em;
}
h3 {
margin-top: 10px;
margin-bottom: 0px;
}
body {
font-family: "Helvetica, Arial, sans-serif";
font-size: 1.3em;
line-height: 1em;
}
div.new_page {
page-break-before: always;
}
div.same_page_ {
-pdf-keep-with-next: true;
}
@page {
size: {{ pagesize }};
margin: 4cm 1cm 1cm 2cm;
font-family: "Helvetica, Arial, sans-serif";
font-size: 2em;
@frame header {
-pdf-frame-content: header;
top: 1cm;
}
@frame footer {
-pdf-frame-content: footer;
bottom: 0cm;
margin-left: 9cm;
margin-right: 9cm;
height: 1cm;
}
}
</style>
</head>
<body>
<div id="header">
<table>
<tr>
<td class="logo"><img src="{% static 'img/logo-senado.jpg' %}"/></td>
<td class="header_text">
<p><strong>{% trans 'SENADO FEDERAL' %}</strong></p>
<p><strong>{% trans 'ILB - Interlegis' %}</strong></p>
<p>{% trans 'Relatório completo' %}</p>
</td>
<td class="logo"><img src="{% static 'img/logo-interlegis.jpg' %}"/></td>
</tr>
</table>
</div>
{% for casa in casas %}
<div class="{% if forloop.first %}{% else %}new_page{% endif %}">
<h2>{{ casa.nome }}</h2>
<table class="identificacao">
<tr><th>{% trans 'Presidente:' %}</th><td>{{ casa.presidente }}</td></tr>
<tr><th>{% trans 'Tipo:' %}</th><td>{{ casa.tipo.nome }}</td></tr>
<tr><th>{% trans 'Estado / região:' %}</th><td>{{ casa.municipio.uf.nome }} / {{ casa.municipio.uf.get_regiao_display }}</td></tr>
<tr><th>{% trans 'Município:' %}</th><td>{{ casa.municipio.nome }}</td></tr>
<tr><th>{% trans 'Endereço:' %}</th><td>{{ casa.logradouro }}</td></tr>
<tr><th>{% trans 'Bairro:' %}</th><td>{{ casa.bairro }}</td></tr>
<tr><th>{% trans 'CEP:' %}</th><td>{{ casa.cep }}</td></tr>
<tr><th>{% trans 'CNPJ:' %}</th><td>{{ casa.cnpj }}</td></tr>
<tr><th>{% trans 'Telefone:' %}</th><td>{{ casa.telefone }}</td></tr>
<tr><th>{% trans 'E-mail:' %}</th><td>{{ casa.email }}</td></tr>
</table>
<h3>Telefones</h3>
<table repeat="1">
<thead>
<tr>
<th>Número</th>
<th>Tipo</th>
<th>Nota</th>
</tr>
<thead>
{% for tel in casa.telefones.all %}
<tr>
<td>{{ tel.numero }}</td>
<td>{{ tel.get_tipo_display }}</td>
<td>{{ tel.nota }}</td>
</tr>
{% endfor %}
</table>
<h3>Pessoas de contato</h3>
<table repeat="1">
<thead>
<tr>
<th>Nome</th>
<th>E-mail</th>
<th>Setor</th>
<th>Notas</th>
</tr>
</thead>
{% for func in casa.funcionario_set.all %}
<tr>
<td>{{ func.nome }}</td>
<td>{{ func.email }}</td>
<td>{{ func.get_setor_display }}</td>
<td>{{ func.nota }}</td>
</tr>
{% endfor %}
</table>
<h3>Convênios</h3>
<table repeat="1">
<thead>
<tr>
<th>Projeto</th>
<th>Nº convênio</th>
<th>Nº processo SF</th>
<th>Adesão</th>
<th>Convênio</th>
<th>Equipada</th>
<th>Publicada</th>
</tr>
</thead>
{% for conv in casa.convenio_set.all %}
<tr>
<td>{{ conv.projeto.nome }}</td>
<td>{{ conv.num_convenio|default_if_none:"-" }}</td>
<td>{{ conv.num_processo_sf|default_if_none:"-" }}</td>
<td>{{ conv.data_adesao|date:"SHORT_DATE_FORMAT" }}</td>
<td>{{ conv.data_retorno_assinatura|date:"SHORT_DATE_FORMAT" }}</td>
<td>{{ conv.equipada|yesno }}</td>
<td>{{ conv.data_pub_diario|date:"SHORT_DATE_FORMAT" }}</td>
</tr>
{% endfor %}
</table>
<h3>Serviços Interlegis</h3>
<table repeat="1">
<thead>
<tr>
<th>Serviço</th>
<th>Endereço</th>
<th>Ativado em</th>
<th>Desativado em</th>
</tr>
</thead>
{% for srv in casa.servico_set.all %}
<tr>
<td>{{ srv.tipo_servico.nome }}</td>
<td>{{ srv.url|default_if_none:"-" }}</td>
<td>{{ srv.data_ativacao|date:"SHORT_DATE_FORMAT" }}</td>
<td>{{ srv.data_desativacao|date:"SHORT_DATE_FORMAT" }}</td>
</tr>
{% endfor %}
</table>
</div>
{% endfor %}
<div id="footer">
{%block page_foot%}
{% trans 'Página' %} <pdf:pagenumber>
{%endblock%}
</div>
</body>
</html>

132
sigi/apps/casas/templates/casas/report_pdf.html

@ -0,0 +1,132 @@
{% load smart_if %}
{% load static from staticfiles %}
{% load i18n %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Casa Legislativa</title>
<style type="text/css">
table {
padding: 3px;
line-height: 1em;
-fs-table-paginate: paginate;
}
thead {
display: table-header-group;
}
th {
font-weight: bold;
text-align: left;
}
th, td {
border-bottom: 1px solid #ddd;
}
td.logo {
text-align: center;
}
td.header_text p {
margin: 0px;
font-size: 1.4em;
}
td.header_text {
width: 550px;
}
h1 {
font-size: 2em;
text-align: center;
}
h2 {
font-size: 1.7em;
}
h3 {
margin-top: 10px;
margin-bottom: 0px;
}
body {
font-family: "Helvetica, Arial, sans-serif";
font-size: 1.3em;
line-height: 1em;
}
#footer {
text-align: center;
}
@page {
size: a4 landscape;
margin: 3.5cm 2cm 2cm 2cm;
font-family: "Helvetica, Arial, sans-serif";
font-size: 2em;
@frame header {
-pdf-frame-content: header;
top: 1cm;
}
@frame footer {
-pdf-frame-content: footer;
bottom: 0cm;
margin-left: 2cm;
margin-right: 2cm;
height: 1cm;
}
}
</style>
</head>
<body>
<div id="header">
<table>
<tr>
<td class="logo"><img src="{% static 'img/logo-senado.jpg' %}"/></td>
<td class="header_text">
<p><strong>{% trans 'SENADO FEDERAL' %}</strong></p>
<p><strong>{% trans 'ILB - Interlegis' %}</strong></p>
<p>{{ title }}</p>
</td>
<td class="logo"><img src="{% static 'img/logo-interlegis.jpg' %}"/></td>
</tr>
</table>
</div>
<table repeat="1">
<thead>
<tr>
<th style="width: 22.5%;">{% trans 'Casa' %}</th>
<th style="width: 12.5%;">{% trans 'Presidente' %}</th>
<th style="width: 5%;">{% trans 'Tipo' %}</th>
<th style="width: 18%;">{% trans 'Endereço' %}</th>
<th style="width: 10%;">{% trans 'Bairro' %}</th>
<th style="width: 7%;">{% trans 'CEP' %}</th>
<th style="width: 12.5%;">{% trans 'Telefone' %}</th>
<th style="width: 12.5%;">{% trans 'E-mail' %}</th>
</tr>
</thead>
{% for casa in casas %}
{% ifchanged casa.municipio.uf %}
<tr><td colspan="8"><h3>{{ casa.municipio.uf.nome }}</h3></td></tr>
{% endifchanged %}
<tr>
<td>{{ casa.nome }}</td>
<td>{{ casa.presidente }}</td>
<td>{{ casa.tipo.sigla }}</td>
<td>{{ casa.logradouro }}</td>
<td>{{ casa.bairro }}</td>
<td>{{ casa.cep }}</td>
<td>{{ casa.telefone }}</td>
<td>{{ casa.email }}</td>
</tr>
{% endfor %}
</table>
<div id="footer">
{%block page_foot%}
{% trans 'Página' %} <pdf:pagenumber>
{%endblock%}
</div>
</body>
</html>

4
sigi/apps/casas/test_casas.py

@ -1,7 +1,7 @@
import pytest
from django_dynamic_fixture import G
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
@pytest.fixture
@ -14,4 +14,4 @@ def some_parliaments():
def parliaments_from_names(names):
return [G(CasaLegislativa, nome=name, foto=None, gerente_contas=None,) for name in names]
return [G(Orgao, nome=name, foto=None,) for name in names]

47
sigi/apps/casas/urls.py

@ -1,38 +1,57 @@
# coding: utf-8
from django.conf.urls import patterns, url
from django.contrib.auth.decorators import login_required
from sigi.apps.casas.views import importa_casas
urlpatterns = patterns(
'sigi.apps.casas.views',
# Informacoes de uma casa legislativa
url(r'^casalegislativa/report_complete/$', 'report_complete', name='report-complete-all'),
url(r'^casalegislativa/(?P<id>\w+)/report_complete/$', 'report_complete', name='report-complete-id'),
url(r'^orgao/report_complete/$', 'report_complete',
name='report-complete-all'),
url(r'^orgao/(?P<id>\w+)/report_complete/$', 'report_complete',
name='report-complete-id'),
# Reports Labels
url(r'^casalegislativa/labels/$', 'labels_report', name='labels-report-all'),
url(r'^casalegislativa/(?P<id>\w+)/labels/$', 'labels_report', name='labels-report-id'),
url(r'^orgao/labels/$', 'labels_report', name='labels-report-all'),
url(r'^orgao/(?P<id>\w+)/labels/$', 'labels_report',
name='labels-report-id'),
# Reports Labels Parlamentar
url(r'^casalegislativa/labels_parlamentar/$', 'labels_report_parlamentar', name='lebels-report-parlamentar-all'),
url(r'^casalegislativa/(?P<id>\w+)/labels_parlamentar/$', 'labels_report_parlamentar', name='labels-report-parlamentar-id'),
url(r'^orgao/labels_parlamentar/$', 'labels_report_parlamentar',
name='lebels-report-parlamentar-all'),
url(r'^orgao/(?P<id>\w+)/labels_parlamentar/$', 'labels_report_parlamentar',
name='labels-report-parlamentar-id'),
# Reports labels sem presidente
url(r'^casalegislativa/labels_sem_presidente/$', 'labels_report_sem_presidente', name='labels-report-sem-presidente-all'),
url(r'^casalegislativa/(?P<id>\w+)/labels_sem_presidente/$', 'labels_report_sem_presidente', name='labels-report-sem-presidente-id'),
url(r'^orgao/labels_sem_presidente/$', 'labels_report_sem_presidente',
name='labels-report-sem-presidente-all'),
url(r'^orgao/(?P<id>\w+)/labels_sem_presidente/$',
'labels_report_sem_presidente', name='labels-report-sem-presidente-id'),
# Reports casas sem convenio
url(r'^casalegislativa/reports/$', 'report', name='casa-report'),
url(r'^casalegislativa/casas_sem_convenio_report/$', 'casas_sem_convenio_report', name='casas-sem-convenio-report'),
url(r'^orgao/reports/$', 'report', name='casa-report'),
url(r'^orgao/casas_sem_convenio_report/$', 'casas_sem_convenio_report',
name='casas-sem-convenio-report'),
# CSV
url(r'^casalegislativa/csv/$', 'export_csv', name='casa-export-csv'), # Error
url(r'^orgao/csv/$', 'export_csv', name='casa-export-csv'), # Error
# Carrinho
url(r'^casalegislativa/carrinho/$', 'visualizar_carrinho', name='visualizar-carrinho'),
url(r'^casalegislativa/carrinho/excluir_carrinho/$', 'excluir_carrinho', name='excluir-carrinho'), # Error
url(r'^casalegislativa/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho', name='deleta-itens-carrinho'), # Error
url(r'^orgao/carrinho/$', 'visualizar_carrinho',
name='visualizar-carrinho'),
url(r'^orgao/carrinho/excluir_carrinho/$', 'excluir_carrinho',
name='excluir-carrinho'), # Error
url(r'^orgao/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho',
name='deleta-itens-carrinho'), # Error
url(r'^portfolio/$', 'portfolio', name='casas-portfolio'),
url(r'^carteira/$', 'painel_relacionamento', name='casas-carteira'),
# Atualização por CSV
url(r'^orgao/importa/$', login_required(importa_casas.as_view()),
name='importar-casas'),
url(r'^gerentes/$', 'gerentes_interlegis',
name='gerentes_interlegis'),
)

624
sigi/apps/casas/views.py

@ -1,33 +1,322 @@
# -*- coding: utf-8 -*-
import csv
from datetime import datetime
from functools import reduce
from geraldo.generators import PDFGenerator
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.db.models import Count, Q
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext as _, ungettext
from geraldo.generators import PDFGenerator
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.reports import CasasLegislativasLabels, CasasLegislativasLabelsSemPresidente, CasasLegislativasReport, CasasSemConvenioReport, InfoCasaLegislativa
from django.views.generic import View
from sigi.apps.casas.forms import PortfolioForm, AtualizaCasaForm
from sigi.apps.casas.models import Orgao, TipoOrgao, Funcionario
from sigi.apps.casas.reports import (CasasLegislativasLabels,
CasasLegislativasLabelsSemPresidente)
from sigi.apps.contatos.models import (UnidadeFederativa, Municipio,
Mesorregiao, Microrregiao)
from sigi.apps.ocorrencias.models import Ocorrencia
from sigi.apps.parlamentares.reports import ParlamentaresLabels
from sigi.apps.contatos.models import UnidadeFederativa, Mesorregiao, Microrregiao
from sigi.apps.casas.forms import PortfolioForm
from django.contrib.auth.decorators import login_required
from sigi.apps.servicos.models import TipoServico
from sigi.apps.servidores.models import Servidor
from sigi.apps.ocorrencias.models import Ocorrencia
from django.db.models import Count, Q
from django.http.response import JsonResponse
from sigi.shortcuts import render_to_pdf
class importa_casas(View):
errors = []
total_registros = 0
TIPO = 'tipo'
MUNICIPIO = 'municipio'
UF = 'uf'
ORGAO_ENDERECO = 'orgao_endereco'
ORGAO_BAIRRO = 'orgao_bairro'
ORGAO_CEP = 'orgao_cep'
ORGAO_EMAIL = 'orgao_email'
ORGAO_PORTAL = 'orgao_portal'
ORGAO_TELEFONES = 'orgao_telefones'
PRESIDENTE_NOME = 'presidente_nome'
PRESIDENTE_DATA_NASCIMENTO = 'presidente_data_nascimento'
PRESIDENTE_TELEFONES = 'presidente_telefones'
PRESIDENTE_EMAILS = 'presidente_emails'
PRESIDENTE_ENDERECO = 'presidente_endereco'
PRESIDENTE_MUNICIPIO = 'presidente_municipio'
PRESIDENTE_BAIRRO = 'presidente_bairro'
PRESIDENTE_CEP = 'presidente_cep'
PRESIDENTE_REDES_SOCIAIS = 'presidente_redes_sociais'
SERVIDOR_NOME = 'contato_nome'
SERVIDOR_DATA_NASCIMENTO = 'contato_data_nascimento'
SERVIDOR_TELEFONES = 'contato_telefones'
SERVIDOR_EMAILS = 'contato_emails'
SERVIDOR_ENDERECO = 'contato_endereco'
SERVIDOR_MUNICIPIO = 'contato_municipio'
SERVIDOR_BAIRRO = 'contato_bairro'
SERVIDOR_CEP = 'contato_cep'
SERVIDOR_REDES_SOCIAIS = 'contato_redes_sociais'
ERROS = 'erros_importacao'
fieldnames = [TIPO, MUNICIPIO, UF, ORGAO_ENDERECO, ORGAO_BAIRRO, ORGAO_CEP,
ORGAO_EMAIL, ORGAO_PORTAL, ORGAO_TELEFONES, PRESIDENTE_NOME,
PRESIDENTE_DATA_NASCIMENTO, PRESIDENTE_TELEFONES,
PRESIDENTE_EMAILS, PRESIDENTE_ENDERECO, PRESIDENTE_MUNICIPIO,
PRESIDENTE_BAIRRO, PRESIDENTE_CEP, PRESIDENTE_REDES_SOCIAIS,
SERVIDOR_NOME, SERVIDOR_DATA_NASCIMENTO, SERVIDOR_TELEFONES,
SERVIDOR_EMAILS, SERVIDOR_ENDERECO, SERVIDOR_MUNICIPIO,
SERVIDOR_BAIRRO, SERVIDOR_CEP, SERVIDOR_REDES_SOCIAIS, ERROS,]
ID_FIELDS = {TIPO, MUNICIPIO, UF}
ORGAO_FIELDS = {
ORGAO_ENDERECO: 'logradouro',
ORGAO_BAIRRO: 'bairro',
ORGAO_CEP: 'cep',
ORGAO_EMAIL: 'email',
ORGAO_PORTAL: 'pagina_web',
ORGAO_TELEFONES: 'telefones',
}
PRESIDENTE_FIELDS = {
PRESIDENTE_NOME: 'nome',
PRESIDENTE_DATA_NASCIMENTO: 'data_nascimento',
PRESIDENTE_TELEFONES: 'nota',
PRESIDENTE_EMAILS: 'email',
PRESIDENTE_ENDERECO: 'endereco',
PRESIDENTE_MUNICIPIO: 'municipio_id',
PRESIDENTE_BAIRRO: 'bairro',
PRESIDENTE_CEP: 'cep',
PRESIDENTE_REDES_SOCIAIS: 'redes_sociais',
}
# @param qs: queryset
# @param o: (int) number of order field
SERVIDOR_FIELDS = {
SERVIDOR_NOME: 'nome',
SERVIDOR_DATA_NASCIMENTO: 'data_nascimento',
SERVIDOR_TELEFONES: 'nota',
SERVIDOR_EMAILS: 'email',
SERVIDOR_ENDERECO: 'endereco',
SERVIDOR_MUNICIPIO: 'municipio_id',
SERVIDOR_BAIRRO: 'bairro',
SERVIDOR_CEP: 'cep',
SERVIDOR_REDES_SOCIAIS: 'redes_sociais',
}
def get(self, request):
if not request.user.is_superuser:
return HttpResponseForbidden()
form = AtualizaCasaForm()
return render(request, 'casas/importar.html', {'form': form})
def post(self, request):
if not request.user.is_superuser:
return HttpResponseForbidden()
form = AtualizaCasaForm(request.POST, request.FILES)
if form.is_valid():
file = form.cleaned_data['arquivo']
reader = csv.DictReader(file)
if not self.ID_FIELDS.issubset(reader.fieldnames):
return render(
request,
'casas/importar.html',
{'form': form, 'error': _(u"O arquivo não possui algum dos "
u"campos obrigatórios")}
)
if self.importa(reader):
# Importação concluída com êxito
return render(
request,
'casas/importar_result.html',
{'file_name': file.name, 'total': self.total_registros,
'com_erros': 0}
)
else:
# Importado com erros
file_name = "casas-erros-{:%Y-%m-%d-%H%M}.csv".format(
datetime.now())
fields = self.fieldnames
for f in reader.fieldnames:
if f not in fields:
fields.append(f)
with open(settings.MEDIA_ROOT+'/temp/'+file_name, "w+") as f:
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
writer.writerows(self.errors)
return render(
request,
'casas/importar_result.html',
{'file_name': file.name, 'result_file': file_name,
'total': self.total_registros,
'com_erros': len(self.errors)}
)
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = (
'attachment; filename="somefilename.csv"')
return response
else:
return render(
request,
'casas/importar.html',
{'form': form, 'error': u"Erro no preenchimento do formulário."}
)
# Atualiza ou cria funcionário
def funcionario_update(self, setor, fields, orgao, reg):
field_nome = (self.PRESIDENTE_NOME if setor == 'presidente' else
self.SERVIDOR_NOME)
# Se não tem nome do contato (ou presidente), então não há nada a
# atualizar. Volta o reg inalterado.
if field_nome not in reg:
return reg
funcionario = orgao.funcionario_set.filter(
setor=setor,
nome__iexact=reg[field_nome].strip()
)
if funcionario.count() == 0:
funcionario = Funcionario(
casa_legislativa=orgao,
nome=reg[field_nome].strip(),
setor=setor
)
else:
funcionario = funcionario.first() #HACK: Sempre atualiza o primeiro
for key in fields:
field_name = fields[key]
if key in reg:
value = reg[key].strip()
else:
value = ""
if value != "":
if field_name == 'municipio_id':
if ',' in value:
municipio, uf = value.split(',')
else:
municipio = value
uf = reg[self.UF]
try:
value = Municipio.objects.get(
nome__iexact=municipio.strip(),
uf__sigla=uf.strip()).pk
except:
value = None
reg[self.ERROS].append(
"Impossivel identificar o Municipio de "
"residencia do {contato}".format(
contato="Presidente" if setor == 'presidente'
else "Contato")
)
continue
if field_name == 'redes_sociais':
value = value.replace(" ", "\r")
if field_name == 'data_nascimento':
sd = value.split('/')
if len(sd) < 3:
reg[self.ERROS].append(
"Data de nascimento do {contato} esta em um "
"formato nao reconhecido. Use DD/MM/AAAA".format(
contato="Presidente" if setor == 'presidente'
else "Contato"
)
)
continue
else:
value = "{ano}-{mes}-{dia}".format(
ano=sd[2],
mes=sd[1],
dia=sd[0]
)
if value != getattr(funcionario, field_name):
setattr(funcionario, field_name, value)
try:
funcionario.save()
except Exception as e:
reg[self.ERROS].append(
"Erro salvando {contato}: '{message}'".format(
message=e.message,
contato="Presidente" if setor == 'presidente'
else "Contato")
)
return reg
def importa(self, reader):
self.errors = []
self.total_registros = 0
for reg in reader:
self.total_registros += 1
reg[self.ERROS] = []
orgao = Orgao.objects.filter(
tipo__sigla=reg[self.TIPO],
municipio__nome=reg[self.MUNICIPIO],
municipio__uf__sigla=reg[self.UF]
)
if orgao.count() == 0:
reg[self.ERROS].append("Nao existe orgao com esta identificacao")
self.errors.append(reg)
continue
elif orgao.count() > 1:
reg[self.ERROS].append("Existem {count} orgaos com esta mesma "
"identificacao").format(count=orgao.count())
self.errors.append(reg)
continue
else:
orgao = orgao.get()
# Atualiza os dados do órgão
for key in self.ORGAO_FIELDS:
field_name = self.ORGAO_FIELDS[key]
if key in reg:
value = reg[key].strip()
if key == self.ORGAO_TELEFONES:
for numero in value.split(";"):
numero = numero.strip()
try:
orgao.telefones.update_or_create(numero=numero)
except:
reg[self.ERROS].append(
'Telefone {numero} não foi '
'atualizado'.format(numero=numero)
)
elif value != "" and value != getattr(orgao, field_name):
setattr(orgao, field_name, value)
try:
orgao.save()
except Exception as e:
reg[self.ERROS].append(
"Erro salvando o orgao: '{message}'".format(
message=e.message)
)
# Atualiza o presidente
reg = self.funcionario_update("presidente", self.PRESIDENTE_FIELDS,
orgao, reg)
# Atualiza o contato
reg = self.funcionario_update("outros", self.SERVIDOR_FIELDS,
orgao, reg)
if len(reg[self.ERROS]) > 0:
self.errors.append(reg)
return len(self.errors) == 0
# @param qs: queryset
# @param o: (int) number of order field
def query_ordena(qs, o):
from sigi.apps.casas.admin import CasaLegislativaAdmin
list_display = CasaLegislativaAdmin.list_display
from sigi.apps.casas.admin import OrgaoAdmin
list_display = OrgaoAdmin.list_display
order_fields = []
for order_number in o.split('.'):
@ -51,6 +340,38 @@ def get_for_qs(get, qs):
if str(k) not in ('page', 'pop', 'q', '_popup', 'o', 'ot'):
kwargs[str(k)] = v
if 'convenio' in kwargs:
if kwargs['convenio'] == 'SC':
qs = qs.filter(convenio=None)
elif kwargs['convenio'] == 'CC':
qs = qs.exclude(convenio=None)
else:
qs = qs.filter(convenio__projeto_id=kwargs['convenio'])
qs = qs.distinct('municipio__uf__nome', 'nome')
del(kwargs['convenio'])
if 'servico' in kwargs:
if kwargs['servico'] == 'SS':
qs = qs.filter(servico=None)
elif kwargs['servico'] == 'CS':
qs = qs.exclude(servico=None).filter(
servico__data_desativacao__isnull=True)
elif kwargs['servico'] == 'CR':
qs = qs.exclude(servico__tipo_servico__modo='H') \
.exclude(servico=None)
elif kwargs['servico'] == 'CH':
qs = qs.filter(
servico__tipo_servico__modo='H',
servico__data_desativacao__isnull=True
)
else:
qs = qs.filter(servico__tipo_servico_id=kwargs['servico'])
qs = qs.distinct('municipio__uf__nome', 'nome')
del(kwargs['servico'])
qs = qs.filter(**kwargs)
if 'o' in get:
qs = query_ordena(qs, get['o'])
@ -64,9 +385,9 @@ def carrinhoOrGet_for_qs(request):
"""
if 'carrinho_casas' in request.session:
ids = request.session['carrinho_casas']
qs = CasaLegislativa.objects.filter(pk__in=ids)
qs = Orgao.objects.filter(pk__in=ids)
else:
qs = CasaLegislativa.objects.all()
qs = Orgao.objects.all()
if request.GET:
qs = get_for_qs(request.GET, qs)
return qs
@ -85,6 +406,7 @@ def adicionar_casas_carrinho(request, queryset=None, id=None):
lista.append(id)
request.session['carrinho_casas'] = lista
@login_required
def visualizar_carrinho(request):
@ -117,12 +439,14 @@ def visualizar_carrinho(request):
}
)
@login_required
def excluir_carrinho(request):
if 'carrinho_casas' in request.session:
del request.session['carrinho_casas']
return HttpResponseRedirect('.')
@login_required
def deleta_itens_carrinho(request):
if request.method == 'POST':
@ -139,6 +463,7 @@ def deleta_itens_carrinho(request):
return HttpResponseRedirect('.')
@login_required
def labels_report(request, id=None, tipo=None, formato='3x9_etiqueta'):
""" TODO: adicionar suporte para resultado de pesquisa do admin.
@ -154,7 +479,7 @@ def labels_report(request, id=None, tipo=None, formato='3x9_etiqueta'):
return labels_report_sem_presidente(request, id, formato)
if id:
qs = CasaLegislativa.objects.filter(pk=id)
qs = Orgao.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
@ -168,6 +493,7 @@ def labels_report(request, id=None, tipo=None, formato='3x9_etiqueta'):
return response
@login_required
def labels_report_parlamentar(request, id=None, formato='3x9_etiqueta'):
""" TODO: adicionar suporte para resultado de pesquisa do admin.
@ -178,7 +504,7 @@ def labels_report_parlamentar(request, id=None, formato='3x9_etiqueta'):
formato = request.POST['tamanho_etiqueta']
if id:
legislaturas = [c.legislatura_set.latest('data_inicio') for c in CasaLegislativa.objects.filter(pk__in=id, legislatura__id__isnull=False).distinct()]
legislaturas = [c.legislatura_set.latest('data_inicio') for c in Orgao.objects.filter(pk__in=id, legislatura__id__isnull=False).distinct()]
mandatos = reduce(lambda x, y: x | y, [l.mandato_set.all() for l in legislaturas])
parlamentares = [m.parlamentar for m in mandatos]
qs = parlamentares
@ -203,12 +529,12 @@ def carrinhoOrGet_for_parlamentar_qs(request):
"""
if 'carrinho_casas' in request.session:
ids = request.session['carrinho_casas']
legislaturas = [c.legislatura_set.latest('data_inicio') for c in CasaLegislativa.objects.filter(pk__in=ids, legislatura__id__isnull=False).distinct()]
legislaturas = [c.legislatura_set.latest('data_inicio') for c in Orgao.objects.filter(pk__in=ids, legislatura__id__isnull=False).distinct()]
mandatos = reduce(lambda x, y: x | y, [l.mandato_set.all() for l in legislaturas])
parlamentares = [m.parlamentar for m in mandatos]
qs = parlamentares
else:
legislaturas = [c.legislatura_set.latest('data_inicio') for c in CasaLegislativa.objects.all().distinct()]
legislaturas = [c.legislatura_set.latest('data_inicio') for c in Orgao.objects.all().distinct()]
mandatos = reduce(lambda x, y: x | y, [l.mandato_set.all() for l in legislaturas])
parlamentares = [m.parlamentar for m in mandatos]
qs = parlamentares
@ -216,13 +542,14 @@ def carrinhoOrGet_for_parlamentar_qs(request):
qs = get_for_qs(request.GET, qs)
return qs
@login_required
def labels_report_sem_presidente(request, id=None, formato='2x5_etiqueta'):
""" TODO: adicionar suporte para resultado de pesquisa do admin.
"""
if id:
qs = CasaLegislativa.objects.filter(pk=id)
qs = Orgao.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
@ -236,6 +563,7 @@ def labels_report_sem_presidente(request, id=None, formato='2x5_etiqueta'):
return response
@login_required
def report(request, id=None, tipo=None):
@ -247,71 +575,47 @@ def report(request, id=None, tipo=None):
return report_complete(request, id)
if id:
qs = CasaLegislativa.objects.filter(pk=id)
qs = Orgao.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
# qs.order_by('municipio__uf','nome')
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
report = CasasLegislativasReport(queryset=qs)
report.generate_by(PDFGenerator, filename=response)
return response
qs = qs.order_by('municipio__uf', 'nome')
context = {'casas': qs, 'title': _(u"Relação de Casas Legislativas")}
return render_to_pdf('casas/report_pdf.html', context)
@login_required
def report_complete(request, id=None):
if id:
qs = CasaLegislativa.objects.filter(pk=id)
qs = Orgao.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
return render_to_pdf('casas/report_complete_pdf.html', {'casas': qs})
# Gera um relatorio para cada casa e concatena os relatorios
cont = 0
canvas = None
quant = qs.count()
if quant > 1:
for i in qs:
cont += 1
# queryset deve ser uma lista
lista = (i,)
if cont == 1:
report = InfoCasaLegislativa(queryset=lista)
canvas = report.generate_by(PDFGenerator, return_canvas=True, filename=response,)
else:
report = InfoCasaLegislativa(queryset=lista)
if cont == quant:
report.generate_by(PDFGenerator, canvas=canvas)
else:
canvas = report.generate_by(PDFGenerator, canvas=canvas, return_canvas=True)
else:
report = InfoCasaLegislativa(queryset=qs)
report.generate_by(PDFGenerator, filename=response)
return response
@login_required
def casas_sem_convenio_report(request):
qs = CasaLegislativa.objects.filter(convenio=None).order_by('municipio__uf', 'nome')
qs = Orgao.objects.filter(convenio=None).order_by('municipio__uf', 'nome')
if request.GET:
qs = get_for_qs(request.GET, qs)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(content_type='application/pdf')
report = CasasSemConvenioReport(queryset=qs)
report.generate_by(PDFGenerator, filename=response)
return response
qs = qs.order_by('municipio__uf', 'nome')
context = {'casas': qs, 'title': _(u"Casas sem convênio")}
return render_to_pdf('casas/report_pdf.html', context)
@login_required
def export_csv(request):
@ -325,18 +629,19 @@ def export_csv(request):
return HttpResponseRedirect('../')
atributos = request.POST.getlist("itens_csv_selected")
atributos2 = [s.encode("utf-8") for s in atributos]
try:
atributos2.insert(atributos2.index(_(u'Município')), _(u'UF'))
atributos.insert(atributos.index(_(u'Município')), _(u'UF'))
except ValueError:
pass
atributos2 = [s.encode("utf-8") for s in atributos]
writer.writerow(atributos2)
for casa in casas:
lista = []
contatos = casa.funcionario_set.filter(setor="contato_interlegis")
contatos = casa.funcionario_set.exclude(nome="")
for atributo in atributos:
if _(u"CNPJ") == atributo:
lista.append(casa.cnpj.encode("utf-8"))
@ -370,19 +675,29 @@ def export_csv(request):
lista.append(casa.total_parlamentares)
elif _(u"Última alteração de endereco") == atributo:
lista.append(casa.ult_alt_endereco)
elif _(u"Servicos SEIT") == atributo:
lista.append(", ".join([s.tipo_servico.nome.encode('utf-8')
for s in casa.servico_set.filter(
data_desativacao__isnull=True)])
)
elif _(u"Nome contato") == atributo:
if contatos and contatos[0].nome:
lista.append(contatos[0].nome.encode("utf-8"))
if contatos:
nomes = u", ".join([c.nome for c in contatos])
lista.append(nomes.encode("utf-8"))
else:
lista.append('')
elif _(u"Cargo contato") == atributo:
if contatos and contatos[0].cargo:
lista.append(contatos[0].cargo.encode("utf-8"))
if contatos:
cargos = u", ".join([c.cargo if c.cargo else u"?"
for c in contatos])
lista.append(cargos.encode("utf-8"))
else:
lista.append('')
elif _(u"Email contato") == atributo:
if contatos and contatos[0].email:
lista.append(contatos[0].email.encode("utf-8"))
if contatos:
emails = u", ".join([c.email if c.email else u"?"
for c in contatos])
lista.append(emails.encode("utf-8"))
else:
lista.append('')
else:
@ -392,9 +707,11 @@ def export_csv(request):
return response
@login_required
def portfolio(request):
page = request.GET.get('page', 1)
tipo = request.GET.get('tipo', None)
regiao = request.GET.get('regiao', None)
uf_id = request.GET.get('uf', None)
meso_id = request.GET.get('meso', None)
@ -404,15 +721,12 @@ def portfolio(request):
data['errors'] = []
data['messages'] = []
data['regioes'] = UnidadeFederativa.REGIAO_CHOICES
data['tipos_casas'] = TipoOrgao.objects.all()
casas = None
gerente_contas = None
gerente = None
if request.method == 'POST':
form = PortfolioForm(data=request.POST)
if form.is_valid():
gerente_contas = form.cleaned_data['gerente_contas']
else:
data['errors'].append(_(u"Dados inválidos"))
if tipo:
data['tipo'] = tipo
if micro_id:
microrregiao = get_object_or_404(Microrregiao, pk=micro_id)
@ -425,9 +739,14 @@ def portfolio(request):
data['ufs'] = UnidadeFederativa.objects.filter(regiao=uf.regiao)
data['mesorregioes'] = uf.mesorregiao_set.all()
data['microrregioes'] = mesorregiao.microrregiao_set.all()
data['form'] = PortfolioForm(_(u'Atribuir casas da microrregiao %s para') % (unicode(microrregiao),))
data['querystring'] = 'micro=%s' % (microrregiao.pk,)
casas = CasaLegislativa.objects.filter(municipio__microrregiao=microrregiao)
data['form'] = PortfolioForm(
_(u'Atribuir casas da microrregiao {name} para').format(
name=unicode(microrregiao))
)
data['querystring'] = 'micro={0}'.format(microrregiao.pk)
casas = Orgao.objects.filter(
municipio__microrregiao=microrregiao
)
elif meso_id:
mesorregiao = get_object_or_404(Mesorregiao, pk=meso_id)
uf = mesorregiao.uf
@ -437,38 +756,74 @@ def portfolio(request):
data['ufs'] = UnidadeFederativa.objects.filter(regiao=uf.regiao)
data['mesorregioes'] = uf.mesorregiao_set.all()
data['microrregioes'] = mesorregiao.microrregiao_set.all()
data['form'] = PortfolioForm(_(u'Atribuir casas da mesorregiao %s para') % (unicode(mesorregiao),))
data['querystring'] = 'meso=%s' % (mesorregiao.pk,)
casas = CasaLegislativa.objects.filter(municipio__microrregiao__mesorregiao=mesorregiao)
data['form'] = PortfolioForm(
_(u'Atribuir casas da mesorregiao {name} para').format(
name=unicode(mesorregiao)))
data['querystring'] = 'meso={0}'.format(mesorregiao.pk)
casas = Orgao.objects.filter(
municipio__microrregiao__mesorregiao=mesorregiao
)
elif uf_id:
uf = get_object_or_404(UnidadeFederativa, pk=uf_id)
data['regiao'] = uf.regiao
data['uf_id'] = uf.pk
data['ufs'] = UnidadeFederativa.objects.filter(regiao=uf.regiao)
data['mesorregioes'] = uf.mesorregiao_set.all()
data['form'] = PortfolioForm(_(u'Atribuir casas do estado %s para') % (unicode(uf),))
data['querystring'] = 'uf=%s' % (uf.pk,)
casas = CasaLegislativa.objects.filter(municipio__uf=uf)
data['form'] = PortfolioForm(
_(u'Atribuir casas do estado {name} para').format(
name=unicode(uf)))
data['querystring'] = 'uf={0}'.format(uf.pk)
casas = Orgao.objects.filter(municipio__uf=uf)
elif regiao:
data['regiao'] = regiao
data['ufs'] = UnidadeFederativa.objects.filter(regiao=regiao)
data['form'] = PortfolioForm(_(u'Atribuir casas da região %s para') % [x[1] for x in UnidadeFederativa.REGIAO_CHOICES if x[0]==regiao][0])
data['querystring'] = 'regiao=%s' % (regiao,)
casas = CasaLegislativa.objects.filter(municipio__uf__regiao=regiao)
data['form'] = PortfolioForm(
_(u'Atribuir casas da região {name} para').format(
name=[x[1] for x in UnidadeFederativa.REGIAO_CHOICES if
x[0] == regiao][0]))
data['querystring'] = 'regiao={0}'.format(regiao)
casas = Orgao.objects.filter(municipio__uf__regiao=regiao)
if casas:
if gerente_contas:
count = casas.update(gerente_contas=gerente_contas)
data['messages'].append(ungettext(
u"%(count)s casa atribuída para %(name)s",
u"%(count)s casas atribuídas para %(name)s",
count) % {'count': count, 'name': unicode(gerente_contas)})
casas = casas.order_by('municipio__uf', 'municipio__microrregiao__mesorregiao',
casas = casas.order_by('municipio__uf',
'municipio__microrregiao__mesorregiao',
'municipio__microrregiao', 'municipio')
casas.prefetch_related('municipio', 'municipio__uf', 'municipio__microrregiao',
'municipio__microrregiao__mesorregiao', 'gerente_contas')
casas.prefetch_related('municipio', 'municipio__uf',
'municipio__microrregiao',
'municipio__microrregiao__mesorregiao',
'gerentes_interlegis')
if tipo:
casas = casas.filter(tipo__sigla=tipo)
data['querystring'] += "&tipo={0}".format(tipo)
if request.method == 'POST':
form = PortfolioForm(data=request.POST)
if form.is_valid():
gerente = form.cleaned_data['gerente']
acao = form.cleaned_data['acao']
count = casas.count()
if acao == 'ADD':
gerente.casas_que_gerencia.add(*casas)
data['messages'].append(ungettext(
u"{count} casa adicionada para {gerente}",
u"{count} casas adicionadas para {gerente}",
count).format(count=count,gerente=gerente.nome_completo)
)
elif acao == 'DEL':
gerente.casas_que_gerencia.remove(*casas)
data['messages'].append(ungettext(
u"{count} casa removida de {gerente}",
u"{count} casas removidas de {gerente}",
count).format(count=count,gerente=gerente.nome_completo)
)
else:
data['errors'].append(_(u"Ação não definida"))
else:
data['errors'].append(_(u"Dados inválidos"))
paginator = Paginator(casas, 30)
try:
@ -602,13 +957,14 @@ def casas_carteira(request, casas, context):
return casas, context
@login_required
def painel_relacionamento(request):
page = request.GET.get('page', 1)
snippet = request.GET.get('snippet', '')
seletor = request.GET.get('s', None)
servidor = request.GET.get('servidor', None)
format = request.GET.get('f', 'html')
fmt = request.GET.get('f', 'html')
if servidor is None:
gerente = request.user.servidor
@ -621,7 +977,7 @@ def painel_relacionamento(request):
casas = gerente.casas_que_gerencia.all()
if gerente is None or not casas.exists():
casas = CasaLegislativa.objects.exclude(gerente_contas=None)
casas = Orgao.objects.exclude(gerentes_interlegis=None)
gerente = None
tipos_servico = TipoServico.objects.all()
@ -650,7 +1006,7 @@ def painel_relacionamento(request):
context['page_obj'] = pagina
if snippet == 'lista':
if format == 'csv':
if fmt == 'csv':
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=casas.csv'
writer = csv.writer(response)
@ -660,7 +1016,7 @@ def painel_relacionamento(request):
_(u"Estado").encode('utf8'),
_(u"Mesorregião").encode('utf8'),
_(u"Microrregião").encode('utf8'),
_(u"Gerente de relacionamento").encode('utf8'),
_(u"Gerentes Interlegis").encode('utf8'),
_(u"Serviços").encode('utf8'),
])
for c in casas:
@ -670,7 +1026,7 @@ def painel_relacionamento(request):
c.municipio.uf.sigla.encode('utf8'),
c.municipio.microrregiao.mesorregiao.nome.encode('utf8'),
c.municipio.microrregiao.nome.encode('utf8'),
c.gerente_contas.nome_completo.encode('utf8'),
c.lista_gerentes(fmt='lista').encode('utf8'),
(u", ".join([s.tipo_servico.nome for s in c.servico_set.filter(data_desativacao__isnull=True)])).encode('utf8'),
])
return response
@ -679,3 +1035,65 @@ def painel_relacionamento(request):
return render(request, 'casas/resumo_carteira_snippet.html', context)
return render(request, 'casas/painel.html', context)
@login_required
def gerentes_interlegis(request):
formato = request.GET.get('fmt', 'html')
inclui_casas = (request.GET.get('casas', 'no') == 'yes')
gerentes = Servidor.objects.exclude(
casas_que_gerencia=None).select_related('casas_que_gerencia')
dados = []
for gerente in gerentes:
row = {'gerente': gerente, 'ufs': []}
for uf in (gerente.casas_que_gerencia.distinct('municipio__uf__sigla')
.order_by('municipio__uf__sigla')
.values_list('municipio__uf__sigla', 'municipio__uf__nome')
):
row['ufs'].append((
uf[0],
uf[1],
gerente.casas_que_gerencia.filter(municipio__uf__sigla=uf[0])
))
dados.append(row)
if formato == 'pdf':
return render_to_pdf(
'casas/gerentes_interlegis_pdf.html',
{'gerentes': dados}
)
elif formato == 'csv':
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = ('attachment; '
'filename="gerentes_interlegis.csv"')
fieldnames = ['gerente', 'total_casas', 'uf', 'total_casas_uf']
if inclui_casas:
fieldnames.append('casa_legislativa')
writer = csv.DictWriter(response, fieldnames=fieldnames)
writer.writeheader()
for linha in dados:
rec = {
'gerente': linha['gerente'].nome_completo.encode('utf8'),
'total_casas': linha['gerente'].casas_que_gerencia.count()
}
for uf in linha['ufs']:
rec['uf'] = uf[1].encode('utf8')
rec['total_casas_uf'] = uf[2].count()
if inclui_casas:
for casa in uf[2]:
rec['casa_legislativa'] = casa.nome.encode('utf8')
writer.writerow(rec)
rec['gerente'] = ''
rec['total_casas'] = ''
rec['uf'] = ''
rec['total_casas_uf'] = ''
else:
writer.writerow(rec)
rec['gerente'] = ''
rec['total_casas'] = ''
return response
return render(
request,
'casas/gerentes_interlegis.html',
{'gerentes': dados}
)

39
sigi/apps/contatos/migrations/0003_auto_20210416_0841.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('contatos', '0002_auto_20151104_0810'),
]
operations = [
migrations.AlterField(
model_name='contato',
name='municipio',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='munic\xedpio', blank=True, to='contatos.Municipio', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='endereco',
name='municipio',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='munic\xedpio', blank=True, to='contatos.Municipio', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='municipio',
name='microrregiao',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Microrregi\xe3o', blank=True, to='contatos.Microrregiao', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='municipio',
name='uf',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='UF', to='contatos.UnidadeFederativa'),
preserve_default=True,
),
]

24
sigi/apps/contatos/migrations/0004_auto_20210611_0946.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('contatos', '0003_auto_20210416_0841'),
]
operations = [
migrations.AlterModelOptions(
name='microrregiao',
options={'ordering': ('nome',), 'verbose_name': 'Microrregi\xe3o', 'verbose_name_plural': 'Microrregi\xf5es'},
),
migrations.AlterField(
model_name='unidadefederativa',
name='regiao',
field=models.CharField(max_length=2, verbose_name='regi\xe3o', choices=[(b'CO', 'Centro-Oeste'), (b'NE', 'Nordeste'), (b'NO', 'Norte'), (b'SD', 'Sudeste'), (b'SL', 'Sul')]),
preserve_default=True,
),
]

54
sigi/apps/contatos/models.py

@ -13,11 +13,11 @@ class UnidadeFederativa(models.Model):
""" Modelo que representa um estado brasileiro
"""
REGIAO_CHOICES = (
('SL', _(u'Sul')),
('SD', _(u'Sudeste')),
('CO', _(u'Centro-Oeste')),
('NE', _(u'Nordeste')),
('NO', _(u'Norte')),
('SD', _(u'Sudeste')),
('SL', _(u'Sul')),
)
codigo_ibge = models.PositiveIntegerField(
u'código IBGE',
@ -51,7 +51,11 @@ class Mesorregiao(models.Model):
unique=True,
help_text=_(u'Código da mesorregião segundo o IBGE')
)
uf = models.ForeignKey(UnidadeFederativa, verbose_name=_(u'UF'))
uf = models.ForeignKey(
UnidadeFederativa,
on_delete=models.CASCADE,
verbose_name=_(u'UF')
)
nome = models.CharField(_(u"Nome mesorregião"), max_length=100)
# Campo de busca em caixa baixa sem acento
search_text = SearchField(field_names=['nome'])
@ -70,13 +74,16 @@ class Microrregiao(models.Model):
unique=True,
help_text=_(u'Código da microrregião segundo o IBGE')
)
mesorregiao = models.ForeignKey(Mesorregiao)
mesorregiao = models.ForeignKey(
Mesorregiao,
on_delete=models.CASCADE
)
nome = models.CharField(_(u"Nome microrregião"), max_length=100)
# Campo de busca em caixa baixa sem acento
search_text = SearchField(field_names=['nome'])
class Meta:
ordering = ('mesorregiao', 'nome')
ordering = ('nome',)
verbose_name, verbose_name_plural = _(u'Microrregião'), _(u'Microrregiões')
def __unicode__(self):
@ -93,7 +100,13 @@ class Municipio(models.Model):
help_text=_(u'Código do município segundo IBGE.')
)
microrregiao = models.ForeignKey(Microrregiao, verbose_name=_(u'Microrregião'), blank=True, null=True)
microrregiao = models.ForeignKey(
Microrregiao,
on_delete=models.PROTECT,
verbose_name=_(u'Microrregião'),
blank=True,
null=True
)
# codio designado pelo Tribunal Superior Eleitoral
codigo_tse = models.PositiveIntegerField(
@ -104,7 +117,11 @@ class Municipio(models.Model):
)
nome = models.CharField(max_length=50)
search_text = SearchField(field_names=[_(u'nome'), _(u'uf')])
uf = models.ForeignKey(UnidadeFederativa, verbose_name=_(u'UF'))
uf = models.ForeignKey(
UnidadeFederativa,
on_delete=models.PROTECT,
verbose_name=_(u'UF')
)
# verdadeiro se o município é capital do estado
is_capital = models.BooleanField(_(u'capital'), default=False)
populacao = models.PositiveIntegerField(_(u'população'))
@ -173,10 +190,13 @@ class Telefone(models.Model):
ult_alteracao = models.DateTimeField(_(u'Última alteração'), null=True, blank=True, editable=False, auto_now=True)
# guarda o tipo do objeto (classe) vinculado a esse registro
content_type = models.ForeignKey(ContentType)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
# identificador do registro na classe vinculado a esse registro
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
content_object = generic.GenericForeignKey(
'content_type',
'object_id',
)
class Meta:
ordering = ('numero',)
@ -200,16 +220,20 @@ class Contato(models.Model):
municipio = models.ForeignKey(
Municipio,
on_delete=models.SET_NULL,
verbose_name=_(u'município'),
blank=True,
null=True,
)
# guarda o tipo do objeto (classe) vinculado a esse registro
content_type = models.ForeignKey(ContentType)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
# identificador do registro na classe vinculado a esse registro
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
content_object = generic.GenericForeignKey(
'content_type',
'object_id',
)
class Meta:
ordering = ('nome',)
@ -291,6 +315,7 @@ class Endereco(models.Model):
municipio = models.ForeignKey(
Municipio,
on_delete=models.SET_NULL,
verbose_name=_(u'município'),
blank=True,
null=True,
@ -298,10 +323,13 @@ class Endereco(models.Model):
municipio.uf_filter = True
# guarda o tipo do objeto (classe) vinculado a esse registro
content_type = models.ForeignKey(ContentType)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
# identificador do registro na classe vinculado a esse registro
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
content_object = generic.GenericForeignKey(
'content_type',
'object_id',
)
class Meta:
ordering = ('logradouro', 'numero')

116
sigi/apps/convenios/admin.py

@ -4,29 +4,29 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.utils.translation import ugettext as _
from geraldo.generators import PDFGenerator
from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo, Tramitacao
from sigi.apps.convenios.models import (Projeto, StatusConvenio,
TipoSolicitacao, Convenio,
EquipamentoPrevisto, Anexo, Tramitacao)
from sigi.apps.convenios.reports import ConvenioReport
from sigi.apps.convenios.views import adicionar_convenios_carrinho
from sigi.apps.utils import queryset_ascii
from sigi.apps.utils.base_admin import BaseModelAdmin
from sigi.apps.servidores.models import Servidor
from sigi.apps.casas.admin import GerentesInterlegisFilter
class TramitacaoInline(admin.TabularInline):
model = Tramitacao
extra = 1
# class TramitacaoInline(admin.TabularInline):
# model = Tramitacao
# extra = 1
class AnexosInline(admin.TabularInline):
model = Anexo
extra = 2
exclude = ['data_pub', ]
class EquipamentoPrevistoInline(admin.TabularInline):
model = EquipamentoPrevisto
extra = 2
raw_id_fields = ('equipamento',)
# class EquipamentoPrevistoInline(admin.TabularInline):
# model = EquipamentoPrevisto
# extra = 2
# raw_id_fields = ('equipamento',)
class AnexoAdmin(BaseModelAdmin):
date_hierarchy = 'data_pub'
@ -36,30 +36,44 @@ class AnexoAdmin(BaseModelAdmin):
search_fields = ('descricao', 'convenio__id', 'arquivo',
'convenio__casa_legislativa__nome')
class AcompanhaFilter(admin.filters.RelatedFieldListFilter):
def __init__(self, *args, **kwargs):
super(AcompanhaFilter, self).__init__(*args, **kwargs)
servidores = Servidor.objects.filter(
convenio__isnull=False).order_by('nome_completo').distinct()
self.lookup_choices = [(x.id, x) for x in servidores]
class ConvenioAdmin(BaseModelAdmin):
change_list_template = 'convenios/change_list.html'
fieldsets = (
(None,
{'fields': ('casa_legislativa', 'num_processo_sf', 'num_convenio', 'projeto', 'observacao')}
{'fields': ('casa_legislativa', 'num_processo_sf', 'num_convenio',
'projeto', 'data_sigi',)}
),
(_(u'Datas'),
{'fields': ('data_adesao', 'data_retorno_assinatura',
'data_termo_aceite', 'data_pub_diario',
'data_devolucao_via', 'data_postagem_correio')}
(_(u"Acompanhamento no gabinete"),
{'fields': ('data_solicitacao', 'data_sigad', 'tipo_solicitacao',
'status', 'acompanha', 'observacao',)}
),
(_(u"Gestão do convênio"),
{'fields': ('servico_gestao', 'servidor_gestao',)}
),
(_(u'Datas - Convenio sem assinatura'),
{'fields': ('data_devolucao_sem_assinatura', 'data_retorno_sem_assinatura',)}
(_(u'Datas'),
{'fields': ('data_retorno_assinatura', 'duracao',
'data_pub_diario',)}
),
)
readonly_fields = ('data_sigi',)
actions = ['adicionar_convenios']
inlines = (TramitacaoInline, AnexosInline, EquipamentoPrevistoInline)
inlines = (AnexosInline,)
list_display = ('num_convenio', 'casa_legislativa', 'get_uf',
'data_adesao', 'data_retorno_assinatura', 'data_pub_diario', 'data_termo_aceite',
'projeto',
)
'status_convenio', 'link_sigad', 'data_retorno_assinatura',
'duracao', 'projeto', 'status', 'acompanha',)
list_display_links = ('num_convenio', 'casa_legislativa',)
list_filter = ('projeto', 'casa_legislativa__municipio__uf', 'casa_legislativa', 'conveniada', 'equipada')
list_filter = ('status', ('acompanha', AcompanhaFilter),
('casa_legislativa__gerentes_interlegis',
GerentesInterlegisFilter), 'projeto',
'casa_legislativa__tipo', 'conveniada','equipada',
'casa_legislativa__municipio__uf',)
#date_hierarchy = 'data_adesao'
ordering = ('casa_legislativa__tipo__sigla', 'casa_legislativa__municipio__uf', 'casa_legislativa')
raw_id_fields = ('casa_legislativa',)
@ -72,25 +86,43 @@ class ConvenioAdmin(BaseModelAdmin):
get_uf.short_description = _(u'UF')
get_uf.admin_order_field = 'casa_legislativa__municipio__uf__sigla'
def status_convenio(self, obj):
if obj.pk is None:
return ""
status = obj.get_status()
if status in [u"Vencido", u"Desistência", u"Cancelado"]:
label = r"danger"
elif status == u"Vigente":
label = r"success"
elif status == u"Pendente":
label = r"warning"
else:
label = r"info"
return u'<p class="label label-{label}">{status}</p>'.format(label=label, status=status)
status_convenio.short_description = _(u"Status do convênio")
status_convenio.allow_tags = True
def link_sigad(self, obj):
if obj.pk is None:
return ""
return obj.get_sigad_url()
link_sigad.short_description = _("Processo no Senado")
link_sigad.allow_tags = True
def changelist_view(self, request, extra_context=None):
import re
from sigi.apps.convenios.views import normaliza_data
request.GET._mutable = True
if 'data_retorno_assinatura__gte' in request.GET:
value = request.GET.get('data_retorno_assinatura__gte', '')
if value == '':
del request.GET['data_retorno_assinatura__gte']
elif re.match('^\d*$', value): # Year only
request.GET['data_retorno_assinatura__gte'] = "%s-01-01" % value # Complete with january 1st
elif re.match('^\d*\D\d*$', value): # Year and month
request.GET['data_retorno_assinatura__gte'] = '%s-01' % value # Complete with 1st day of month
if 'data_retorno_assinatura__lte' in request.GET:
value = request.GET.get('data_retorno_assinatura__lte', '')
if value == '':
del request.GET['data_retorno_assinatura__lte']
elif re.match('^\d*$', value): # Year only
request.GET['data_retorno_assinatura__lte'] = "%s-01-01" % value # Complete with january 1st
elif re.match('^\d*\D\d*$', value): # Year and month
request.GET['data_retorno_assinatura__lte'] = '%s-01' % value # Complete with 1st day of month
normaliza_data(request.GET, 'data_retorno_assinatura__gte')
normaliza_data(request.GET, 'data_retorno_assinatura__lte')
normaliza_data(request.GET, 'data_sigad__gte')
normaliza_data(request.GET, 'data_sigad__lte')
normaliza_data(request.GET, 'data_sigi__gte')
normaliza_data(request.GET, 'data_sigi__lte')
normaliza_data(request.GET, 'data_solicitacao__gte')
normaliza_data(request.GET, 'data_solicitacao__lte')
request.GET._mutable = False
return super(ConvenioAdmin, self).changelist_view(
@ -141,5 +173,7 @@ class EquipamentoPrevistoAdmin(BaseModelAdmin):
'equipamento__modelo__modelo', 'equipamento__modelo__tipo__tipo')
admin.site.register(Projeto)
admin.site.register(StatusConvenio)
admin.site.register(TipoSolicitacao)
admin.site.register(Convenio, ConvenioAdmin)
admin.site.register(EquipamentoPrevisto, EquipamentoPrevistoAdmin)

0
sigi/apps/mdl/__init__.py → sigi/apps/convenios/management/__init__.py

0
sigi/apps/mdl/migrations/__init__.py → sigi/apps/convenios/management/commands/__init__.py

26
sigi/apps/metas/management/commands/gera_map_data.py → sigi/apps/convenios/management/commands/duracao_act.py

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.servicos.management.commands.atualiza_uso_servico
# sigi.apps.casas.management.commands.importa_gerentes
#
# Copyright (c) 2012 by Interlegis
# Copyright (c) 2015 by Interlegis
#
# GNU General Public License (GPL)
#
@ -21,15 +21,23 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
from django.core.management.base import BaseCommand
from django.utils.translation import ugettext as _
from sigi.apps.metas.views import gera_map_data_file
from django.core.management.base import BaseCommand, CommandError
from sigi.apps.convenios.models import Projeto, Convenio
class Command(BaseCommand):
help = _(u'Gera arquivo de dados de plotagem do mapa de atuação do Interlegis.')
help = u"""Define a duração de todos os ACT para 60 meses.
* A sigla do Projeto precisa ser ACT;
* O campo duracao precisa estar em branco.
"""
def handle(self, *args, **options):
result = gera_map_data_file(cronjob=True)
self.stdout.write(result + "\n")
self.stdout.write(u"Atualizando ACTs... ")
act = Projeto.objects.get(sigla='ACT')
for conv in Convenio.objects.filter(projeto=act, duracao=None):
conv.duracao = 60
conv.save()
self.stdout.write(u"\tACT {sigad} da Casa {casa} atualizado".format(
sigad=conv.num_processo_sf, casa=conv.casa_legislativa.nome
))
self.stdout.write(u"Pronto!")

20
sigi/apps/convenios/migrations/0002_convenio_duracao.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('convenios', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='convenio',
name='duracao',
field=models.PositiveIntegerField(help_text='Deixar em branco caso a dura\xe7\xe3o seja indefinida', null=True, verbose_name='Dura\xe7\xe3o (meses)', blank=True),
preserve_default=True,
),
]

21
sigi/apps/convenios/migrations/0003_auto_20210406_1945.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('convenios', '0002_convenio_duracao'),
('casas', '0014_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='convenio',
name='casa_legislativa',
field=models.ForeignKey(verbose_name='Casa Legislativa', to='casas.Orgao'),
preserve_default=True,
),
]

78
sigi/apps/convenios/migrations/0004_auto_20210407_1928.py

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('servidores', '0001_initial'),
('convenios', '0003_auto_20210406_1945'),
]
operations = [
migrations.CreateModel(
name='StatusConvenio',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('nome', models.CharField(max_length=100)),
('cancela', models.BooleanField(default=False, verbose_name='Cancela o conv\xeanio')),
],
options={
'ordering': ('nome',),
'verbose_name': 'Estado de convenios',
'verbose_name_plural': 'Estados de convenios',
},
bases=(models.Model,),
),
migrations.AddField(
model_name='convenio',
name='acompanha',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='acompanhado por', blank=True, to='servidores.Servidor', null=True),
preserve_default=True,
),
migrations.AddField(
model_name='convenio',
name='status',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='estado atual', blank=True, to='convenios.StatusConvenio', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='casa_legislativa',
field=models.ForeignKey(verbose_name='\xf3rg\xe3o conveniado', to='casas.Orgao'),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='data_adesao',
field=models.DateField(null=True, verbose_name='aderidas', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='data_retorno_assinatura',
field=models.DateField(help_text='Conv\xeanio firmado.', null=True, verbose_name='conveniadas', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='data_termo_aceite',
field=models.DateField(help_text='Equipamentos recebidos.', null=True, verbose_name='equipadas', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='duracao',
field=models.PositiveIntegerField(help_text='Deixar em branco caso a dura\xe7\xe3o seja indefinida', null=True, verbose_name='dura\xe7\xe3o (meses)', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='observacao',
field=models.TextField(null=True, verbose_name='observa\xe7\xf5es', blank=True),
preserve_default=True,
),
]

26
sigi/apps/convenios/migrations/0005_auto_20210409_0842.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('convenios', '0004_auto_20210407_1928'),
]
operations = [
migrations.AddField(
model_name='convenio',
name='data_sigad',
field=models.DateField(null=True, verbose_name='data de cadastro no SIGAD', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='convenio',
name='data_sigi',
field=models.DateField(auto_now_add=True, verbose_name='data de cadastro no SIGI', null=True),
preserve_default=True,
),
]

33
sigi/apps/convenios/migrations/0006_auto_20210416_0841.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('convenios', '0005_auto_20210409_0842'),
]
operations = [
migrations.AlterField(
model_name='convenio',
name='casa_legislativa',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='\xf3rg\xe3o conveniado', to='casas.Orgao'),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='projeto',
field=models.ForeignKey(to='convenios.Projeto', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
migrations.AlterField(
model_name='tramitacao',
name='unid_admin',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Unidade Administrativa', to='convenios.UnidadeAdministrativa'),
preserve_default=True,
),
]

40
sigi/apps/convenios/migrations/0007_auto_20210416_0918.py

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('convenios', '0006_auto_20210416_0841'),
]
operations = [
migrations.CreateModel(
name='TipoSolicitacao',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('nome', models.CharField(max_length=100)),
],
options={
'ordering': ('nome',),
'verbose_name': 'tipo de solicita\xe7\xe3o',
'verbose_name_plural': 'Tipos de solicita\xe7\xe3o',
},
bases=(models.Model,),
),
migrations.AddField(
model_name='convenio',
name='data_solicitacao',
field=models.DateField(null=True, verbose_name='data do e-mail de solicita\xe7\xe3o', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='convenio',
name='tipo_solicitacao',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='tipo de solicita\xe7\xe3o', blank=True, to='convenios.TipoSolicitacao', null=True),
preserve_default=True,
),
]

34
sigi/apps/convenios/migrations/0008_auto_20210422_1907.py

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('servidores', '0004_auto_20210422_1907'),
('convenios', '0007_auto_20210416_0918'),
]
operations = [
migrations.AddField(
model_name='convenio',
name='servico_gestao',
field=models.ForeignKey(related_name='convenios_geridos', on_delete=django.db.models.deletion.SET_NULL, verbose_name='servi\xe7o de gest\xe3o', blank=True, to='servidores.Servico', null=True),
preserve_default=True,
),
migrations.AddField(
model_name='convenio',
name='servidor_gestao',
field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, verbose_name='servidor de gest\xe3o', blank=True, to='servidores.Servidor', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='convenio',
name='acompanha',
field=models.ForeignKey(related_name='convenios_acompanhados', on_delete=django.db.models.deletion.SET_NULL, verbose_name='acompanhado por', blank=True, to='servidores.Servidor', null=True),
preserve_default=True,
),
]

18
sigi/apps/convenios/migrations/0009_auto_20210611_0946.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('convenios', '0008_auto_20210422_1907'),
]
operations = [
migrations.AlterModelOptions(
name='projeto',
options={'ordering': ('nome',)},
),
]

255
sigi/apps/convenios/models.py

@ -1,13 +1,12 @@
# style="list-style-type: noneo -*- coding: utf-8 -*-
from datetime import datetime
#-*- coding: utf-8 -*-
import re
from datetime import datetime, date
from django.db import models
from django.utils.translation import ugettext as _
from sigi.apps.utils import SearchField
from sigi.apps.servidores.models import Servidor, Servico
class Projeto(models.Model):
""" Modelo para representar os projetos do programa
Interlegis
"""
@ -17,24 +16,44 @@ class Projeto(models.Model):
def __unicode__(self):
return self.sigla
class Meta:
ordering = ('nome',)
class Convenio(models.Model):
class StatusConvenio(models.Model):
nome = models.CharField(max_length=100)
cancela = models.BooleanField(_(u"Cancela o convênio"), default=False)
""" Modelo que representa um convênio do Interlegis
com uma Casa Legislativa.
class Meta:
ordering = ('nome',)
verbose_name = _(u"Estado de convenios")
verbose_name_plural = _(u"Estados de convenios")
Uma Casa Legislativa pode não ter um convênio e sim
apenas uma adesão com o Interlegis, isto é,
não tem compromissos direto com o Interlegis apenas
um pacto de colaboração entre as partes
"""
def __unicode__(self):
return self.nome
class TipoSolicitacao(models.Model):
nome = models.CharField(max_length=100)
class Meta:
ordering = ('nome',)
verbose_name = _(u"tipo de solicitação")
verbose_name_plural = _(u"Tipos de solicitação")
def __unicode__(self):
return self.nome
class Convenio(models.Model):
casa_legislativa = models.ForeignKey(
'casas.CasaLegislativa',
verbose_name=_(u'Casa Legislativa')
'casas.Orgao',
on_delete=models.PROTECT,
verbose_name=_(u'órgão conveniado')
)
# campo de busca em caixa baixa e sem acentos
search_text = SearchField(field_names=['casa_legislativa'])
projeto = models.ForeignKey(_(u'Projeto'))
projeto = models.ForeignKey(
Projeto,
on_delete=models.PROTECT,
)
# numero designado pelo Senado Federal para o convênio
num_processo_sf = models.CharField(
_(u'número do processo SF (Senado Federal)'),
@ -47,24 +66,88 @@ class Convenio(models.Model):
max_length=10,
blank=True
)
data_sigi = models.DateField(
_(u"data de cadastro no SIGI"),
blank=True,
null=True,
auto_now_add=True
)
data_sigad = models.DateField(
_(u"data de cadastro no SIGAD"),
null=True,
blank=True
)
data_solicitacao = models.DateField(
_(u"data do e-mail de solicitação"),
null=True,
blank=True
)
tipo_solicitacao = models.ForeignKey(
TipoSolicitacao,
on_delete=models.PROTECT,
null=True,
blank=True,
verbose_name=_(u"tipo de solicitação")
)
status = models.ForeignKey(
StatusConvenio,
on_delete=models.SET_NULL,
verbose_name=_(u"estado atual"),
null=True,
blank=True
)
acompanha = models.ForeignKey(
Servidor,
on_delete=models.SET_NULL,
related_name='convenios_acompanhados',
verbose_name=_(u"acompanhado por"),
null=True,
blank=True
)
observacao = models.TextField(
_(u"observações"),
null=True,
blank=True,
)
servico_gestao = models.ForeignKey(
Servico,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='convenios_geridos',
verbose_name=_(u"serviço de gestão")
)
servidor_gestao = models.ForeignKey(
Servidor,
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=_(u"servidor de gestão")
)
data_adesao = models.DateField(
_(u'Aderidas'),
_(u'aderidas'),
null=True,
blank=True,
)
data_retorno_assinatura = models.DateField(
_(u'Conveniadas'),
_(u'conveniadas'),
null=True,
blank=True,
help_text=_(u'Convênio firmado.')
)
duracao = models.PositiveIntegerField(
_(u"duração (meses)"),
null=True,
blank=True,
help_text=_(u"Deixar em branco caso a duração seja indefinida")
)
data_pub_diario = models.DateField(
_(u'data da publicação no Diário Oficial'),
null=True,
blank=True
)
data_termo_aceite = models.DateField(
_(u'Equipadas'),
_(u'equipadas'),
null=True,
blank=True,
help_text=_(u'Equipamentos recebidos.')
@ -92,14 +175,64 @@ class Convenio(models.Model):
blank=True,
help_text=_(u'Data do retorno do convênio sem assinatura'),
)
observacao = models.CharField(
null=True,
blank=True,
max_length=100,
)
conveniada = models.BooleanField(default=False)
equipada = models.BooleanField(default=False)
def get_termino_convenio(self):
if (self.data_retorno_assinatura is None or
self.duracao is None):
return None
ano = self.data_retorno_assinatura.year + int(self.duracao / 12)
mes = int(self.data_retorno_assinatura.month + int(self.duracao % 12))
if mes > 12:
ano = ano + 1
mes = mes - 12
dia = self.data_retorno_assinatura.day
while True:
try:
data_fim = date(year=ano, month=mes,day=dia)
break
except:
dia = dia - 1
return data_fim
def get_status(self):
if self.status and self.status.cancela:
return _(u"Cancelado")
if self.data_retorno_assinatura is not None:
if self.duracao is not None:
if date.today() >= self.get_termino_convenio():
return _(u"Vencido")
return _(u"Vigente")
if (self.data_retorno_assinatura is None and
self.data_devolucao_sem_assinatura is None and
self.data_retorno_sem_assinatura is None):
return _(u"Pendente")
if (self.data_devolucao_sem_assinatura is not None or
self.data_retorno_sem_assinatura is not None):
return _(u"Desistência")
return _(u"Indefinido")
def get_sigad_url(self):
m = re.match(
r'(?P<orgao>00100|00200)\.(?P<sequencial>\d{6})/(?P<ano>\d{4})-\d{2}',
self.num_processo_sf
)
if m:
return (r'<a href="https://intra.senado.leg.br/'
r'sigad/novo/protocolo/impressao.asp?area=processo'
r'&txt_numero_orgao={orgao}'
r'&txt_numero_sequencial={sequencial}'
r'&txt_numero_ano={ano}"'
r' target="_blank">{processo}</a>').format(processo=self.num_processo_sf,**m.groupdict())
return self.num_processo_sf
def save(self, *args, **kwargs):
self.conveniada = self.data_retorno_assinatura is not None
self.equipada = self.data_termo_aceite is not None
@ -111,16 +244,47 @@ class Convenio(models.Model):
verbose_name = _(u'convênio')
def __unicode__(self):
if self.data_retorno_assinatura is not None:
return _(u"Convênio nº %(number)s - projeto %(project)s, em %(date)s") % dict(
# if self.data_retorno_assinatura is not None:
# return _(u"Convênio {project} nº {number} assinado em {date}. Status: {status}".format(
# number=self.num_convenio,
# project=self.projeto.sigla,
# date=self.data_retorno_assinatura,
# status=self.get_status()))
# else:
# return _(u"Adesão ao projeto %(project)s, em %(date)s") % dict(
# project=self.projeto.sigla,
# date=self.data_adesao)
if ((self.data_retorno_assinatura is None) and
(self.equipada and self.data_termo_aceite is not None)):
return _(u"Convênio nº {number} - equipada em {date} pelo {project}"
).format(number=self.num_convenio,
date=self.data_termo_aceite.strftime('%d/%m/%Y'),
project=self.projeto.sigla)
elif self.data_retorno_assinatura is None:
return _(u"Convênio nº {number} - adesão ao projeto {project}, "
u"em {date}").format(number=self.num_convenio,
project=self.projeto.sigla,
date=self.data_adesao)
if ((self.data_retorno_assinatura is not None) and not
(self.equipada and self.data_termo_aceite is not None)):
return _(u"Convênio nº {number} - conveniada ao {project} em "
u"{date}. Status: {status}").format(
number=self.num_convenio,
project=self.projeto.sigla,
date=self.data_retorno_assinatura)
else:
return _(u"Adesão ao projeto %(project)s, em %(date)s") % dict(
date=self.data_retorno_assinatura.strftime('%d/%m/%Y'),
status=self.get_status())
if ((self.data_retorno_assinatura is not None) and
(self.equipada and self.data_termo_aceite is not None)):
return _(u"Convẽnio nº {number} - conveniada ao {project} em {date}"
u" e equipada em {equipped_date}. Status: {status}"
).format(number=self.num_convenio,
project=self.projeto.sigla,
date=self.data_adesao)
date=self.data_retorno_assinatura.strftime(
'%d/%m/%Y'),
equipped_date=self.data_termo_aceite.strftime(
'%d/%m/%Y'),
status=self.get_status())
class EquipamentoPrevisto(models.Model):
@ -128,8 +292,15 @@ class EquipamentoPrevisto(models.Model):
disponibilizados para as Casas Legislativas
(foi usado na prmeira etapa do programa)
"""
convenio = models.ForeignKey(Convenio, verbose_name=_(u'convênio'))
equipamento = models.ForeignKey('inventario.Equipamento')
convenio = models.ForeignKey(
Convenio,
on_delete=models.CASCADE,
verbose_name=_(u'convênio')
)
equipamento = models.ForeignKey(
'inventario.Equipamento',
on_delete=models.CASCADE
)
quantidade = models.PositiveSmallIntegerField(default=1)
class Meta:
@ -145,7 +316,11 @@ class Anexo(models.Model):
""" Modelo para giardar os documentos gerados
no processo de convênio
"""
convenio = models.ForeignKey(Convenio, verbose_name=_(u'convênio'))
convenio = models.ForeignKey(
Convenio,
on_delete=models.CASCADE,
verbose_name=_(u'convênio')
)
# caminho no sistema para o documento anexo
arquivo = models.FileField(upload_to='apps/convenios/anexo/arquivo', max_length=500)
descricao = models.CharField(_(u'descrição'), max_length='70')
@ -179,8 +354,16 @@ class Tramitacao(models.Model):
""" Modelo para registrar as vias do processo de convênio e a Unidade
responsável pelo tramite (ex. colher assinaturas do secretário do senado)
"""
convenio = models.ForeignKey(Convenio, verbose_name=_(u'convênio'))
unid_admin = models.ForeignKey(UnidadeAdministrativa, verbose_name=_(u'Unidade Administrativa'))
convenio = models.ForeignKey(
Convenio,
on_delete=models.CASCADE,
verbose_name=_(u'convênio')
)
unid_admin = models.ForeignKey(
UnidadeAdministrativa,
on_delete=models.PROTECT,
verbose_name=_(u'Unidade Administrativa')
)
data = models.DateField()
observacao = models.CharField(
_(u'observação'),

36
sigi/apps/convenios/templates/convenios/carrinho.html

@ -21,8 +21,8 @@
{% block action %}deleta_itens_carrinho{% endblock %}
{% block tabela %}
<table>
<thead>
<table class="table table-striped">
<thead class="thead-dark">
<tr>
{%if not carIsEmpty%}
<th class="sorted ascending"><!-- <input type="checkbox" id="action-toggle" style="display: inline;">-->
@ -38,7 +38,7 @@
</thead>
<tbody>
{% for convenio in paginas.object_list %}
<tr class="{% cycle 'row1' 'row2' %}">
<tr>
{%if not carIsEmpty%}
<th><input type="checkbox" name="_selected_action"
value="{{convenio.id|safe}}" class="action-select" /></th>
@ -56,19 +56,22 @@
{% endblock %}
{% block botoes %}
<div id="tabs">
<ul>
<li><a href="#tabs-1">{% trans 'Relatório' %}</a></li>
<li><a href="#tabs-2">{% trans 'Arquivo CSV (Excel, Calc)' %}</a></li>
<ul class="nav nav-tabs" role="tablist">
<li class="active" role="presentation"><a href="#tabs-1" aria-controls="tabs-1" role="tab" data-toggle="tab">{% trans 'Relatório' %}</a></li>
<li role="presentation"><a href="#tabs-2" aria-controls="tabs-2" role="tab" data-toggle="tab">{% trans 'Arquivo CSV (Excel, Calc)' %}</a></li>
</ul>
<div id="tabs-1">
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tabs-1">
<form action="../reports/{{ query_str }}" method="post">{% csrf_token %}
<fieldset>
<legend>{% trans 'Relatório por' %}</legend>
<ul class="tabs-conteudo">
<li>
<input type="radio" name="filtro_casa" value="cm" checked="checked"/>
<input type="radio" name="filtro_casa" value="tudo" checked="checked"/>
<label>{% trans 'Todos' %}</label>
</li>
<li>
<input type="radio" name="filtro_casa" value="cm"/>
<label>{% trans 'Câmara Municipal' %}</label>
</li>
<li>
@ -90,14 +93,13 @@
</li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Gerar Relatório"></li>
</ul>
<input type="submit" value="Gerar Relatório" type="button" class="btn btn-primary">
</form>
</div>
<div id="tabs-2">
<div role="tabpanel" class="tab-pane" id="tabs-2">
<form action="../csv/{{query_str}}" method="post">{% csrf_token %}
<fieldset><legend>{% trans 'Escolha os atributos para exportar' %}</legend>
<fieldset>
<legend>{% trans 'Escolha os atributos para exportar' %}</legend>
<ul id="sortable" class="tabs-conteudo">
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
@ -149,9 +151,7 @@
</li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Exportar CSV" /></li>
</ul>
<input type="submit" value="Exportar CSV" type="button" class="btn btn-primary"/>
</form>
</div>
</div>

68
sigi/apps/convenios/templates/convenios/change_list.html

@ -1,19 +1,67 @@
{% extends "change_list_with_cart.html" %}
{% load i18n %}
{% block search %}
<div id="toolbar">
<form id="changelist-search" action="" method="get">
<div><!-- DIV needed for valid HTML -->
<label for="searchbar"><img src="/static/admin/img/icon_searchbox.png" alt="Search" /></label>
<input type="text" size="40" name="q" value="" id="searchbar" />
{% block extra_search %}
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Filtro de datas</a>
<p class="navbar-text">Use AAAA, AAAA-MM ou AAAA-MM-DD</p>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form class="navbar-form navbar-left" role="extra-search" id="changelist-extrasearch" action="" method="get">
<div class="form-group">
<label for="data_retorno_assinatura__gte">{% trans 'Conveniadas a partir de' %}:</label>
<input type="text" size="10" name="data_retorno_assinatura__gte" value="" id="data_retorno_assinatura__gte" class="vDateField"/>
<input type="text" class="form-control search-query" size="10" name="data_retorno_assinatura__gte" value="" id="data_retorno_assinatura__gte">
<label for="data_retorno_assinatura__lte">{% trans 'até' %}:</label>
<input type="text" size="10" name="data_retorno_assinatura__lte" value="" id="data_retorno_assinatura__lte" />
<input type="submit" value="Pesquisar" />
{% trans 'Datas podem ser: Um ano (aaaa), um mês (aaaa-mm) ou um dia (aaaa-mm-dd)' %}
<input type="text" class="form-control search-query" size="10" name="data_retorno_assinatura__lte" value="" id="data_retorno_assinatura__lte">
</div>
<div class="form-group">
<label for="data_sigad__gte">{% trans 'SIGAD a partir de' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_sigad__gte" value="" id="data_sigad__gte">
<label for="data_sigad__lte">{% trans 'até' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_sigad__lte" value="" id="data_sigad__lte">
</div>
<div class="form-group">
<label for="data_sigi__gte">{% trans 'SIGI a partir de' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_sigi__gte" value="" id="data_sigi__gte">
<label for="data_sigi__lte">{% trans 'até' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_sigi__lte" value="" id="data_sigi__lte">
</div>
<div class="form-group">
<label for="data_solicitacao__gte">{% trans 'E-mail a partir de' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_solicitacao__gte" value="" id="data_solicitacao__gte">
<label for="data_solicitacao__lte">{% trans 'até' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_solicitacao__lte" value="" id="data_solicitacao__lte">
</div>
<button type="submit" class="btn btn-default navbar-btn ">
<span class="glyphicon glyphicon-search"></span>
</button>
</form>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% comment %}
<form class="navbar-form navbar-right" role="extra-search" id="changelist-extrasearch" action="" method="get">
<div class="form-group"><!-- DIV needed for valid HTML -->
<div class="input-group">
<label for="data_retorno_assinatura__gte">{% trans 'Conveniadas a partir de' %}:</label>
<input type="text" class="form-control search-query" placeholder="YYYY ou YYYY-MM ou YYYY-MM-DD" size="10" name="data_retorno_assinatura__gte" value="" id="data_retorno_assinatura__gte">
<label for="data_retorno_assinatura__lte">{% trans 'até' %}:</label>
<input type="text" class="form-control search-query" placeholder="YYYY ou YYYY-MM ou YYYY-MM-DD" size="10" name="data_retorno_assinatura__lte" value="" id="data_retorno_assinatura__lte">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</div>
</form>
{% endcomment %}
{% endblock %}

43
sigi/apps/convenios/views.py

@ -11,10 +11,15 @@ from django.template import Context, loader
from django.utils.translation import ugettext as _
from geraldo.generators import PDFGenerator
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.convenios.models import Convenio, Projeto
from sigi.apps.convenios.reports import ConvenioPorCMReport, ConvenioPorALReport, ConvenioReportSemAceiteAL, ConvenioReportSemAceiteCM
from sigi.apps.convenios.reports import (ConvenioReport,
ConvenioReportSemAceite,
ConvenioPorCMReport,
ConvenioPorALReport,
ConvenioReportSemAceiteAL,
ConvenioReportSemAceiteCM)
from django.contrib.auth.decorators import login_required
@ -31,10 +36,32 @@ def query_ordena(qs, o, ot):
qs = qs.order_by("-" + aux)
return qs
def normaliza_data(get, nome_param):
import re
if nome_param in get:
value = get.get(nome_param, '')
if value == '':
del get[nome_param]
elif re.match('^\d*$', value): # Year only
# Complete with january 1st
get[nome_param] = "%s-01-01" % value
elif re.match('^\d*\D\d*$', value): # Year and month
# Complete with 1st day of month
get[nome_param] = '%s-01' % value
def get_for_qs(get, qs):
kwargs = {}
ids = 0
get._mutable = True
normaliza_data(get, 'data_retorno_assinatura__gte')
normaliza_data(get, 'data_retorno_assinatura__lte')
normaliza_data(get, 'data_sigad__gte')
normaliza_data(get, 'data_sigad__lte')
normaliza_data(get, 'data_sigi__gte')
normaliza_data(get, 'data_sigi__lte')
normaliza_data(get, 'data_solicitacao__gte')
normaliza_data(get, 'data_solicitacao__lte')
get._mutable = False
for k, v in get.iteritems():
if k not in ['page', 'pop', 'q', '_popup']:
if not k == 'o':
@ -46,7 +73,6 @@ def get_for_qs(get, qs):
ids = 1
break
qs = qs.filter(**kwargs)
if ids:
query = 'id IN (' + kwargs['ids'].__str__() + ')'
qs = Convenio.objects.extra(where=[query])
@ -154,7 +180,7 @@ def report(request, id=None):
tipo = request.POST['filtro_casa']
if 'data_aceite' in request.POST:
data_aceite_has = request.POST['data_aceite']
# Verifica filtro se é por Assembleia
# filtro adicional pela seleção do usuário
if tipo == 'al':
qs = qs.filter(casa_legislativa__tipo__sigla='AL')
# Verifica se é com data de aceite
@ -162,12 +188,17 @@ def report(request, id=None):
report = ConvenioReportSemAceiteAL(queryset=qs)
else:
report = ConvenioPorALReport(queryset=qs)
else:
elif tipo == 'cm':
qs = qs.filter(casa_legislativa__tipo__sigla='CM')
if data_aceite_has == 'nao':
report = ConvenioReportSemAceiteCM(queryset=qs)
else:
report = ConvenioPorCMReport(queryset=qs)
else:
if data_aceite_has == 'nao':
report = ConvenioReportSemAceite(queryset=qs)
else:
report = ConvenioReport(queryset=qs)
response = HttpResponse(content_type='application/pdf')
if report:
@ -249,7 +280,7 @@ def report_regiao(request, regiao='NE'):
projetos = Projeto.objects.all()
camaras = CasaLegislativa.objects.filter(tipo__sigla='CM')
camaras = Orgao.objects.filter(tipo__sigla='CM')
tabelas = list()
# Geral

10
sigi/apps/diagnosticos/forms.py

@ -11,7 +11,7 @@ from django.utils.translation import ugettext as _
from eav.fields import RangeField
from eav.forms import BaseDynamicEntityForm
from sigi.apps.casas.models import CasaLegislativa, Funcionario
from sigi.apps.casas.models import Orgao, Funcionario
from sigi.apps.contatos.models import Telefone
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.diagnosticos.widgets import EavCheckboxSelectMultiple, EavRadioSelect
@ -132,23 +132,23 @@ class DiagnosticoMobileForm(BaseDynamicEntityForm):
self.initial[schema.name] = value
class CasaLegislativaMobileForm(forms.ModelForm):
class OrgaoMobileForm(forms.ModelForm):
data_instalacao = forms.DateField(label=_(u'Data de instalação da Casa Legislativa'), required=False)
data_criacao = forms.DateField()
class Meta:
model = CasaLegislativa
model = Orgao
fields = ('cnpj', 'data_criacao', 'data_instalacao', 'logradouro', 'bairro', 'cep', 'email', 'pagina_web')
def __init__(self, *args, **kwargs):
super(CasaLegislativaMobileForm, self).__init__(*args, **kwargs)
super(OrgaoMobileForm, self).__init__(*args, **kwargs)
self.fields['data_criacao'] = forms.DateField(
label=_(u'Data de criação do Município'),
initial=self.instance.municipio.data_criacao,
required=False)
def save(self, commit=True):
super(CasaLegislativaMobileForm, self).save(commit=True)
super(OrgaoMobileForm, self).save(commit=True)
self.instance.municipio.data_criacao = self.cleaned_data['data_criacao']
if commit:
self.instance.municipio.save()

0
sigi/apps/saberes/__init__.py → sigi/apps/diagnosticos/management/__init__.py

0
sigi/apps/saberes/management/__init__.py → sigi/apps/diagnosticos/management/commands/__init__.py

275
sigi/apps/diagnosticos/management/commands/ls_export.py

@ -0,0 +1,275 @@
# -*- coding: utf-8 -*-
import csv
from collections import OrderedDict
from django.core.management.base import BaseCommand, CommandError
from sigi.apps.casas.models import Funcionario
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.diagnosticos.models import Categoria, Diagnostico, Resposta
DATATYPES = {
'text': 'T',
'float': 'N',
'date': 'D',
'one': 'L',
'many': 'M'
}
class Command(BaseCommand):
help = u"""Exporta dados do diagnóstico para o formato Tab-Separated-Values
do LimeSurvey, conforme documentado em
https://manual.limesurvey.org/Tab_Separated_Value_survey_structure"""
def handle(self, *args, **options):
def normalize(l):
return [s.encode('utf-8') for s in l]
nonum = lambda s: s[s.index(' ')+1:]
avalue = lambda e: ('Y' if e.title == u'Sim' else 'N'
if e.title == u'Não' else e.id)
setores = [(i+1, s[0], s[1]) for i, s in enumerate(
Funcionario.SETOR_CHOICES)]
if len(args) < 2:
raise CommandError(u"Use: ls_export survey_id struct.txt data.csv")
survey_id = args[0]
lsf = csv.writer(open(args[1], 'wb+'), delimiter="\t",
quoting=csv.QUOTE_MINIMAL)
struct = ['id', 'token', 'submitdate', 'lastpage', 'startlanguage',
'seed']
self.stdout.write("Exporting survey structure: ")
# Structure headers #
self.stdout.write("\tStructure headers...", ending=" ")
lsf.writerow(['id', 'related_id', 'class', 'type/scale', 'name',
'relevance', 'text', 'help', 'language', 'validation',
'mandatory', 'other', 'default', 'same_default'])
lsf.writerows([
['', '', 'S', '', 'sid', '', survey_id],
['', '', 'S', '', 'format', '', 'G'],
['', '', 'S', '', 'language', '', 'pt-BR'],
['', '', 'SL', '', 'surveyls_survey_id', '', survey_id, '',
'pt-BR'],
['', '', 'SL', '', 'surveyls_language', '', 'pt-BR', '', 'pt-BR'],
['', '', 'SL', '', 'surveyls_title', '',
u'Diagnóstico PML'.encode('utf-8'), '', 'pt-BR']])
self.stdout.write("Done!")
# Identificação da Casa Legislativa e sua equipe #
self.stdout.write("\tIdentificação da Casa...", ending=" ")
lsf.writerow(normalize(['1000', '', 'G', '', u'Identificação da Casa',
'', '', '', 'pt-BR']))
lsf.writerow(normalize(['1001', '', 'Q', 'L', 'c001q001', '1',
u'Região', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c001q001')
lsf.writerows([normalize(['1001', '', 'A', '0', sigla, '', nome, '',
'pt-BR']) for sigla, nome in UnidadeFederativa.REGIAO_CHOICES])
lsf.writerow(normalize(['1002', '', 'Q', '!', 'c001q002', '1',
u'Estado (UF)', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c001q002')
lsf.writerows([normalize(['1002', '', 'A', '0', u.sigla, '', u.nome, '',
'pt-BR']) for u in UnidadeFederativa.objects.all()])
lsf.writerow(normalize(['1003', '', 'Q', 'S', 'c001q003', '1',
u'Município', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c001q003')
lsf.writerow(normalize(['1004', '', 'Q', 'D', 'c001q004', '1',
u'Data de criação do município', '', 'pt-BR', '', 'Y', 'N', '',
'0']))
struct.append('c001q004')
lsf.writerow(normalize(['1005', '', 'Q', 'S', 'c001q005', '1',
u'Nome da Casa', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c001q005')
lsf.writerow(normalize(['1006', '', 'Q', 'D', 'c001q006', '1',
u'Data de instalação do legislativo', '', 'pt-BR', '', 'Y', 'N', '',
'0']))
struct.append('c001q006')
lsf.writerow(normalize(['1007', '', 'Q', 'T', 'c001q007', '1',
u'Endereço', '', 'pt-BR', '', 'N', 'N', '', '0']))
struct.append('c001q007')
lsf.writerow(normalize(['1008', '', 'Q', 'S', 'c001q008', '1',
u'CNPJ', '', 'pt-BR', '', 'N', 'N', '', '0']))
struct.append('c001q008')
lsf.writerow(normalize(['1009', '', 'Q', 'S', 'c001q009', '1',
u'E-mail principal', '', 'pt-BR', '', 'N', 'N', '', '0']))
struct.append('c001q009')
lsf.writerow(normalize(['1010', '', 'Q', 'S', 'c001q010', '1',
u'Endereço Web', '', 'pt-BR', '', 'N', 'N', '', '0']))
struct.append('c001q010')
lsf.writerow(normalize(['1011', '', 'Q', ';', 'c001q011', '1',
u'Pessoas de contato', '', 'pt-BR', '', 'N', 'N', '', '0']))
lsf.writerow(normalize(['101198', '', 'SQ', '1', 'SQ00101', '', u'Nome',
'', 'pt-BR', '', '', 'N', '', '0']))
lsf.writerow(normalize(['101199', '', 'SQ', '1', 'SQ00102', '',
u'E-mail', '', 'pt-BR', '', '', 'N', '', '0']))
for i, k, v in setores:
lsf.writerow(normalize(['10110{0}'.format(i), '', 'SQ', '',
'SQ1010{0}'.format(i), '1', v, '', 'pt-BR', '', '', 'N',
'', '0']))
struct.extend([
'c001q011_SQ1010{0}_SQ00101'.format(i),
'c001q011_SQ1010{0}_SQ00102'.format(i),
])
self.stdout.write("Done!")
# Equipe de diagnóstico #
self.stdout.write("\tEquipe de diagnóstico...", ending=" ")
lsf.writerow(normalize(['2000', '', 'G', '', u'Equipe de diagnóstico',
'', '', '', 'pt-BR']))
lsf.writerow(normalize(['2001', '', 'Q', 'D', 'c002q001', '1',
u'Data de início da visita', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c002q001')
lsf.writerow(normalize(['2002', '', 'Q', 'D', 'c002q002', '1',
u'Data de término da visita', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c002q002')
lsf.writerow(normalize(['2003', '', 'Q', 'S', 'c002q003', '1',
u'Líder da equipe', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c002q003')
lsf.writerow(normalize(['2004', '', 'Q', 'T', 'c002q004', '1',
u'Membros da equipe', '', 'pt-BR', '', 'Y', 'N', '', '0']))
struct.append('c002q004')
self.stdout.write("Done!")
for c in Categoria.objects.all():
self.stdout.write("\t{0}...".format(nonum(c.nome).encode('utf-8')), ending=" ")
lsf.writerow(normalize([str(c.id), '', 'G', '',
nonum(c.nome), '', nonum(c.nome), '',
'pt-BR']))
perguntas = sorted([(p.title, p) for p in c.perguntas.all()])
for t, p in perguntas:
lstype = DATATYPES[p.datatype]
# Hack para perguntas SIM/NÃO que foram cadastradas como Choice
if lstype == 'L':
if ("".join([e.title for e in p.choices.all()]) in
[u"SimNão", u"NãoSim"]):
lstype = 'Y'
########
relevance = "1"
if p.abre_por.exists():
relevance = "(" + " or ".join(
[u'({sid}X{gid}X{qid}.NAOK == "{value}")'.format(
sid=survey_id, gid=e.schema.categoria.id,
qid=e.schema.id, value=avalue(e)) for e in
p.abre_por.all()]) + ")"
lsf.writerow(normalize([str(p.id), '', 'Q', lstype,
'c{0:03}q{1:03}'.format(c.id, p.id), relevance,
nonum(p.title), p.help_text, 'pt-BR', '', 'NY'[p.required],
'N', '', '0']))
if lstype == 'L':
lsf.writerows([normalize([str(p.id), u'', u'A', u'0',
str(e.id), u'', e.title, u'', u'pt-BR'])
for e in p.choices.all()])
if lstype == 'M':
lsf.writerows([normalize([str(p.id*1000+e.id), u'', u'SQ',
u'', str(e.id), u'1', e.title, u'', u'pt-BR'])
for e in p.choices.all()])
struct.extend(['c{0:03}q{1:03}_{2}'.format(c.id, p.id,
e.id) for e in p.choices.all()])
else:
struct.extend(['c{0:03}q{1:03}'.format(c.id, p.id)])
self.stdout.write("Done!")
if len(args) < 3: # No data export
return
self.stdout.write("Exporting survey data: ")
dtf = csv.writer(open(args[2], 'wb+'), delimiter='\t',
quoting=csv.QUOTE_MINIMAL)
dtf.writerow(struct)
for d in Diagnostico.objects.all():
self.stdout.write(u"\t{0}".format(d.casa_legislativa.nome))
form = OrderedDict.fromkeys(struct, '{question_not_shown}')
form['id'] = str(d.id)
if d.data_publicacao:
form['submitdate'] = d.data_publicacao.isoformat()
# form['lastpage'] = '8'
form['startlanguage'] = 'pt-BR'
# form['seed'] = '123456'
# Identificação da Casa Legislativa e sua equipe #
form['c001q001'] = d.casa_legislativa.municipio.uf.regiao
form['c001q002'] = d.casa_legislativa.municipio.uf.sigla
form['c001q003'] = d.casa_legislativa.municipio.nome
if d.casa_legislativa.municipio.data_criacao:
form['c001q004'] = \
d.casa_legislativa.municipio.data_criacao.isoformat()
form['c001q005'] = d.casa_legislativa.nome
if d.casa_legislativa.data_instalacao:
form['c001q006'] = \
d.casa_legislativa.data_instalacao.isoformat()
form['c001q007'] = (
u"{logradouro}{{cr}}{{newline}}"
u"{bairro}{{cr}}{{newline}}"
u"{cep} - {municipio} - {uf}".format(
logradouro=d.casa_legislativa.logradouro,
bairro=d.casa_legislativa.bairro,
cep=d.casa_legislativa.cep,
municipio=d.casa_legislativa.municipio.nome,
uf=d.casa_legislativa.municipio.uf.sigla
))
form['c001q008'] = d.casa_legislativa.cnpj
form['c001q009'] = d.casa_legislativa.email
form['c001q010'] = d.casa_legislativa.pagina_web
for i, k, v in setores:
q = d.casa_legislativa.funcionario_set.filter(setor=k)
if q.exists():
f = q.first()
knome = 'c001q011_SQ1010{0}_SQ00101'.format(i)
kmail = 'c001q011_SQ1010{0}_SQ00102'.format(i)
form[knome] = f.nome
form[kmail] = f.email
if d.data_visita_inicio:
form['c002q001'] = d.data_visita_inicio.isoformat()
if d.data_visita_fim:
form['c002q002'] = d.data_visita_fim.isoformat()
form['c002q003'] = d.responsavel.nome_completo
form['c002q004'] = "{cr}{newline}".join(
[e.membro.nome_completo for e in d.equipe_set.all()])
for r in Resposta.objects.filter(entity_id=d.id):
if r.schema.datatype == 'many':
key = "c{cid:03}q{qid:03}_{sqid}".format(
cid=r.schema.categoria.id,
qid=r.schema.id,
sqid=r.value.id
)
value = 'Y'
else:
key = "c{cid:03}q{qid:03}".format(cid=r.schema.categoria.id,
qid=r.schema.id)
value = r.value
if r.schema.datatype == 'one':
if value is None:
value = '{question_not_shown}'
elif value.title == u'Sim':
value = 'Y'
elif value.title == u'Não':
value = 'N'
else:
value = r.value.id
elif r.schema.datatype == 'text':
value = value.\
replace('\r\n', '{cr}{newline}').\
replace('\r', '{cr}{newline}').\
replace('\n', '{cr}{newline}').\
replace('\t', ' ')
if value is None:
value = '{question_not_shown}'
form[key] = u'{0}'.format(value)
dtf.writerow(normalize(form.values()))
self.stdout.write('Done!')

22
sigi/apps/diagnosticos/migrations/0002_auto_20170407_1024.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import autoslug.fields
import eav.models
class Migration(migrations.Migration):
dependencies = [
('diagnosticos', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='pergunta',
name='name',
field=autoslug.fields.AutoSlugField(populate_from=b'title', editable=True, max_length=250, blank=True, verbose_name='name', slugify=eav.models.slugify_attr_name),
preserve_default=True,
),
]

20
sigi/apps/diagnosticos/migrations/0003_auto_20201101_2240.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('diagnosticos', '0002_auto_20170407_1024'),
]
operations = [
migrations.AlterField(
model_name='escolha',
name='schema_to_open',
field=models.ForeignKey(related_name='abre_por', verbose_name='pergunta para abrir', blank=True, to='diagnosticos.Pergunta', null=True),
preserve_default=True,
),
]

21
sigi/apps/diagnosticos/migrations/0004_auto_20210406_1945.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('diagnosticos', '0003_auto_20201101_2240'),
('casas', '0014_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='diagnostico',
name='casa_legislativa',
field=models.ForeignKey(verbose_name='Casa Legislativa', to='casas.Orgao'),
preserve_default=True,
),
]

51
sigi/apps/diagnosticos/migrations/0005_auto_20210416_0841.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('diagnosticos', '0004_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='diagnostico',
name='casa_legislativa',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Casa Legislativa', to='casas.Orgao'),
preserve_default=True,
),
migrations.AlterField(
model_name='diagnostico',
name='responsavel',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='respons\xe1vel', to='servidores.Servidor'),
preserve_default=True,
),
migrations.AlterField(
model_name='equipe',
name='membro',
field=models.ForeignKey(to='servidores.Servidor', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
migrations.AlterField(
model_name='escolha',
name='schema_to_open',
field=models.ForeignKey(related_name='abre_por', on_delete=django.db.models.deletion.SET_NULL, verbose_name='pergunta para abrir', blank=True, to='diagnosticos.Pergunta', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='resposta',
name='choice',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='escolha', blank=True, to='diagnosticos.Escolha', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='resposta',
name='schema',
field=models.ForeignKey(related_name='attrs', on_delete=django.db.models.deletion.PROTECT, verbose_name='pergunta', to='diagnosticos.Pergunta'),
preserve_default=True,
),
]

67
sigi/apps/diagnosticos/models.py

@ -14,8 +14,10 @@ class Diagnostico(BaseEntity):
em uma Casa Legislativa
"""
casa_legislativa = models.ForeignKey(
'casas.CasaLegislativa',
verbose_name=_(u'Casa Legislativa'))
'casas.Orgao',
on_delete=models.PROTECT,
verbose_name=_(u'Casa Legislativa')
)
# campo de busca em caixa baixa e sem acento
search_text = SearchField(field_names=['casa_legislativa'])
@ -38,8 +40,11 @@ class Diagnostico(BaseEntity):
blank=True,
)
responsavel = models.ForeignKey('servidores.Servidor',
verbose_name=_(u'responsável'))
responsavel = models.ForeignKey(
'servidores.Servidor',
on_delete=models.PROTECT,
verbose_name=_(u'responsável')
)
class Meta:
verbose_name, verbose_name_plural = _(u'diagnóstico'), _(u'diagnósticos')
@ -156,7 +161,11 @@ class Pergunta(BaseSchema):
Uma pergunta tem o nome e o tipo da resposta
"""
categoria = models.ForeignKey(Categoria, related_name='perguntas')
categoria = models.ForeignKey(
Categoria,
on_delete=models.CASCADE,
related_name='perguntas'
)
def group_choices(self):
from django.db import connection, transaction
@ -196,10 +205,20 @@ class Escolha(BaseChoice):
""" Perguntas de multiplas escolhas tem as opções
cadastradas neste modelo
"""
schema = models.ForeignKey(Pergunta,
related_name='choices', verbose_name=_(u'pergunta'))
schema_to_open = models.ForeignKey(Pergunta, related_name='',
verbose_name=_(u'pergunta para abrir'), blank=True, null=True)
schema = models.ForeignKey(
Pergunta,
on_delete=models.CASCADE,
related_name='choices',
verbose_name=_(u'pergunta')
)
schema_to_open = models.ForeignKey(
Pergunta,
on_delete=models.SET_NULL,
related_name='abre_por',
verbose_name=_(u'pergunta para abrir'),
blank=True,
null=True
)
ordem = models.PositiveIntegerField(blank=True, null=True)
class Meta:
@ -212,10 +231,19 @@ class Resposta(BaseAttribute):
""" Modelo para guardar as respostas das perguntas
de um diagnosico
"""
schema = models.ForeignKey(Pergunta, related_name='attrs',
verbose_name=_(u'pergunta'))
choice = models.ForeignKey(Escolha, verbose_name=_(u'escolha'),
blank=True, null=True)
schema = models.ForeignKey(
Pergunta,
on_delete=models.PROTECT,
related_name='attrs',
verbose_name=_(u'pergunta')
)
choice = models.ForeignKey(
Escolha,
on_delete=models.PROTECT,
verbose_name=_(u'escolha'),
blank=True,
null=True
)
class Meta:
verbose_name, verbose_name_plural = _(u'resposta'), _(u'respostas')
@ -225,8 +253,11 @@ class Equipe(models.Model):
""" Modelo que representa a equipe de um diagnóstico
"""
diagnostico = models.ForeignKey(Diagnostico)
membro = models.ForeignKey('servidores.Servidor')
diagnostico = models.ForeignKey(Diagnostico, on_delete=models.CASCADE)
membro = models.ForeignKey(
'servidores.Servidor',
on_delete=models.PROTECT
)
class Meta:
verbose_name, verbose_name_plural = _(u'equipe'), _(u'equipe')
@ -240,7 +271,11 @@ class Anexo(models.Model):
""" Modelo para representar os documentos levantados
no processo de diagnóstico. Podem ser fotos, contratos, etc.
"""
diagnostico = models.ForeignKey(Diagnostico, verbose_name=u'diagnóstico')
diagnostico = models.ForeignKey(
Diagnostico,
on_delete=models.CASCADE,
verbose_name=u'diagnóstico'
)
arquivo = models.FileField(upload_to='apps/diagnostico/anexo/arquivo', max_length=500)
descricao = models.CharField(_(u'descrição'), max_length='70')
data_pub = models.DateTimeField(_(u'data da publicação do anexo'),

6
sigi/apps/diagnosticos/views.py

@ -12,7 +12,7 @@ from sigi.apps.casas.models import Funcionario
from sigi.apps.contatos.models import Telefone
from sigi.apps.diagnosticos.decorators import validate_diagnostico
from sigi.apps.diagnosticos.forms import (DiagnosticoMobileForm,
CasaLegislativaMobileForm, FuncionariosMobileForm)
OrgaoMobileForm, FuncionariosMobileForm)
from sigi.apps.diagnosticos.models import Diagnostico, Categoria, Pergunta
from sigi.apps.diagnosticos.urls import LOGIN_REDIRECT_URL
from sigi.apps.utils.decorators import login_required
@ -117,7 +117,7 @@ def categoria_casa_legislativa(request, id_diagnostico):
casa_legislativa = diagnostico.casa_legislativa
if request.method == "POST":
form = CasaLegislativaMobileForm(request.POST,
form = OrgaoMobileForm(request.POST,
instance=casa_legislativa)
if form.is_valid():
form.save()
@ -133,7 +133,7 @@ def categoria_casa_legislativa(request, id_diagnostico):
json = simplejson.dumps(resposta)
return HttpResponse(json, content_type='application/json')
else:
form = CasaLegislativaMobileForm(instance=casa_legislativa)
form = OrgaoMobileForm(instance=casa_legislativa)
context = RequestContext(request, {'form': form,
'diagnostico': diagnostico, 'casa_legislativa': casa_legislativa})

42
sigi/apps/eventos/admin.py

@ -18,18 +18,20 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from django.contrib import admin
from django import forms
from django.contrib import admin
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext as _
from sigi.apps.eventos.models import TipoEvento, Funcao, Evento, Equipe, Convite
from sigi.apps.eventos.views import adicionar_eventos_carrinho
class EventoAdminForm(forms.ModelForm):
class Meta:
model = Evento
fields = ('tipo_evento', 'nome', 'descricao', 'solicitante', 'data_inicio', 'data_termino',
'casa_anfitria', 'municipio', 'local', 'publico_alvo', 'status',
'data_cancelamento', 'motivo_cancelamento', 'curso_moodle_id',
)
fields = ('tipo_evento', 'nome', 'descricao', 'virtual', 'solicitante',
'data_inicio', 'data_termino', 'carga_horaria',
'casa_anfitria', 'municipio', 'local', 'publico_alvo',
'status', 'data_cancelamento', 'motivo_cancelamento', )
def clean(self):
cleaned_data = super(EventoAdminForm, self).clean()
@ -37,8 +39,10 @@ class EventoAdminForm(forms.ModelForm):
data_termino = cleaned_data.get("data_termino")
if data_inicio > data_termino:
raise forms.ValidationError(_(u"Data término deve ser posterior à data inicio"),
code="invalid_period" )
raise forms.ValidationError(
_(u"Data término deve ser posterior à data inicio"),
code="invalid_period"
)
@admin.register(TipoEvento)
class TipoEventAdmin(admin.ModelAdmin):
@ -60,12 +64,30 @@ class ConviteInline(admin.TabularInline):
class EventoAdmin(admin.ModelAdmin):
form = EventoAdminForm
date_hierarchy = 'data_inicio'
list_display = ('nome', 'tipo_evento', 'status', 'data_inicio', 'data_termino', 'municipio',
list_display = ('nome', 'tipo_evento', 'status', 'data_inicio',
'data_termino', 'municipio', 'solicitante')
list_filter = ('status', 'tipo_evento', 'virtual', 'municipio__uf',
'solicitante')
list_filter = ('status', 'tipo_evento', 'municipio__uf', 'solicitante')
raw_id_fields = ('casa_anfitria', 'municipio',)
search_fields = ('nome', 'tipo_evento__nome', 'casa_anfitria__search_text',
'municipio__search_text', 'solicitante')
inlines = (EquipeInline, ConviteInline)
actions = ['adicionar_eventos', ]
def adicionar_eventos(self, request, queryset):
if 'carrinho_eventos' in request.session:
q1 = len(request.session['carrinho_eventos'])
else:
q1 = 0
response = adicionar_eventos_carrinho(request, queryset=queryset)
q2 = len(request.session['carrinho_eventos'])
quant = q2 - q1
if quant:
self.message_user(request, str(q2 - q1) + " " +
_(u"Eventos adicionados no carrinho"))
else:
self.message_user(request, _(u"Os Eventos selecionados "
u"já foram adicionados anteriormente"))
return HttpResponseRedirect('.')
adicionar_eventos.short_description = _(u"Armazenar eventos no carrinho "
u"para exportar")

18
sigi/apps/eventos/migrations/0004_remove_evento_curso_moodle_id.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('eventos', '0003_auto_20151104_0810'),
]
operations = [
migrations.RemoveField(
model_name='evento',
name='curso_moodle_id',
),
]

27
sigi/apps/eventos/migrations/0005_auto_20210406_1945.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('eventos', '0004_remove_evento_curso_moodle_id'),
('casas', '0014_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='convite',
name='casa',
field=models.ForeignKey(verbose_name='Casa convidada', to='casas.Orgao'),
preserve_default=True,
),
migrations.AlterField(
model_name='evento',
name='casa_anfitria',
field=models.ForeignKey(verbose_name='Casa anfitri\xe3', blank=True, to='casas.Orgao', null=True),
preserve_default=True,
),
]

57
sigi/apps/eventos/migrations/0006_auto_20210416_0841.py

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('eventos', '0005_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='convite',
name='casa',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Casa convidada', to='casas.Orgao'),
preserve_default=True,
),
migrations.AlterField(
model_name='convite',
name='servidor',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Servidor que convidou', to='servidores.Servidor'),
preserve_default=True,
),
migrations.AlterField(
model_name='equipe',
name='funcao',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Fun\xe7\xe3o na equipe', to='eventos.Funcao'),
preserve_default=True,
),
migrations.AlterField(
model_name='equipe',
name='membro',
field=models.ForeignKey(related_name='equipe_evento', on_delete=django.db.models.deletion.PROTECT, to='servidores.Servidor'),
preserve_default=True,
),
migrations.AlterField(
model_name='evento',
name='casa_anfitria',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Casa anfitri\xe3', blank=True, to='casas.Orgao', null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='evento',
name='municipio',
field=models.ForeignKey(to='contatos.Municipio', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
migrations.AlterField(
model_name='evento',
name='tipo_evento',
field=models.ForeignKey(to='eventos.TipoEvento', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
]

38
sigi/apps/eventos/migrations/0007_auto_20210417_0744.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('eventos', '0006_auto_20210416_0841'),
]
operations = [
migrations.AddField(
model_name='convite',
name='nomes_participantes',
field=models.TextField(help_text='Favor colocar um participante por linha', verbose_name='nome dos participantes', blank=True),
preserve_default=True,
),
migrations.AddField(
model_name='convite',
name='qtde_participantes',
field=models.PositiveIntegerField(default=0, verbose_name='n\xfamero de participantes'),
preserve_default=True,
),
migrations.AddField(
model_name='evento',
name='carga_horaria',
field=models.PositiveIntegerField(default=0, verbose_name='carga hor\xe1ria'),
preserve_default=True,
),
migrations.AddField(
model_name='evento',
name='virtual',
field=models.BooleanField(default=False, verbose_name='Virtual'),
preserve_default=True,
),
]

111
sigi/apps/eventos/models.py

@ -1,32 +1,12 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.eventos.models
#
# Copyright (C) 2015 Interlegis
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from django.db import models
from django.utils.functional import lazy
from django.utils.translation import ugettext as _
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.contatos.models import Municipio
from sigi.apps.servidores.models import Servidor
from sigi.apps.utils.moodle_ws_api import get_courses
from django.core.exceptions import ValidationError
from sigi.apps.mdl.models import Course
class TipoEvento(models.Model):
nome = models.CharField(_(u"Nome"), max_length=100)
@ -47,42 +27,36 @@ class Evento(models.Model):
('C', _(u"Cancelado"))
)
# def get_course_choices():
# result = [(None, u'---------')]
#
# try:
# courses = get_courses(sort_order='categorysortorder', idnumber__startswith='evento')
# result = result + [(c['id'], c['fullname']) for c in courses]
# except Exception as e:
# result.append((None, _(u"Erro ao acessar o saberes: '%s'" % (e.message,))))
#
# return result
def get_course_choices():
from django.apps import apps
if apps.models_ready:
courses = Course.objects.filter(idnumber__startswith='evento')
else:
courses = []
result = [(None, u'---------')] + [(c.id, c.fullname) for c in courses]
return result
tipo_evento = models.ForeignKey(TipoEvento)
tipo_evento = models.ForeignKey(
TipoEvento,
on_delete=models.PROTECT,
)
nome = models.CharField(_(u"Nome do evento"), max_length=100)
descricao = models.TextField(_(u"Descrição do evento"))
virtual = models.BooleanField(_("Virtual"), default=False)
solicitante = models.CharField(_(u"Solicitante"), max_length=100)
data_inicio = models.DateField(_(u"Data de início"))
data_termino = models.DateField(_(u"Data de término"))
casa_anfitria = models.ForeignKey(CasaLegislativa, verbose_name=_(u"Casa anfitriã"), blank=True,
null=True)
municipio = models.ForeignKey(Municipio)
carga_horaria = models.PositiveIntegerField(
_(u"carga horária"),
default=0
)
casa_anfitria = models.ForeignKey(
Orgao,
on_delete=models.PROTECT,
verbose_name=_(u"Casa anfitriã"),
blank=True,
null=True
)
municipio = models.ForeignKey(
Municipio,
on_delete=models.PROTECT
)
local = models.TextField(_(u"Local do evento"), blank=True)
publico_alvo = models.TextField(_(u"Público alvo"), blank=True)
status = models.CharField(_(u"Status"), max_length=1, choices=STATUS_CHOICES)
data_cancelamento = models.DateField(_(u"Data de cancelamento"), blank=True, null=True)
motivo_cancelamento = models.TextField(_(u"Motivo do cancelamento"), blank=True)
curso_moodle_id = models.IntegerField(_(u"Curso saberes"), blank=True, null=True,
choices=lazy(get_course_choices, list)())
class Meta:
ordering = ("-data_inicio",)
@ -115,9 +89,20 @@ class Funcao(models.Model):
return self.nome
class Equipe(models.Model):
evento = models.ForeignKey(Evento)
membro = models.ForeignKey(Servidor, related_name="equipe_evento")
funcao = models.ForeignKey(Funcao, verbose_name=_(u"Função na equipe"))
evento = models.ForeignKey(
Evento,
on_delete=models.CASCADE
)
membro = models.ForeignKey(
Servidor,
on_delete=models.PROTECT,
related_name="equipe_evento"
)
funcao = models.ForeignKey(
Funcao,
on_delete=models.PROTECT,
verbose_name=_(u"Função na equipe")
)
observacoes = models.TextField(_(u"Observações"), blank=True)
class Meta:
@ -128,12 +113,32 @@ class Equipe(models.Model):
return u"%s (%s)" % (unicode(self.membro), unicode(self.funcao),)
class Convite(models.Model):
evento = models.ForeignKey(Evento)
casa = models.ForeignKey(CasaLegislativa, verbose_name=_(u"Casa convidada"))
servidor = models.ForeignKey(Servidor, verbose_name=_(u"Servidor que convidou"))
evento = models.ForeignKey(
Evento,
on_delete=models.CASCADE
)
casa = models.ForeignKey(
Orgao,
on_delete=models.PROTECT,
verbose_name=_(u"Casa convidada")
)
servidor = models.ForeignKey(
Servidor,
on_delete=models.PROTECT,
verbose_name=_(u"Servidor que convidou")
)
data_convite = models.DateField(_(u"Data do convite"))
aceite = models.BooleanField(_("Aceitou o convite"), default=False)
participou = models.BooleanField(_(u"Participou do evento"), default=False)
qtde_participantes = models.PositiveIntegerField(
_(u"número de participantes"),
default=0
)
nomes_participantes = models.TextField(
_(u"nome dos participantes"),
blank=True,
help_text=_(u"Favor colocar um participante por linha")
)
class Meta:
ordering = ('evento', 'casa', '-data_convite')

1
sigi/apps/eventos/templates/admin/eventos/change_list.html

@ -0,0 +1 @@
{% extends "change_list_with_cart.html" %}

63
sigi/apps/eventos/templates/eventos/carrinho.html

@ -0,0 +1,63 @@
{% extends "admin/carrinho.html" %}
{% load admin_list i18n %}
{% block extrastyle %}
{{ block.super }}
{#% include "admin/tabs_style.html" %#}
{% endblock %}
{% block title %}{% trans 'Eventos no Carrinho | SIGI' %}{% endblock %}
{% block content_title %}<h1>{% trans 'Eventos no Carrinho' %}</h1>{% endblock %}
{% block mensagem%}
<ul class="messagelist">
{%if carIsEmpty%}
<li class="warning">{% trans 'O carrinho está vazio, sendo assim todos os eventos entram na lista para exportação de acordo com os filtros aplicados.' %}</li>
{%else%}
<li>{{paginas.paginator.count}} {% trans 'Eventos no carrinho' %}.</li>
{%endif%}
</ul>
{% endblock %}
{% block action %}deleta_itens_carrinho{% endblock %}
{% block tabela %}
<table class="table table-striped">
<thead class="thead-dark">
<tr>
{%if not carIsEmpty%}
<th><!-- <input type="checkbox" id="action-toggle" style="display: inline;">-->
</th>
{% endif %}
<th>{% trans 'Nome do evento' %}</th>
<th>{% trans 'Tipo evento' %}</th>
<th>{% trans 'Status' %}</th>
<th>{% trans 'Data de início' %}</th>
<th>{% trans 'Data de término' %}</th>
<th>{% trans 'município' %}</th>
<th>{% trans 'Solicitante' %}</th>
</tr>
</thead>
<tbody>
{% for evento in paginas.object_list %}
<tr>
{%if not carIsEmpty%}
<th><input type="checkbox" name="_selected_action"
value="{{evento.id|safe}}" class="action-select" />
</th>
{% endif %}
<td style="text-align: left;">{{evento.nome}}</td>
<td>{{evento.tipo_evento}}</td>
<td>{{evento.get_status_display}}</td>
<td>{{evento.data_inicio}}</td>
<td>{{evento.data_termino}}</td>
<td>{{evento.municipio}}</td>
<td>{{evento.solicitante}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block botoes %}
<a class="btn btn-primary" href="../csv/{{query_str}}">{% trans "Exportar CVS" %}</a>
{% endblock %}

9
sigi/apps/eventos/urls.py

@ -7,4 +7,13 @@ urlpatterns = patterns(
# Painel de ocorrencias
url(r'^calendario/$', 'calendario', name='eventos-calendario'),
url(r'^alocacaoequipe/$', 'alocacao_equipe', name='eventos-alocacaoequipe'),
# Carrinho
url(r'^evento/carrinho/$', 'visualizar_carrinho',
name='visualizar-carrinho-evento'),
url(r'^evento/carrinho/excluir_carrinho/$', 'excluir_carrinho',
name='excluir-carrinho-evento'), # Error
url(r'^evento/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho',
name='deleta-itens-carrinho-evento'), # Error
url(r'^evento/csv/$', 'export_csv', name='evento-export-csv'), # Error
)

166
sigi/apps/eventos/views.py

@ -21,11 +21,14 @@
import calendar
import datetime
import locale
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.utils import translation
from django.utils.translation import ungettext, ugettext as _
from sigi.apps.eventos.models import Evento
from sigi.apps.eventos.models import Evento, Equipe, Convite
from sigi.apps.servidores.models import Servidor
from sigi.shortcuts import render_to_pdf
import csv
@ -189,3 +192,164 @@ def alocacao_equipe(request):
return JsonResponse(result)
return render(request, 'eventos/alocacao_equipe.html', data)
# Views e functions para carrinho de exportação
def query_ordena(qs, o):
from sigi.apps.eventos.admin import EventoAdmin
list_display = EventoAdmin.list_display
order_fields = []
for order_number in o.split('.'):
order_number = int(order_number)
order = ''
if order_number != abs(order_number):
order_number = abs(order_number)
order = '-'
order_fields.append(order + list_display[order_number - 1])
qs = qs.order_by(*order_fields)
return qs
def get_for_qs(get, qs):
kwargs = {}
for k, v in get.iteritems():
if str(k) not in ('page', 'pop', 'q', '_popup', 'o', 'ot'):
kwargs[str(k)] = v
qs = qs.filter(**kwargs)
if 'o' in get:
qs = query_ordena(qs, get['o'])
return qs
def carrinhoOrGet_for_qs(request):
if 'carrinho_eventos' in request.session:
ids = request.session['carrinho_eventos']
qs = Evento.objects.filter(pk__in=ids)
else:
qs = Evento.objects.all()
if request.GET:
qs = get_for_qs(request.GET, qs)
return qs
def adicionar_eventos_carrinho(request, queryset=None, id=None):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if 'carrinho_eventos' not in request.session:
request.session['carrinho_eventos'] = ids_selecionados
else:
lista = request.session['carrinho_eventos']
# Verifica se id já não está adicionado
for id in ids_selecionados:
if id not in lista:
lista.append(id)
request.session['carrinho_eventos'] = lista
@login_required
def visualizar_carrinho(request):
qs = carrinhoOrGet_for_qs(request)
paginator = Paginator(qs, 100)
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
paginas = paginator.page(page)
except (EmptyPage, InvalidPage):
paginas = paginator.page(paginator.num_pages)
carrinhoIsEmpty = not('carrinho_eventos' in request.session)
return render(
request,
'eventos/carrinho.html',
{
'carIsEmpty': carrinhoIsEmpty,
'paginas': paginas,
'query_str': '?' + request.META['QUERY_STRING']
}
)
@login_required
def excluir_carrinho(request):
if 'carrinho_eventos' in request.session:
del request.session['carrinho_eventos']
messages.info(request, u'O carrinho foi esvaziado')
return HttpResponseRedirect('../../')
@login_required
def deleta_itens_carrinho(request):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
removed = 0
if 'carrinho_eventos' in request.session:
lista = request.session['carrinho_eventos']
for item in ids_selecionados:
lista.remove(item)
removed += 1
if lista:
request.session['carrinho_eventos'] = lista
else:
del lista
del request.session['carrinho_eventos']
messages.info(request, u"{0} itens removidos do carrinho".format(removed))
return HttpResponseRedirect('.')
@login_required
def export_csv(request):
def serialize(r, field):
value = (getattr(r, 'get_{0}_display'.format(field.name), None) or
getattr(r, field.name, ""))
if callable(value):
value = value()
if value is None:
value = ""
return unicode(value).encode('utf8')
eventos = carrinhoOrGet_for_qs(request)
eventos.select_related('equipe', 'convite')
if not eventos:
messages.info(request, _(u"Nenhum evento a exportar"))
return HttpResponseRedirect('../')
max_equipe = max([e.equipe_set.count() for e in eventos])
head = [f.verbose_name.encode('utf8') for f in Evento._meta.fields]
head.extend([f.verbose_name.encode('utf8')+"_{0}".format(i+1)
for i in range(max_equipe) for f in Equipe._meta.fields
if f.name not in ('id', 'evento')])
head.extend([f.verbose_name.encode('utf8') for f in Convite._meta.fields
if f.name not in ('id', 'evento')])
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=eventos.csv'
writer = csv.DictWriter(response, fieldnames=head)
writer.writeheader()
for evento in eventos:
reg = {f.verbose_name.encode('utf8'): serialize(evento, f)
for f in Evento._meta.fields}
idx = 1
for membro in evento.equipe_set.all():
reg.update(
{
"{0}_{1}".format(f.verbose_name.encode('utf8'), idx):
serialize(membro, f) for f in Equipe._meta.fields
if f.name not in ('id', 'evento')
}
)
idx += 1
for convite in evento.convite_set.all():
reg.update(
{f.verbose_name.encode('utf8'): serialize(convite, f)
for f in Convite._meta.fields
if f.name not in ('id', 'evento')}
)
writer.writerow(reg)
if evento.convite_set.count() == 0:
writer.writerow(reg)
return response

6
sigi/apps/financeiro/models.py

@ -6,7 +6,11 @@ from sigi.apps.convenios.models import Projeto
class Desembolso(models.Model):
projeto = models.ForeignKey(Projeto, verbose_name=_(u'Projeto'))
projeto = models.ForeignKey(
Projeto,
on_delete=models.CASCADE,
verbose_name=_(u'Projeto')
)
descricao = models.CharField(_(u'Descrição da despesa'), max_length=100)
data = models.DateField(_(u'Data do desembolso'))
valor_reais = models.DecimalField(_(u'Valor em R$'), max_digits=18, decimal_places=2)

2
sigi/apps/home/templates/home/sem_convenio.html

@ -77,7 +77,7 @@
<tr>
<td>{{ casa.nome }}</td>
<td>{{ casa.municipio.uf.sigla }}</td>
<td>{{ casa.gerente_contas.nome_completo }}</td>
<td>{{ casa.lista_gerentes }}</td>
<td>
{% for s in casa.servico_set.all %}
{% if s.data_desativacao == None %}

170
sigi/apps/home/templatetags/menu_conf.yaml

@ -1,6 +1,5 @@
main_menu:
- title: Municípios
url: contatos/municipio/
children:
- title: Municípios
url: contatos/municipio/
@ -8,96 +7,43 @@ main_menu:
url: contatos/unidadefederativa/
- title: Mesorregiões
url: contatos/mesorregiao/
- title: Casas Legislativas
url: casas/casalegislativa/
- title: Casas e órgãos
children:
- title: Todas
url: casas/casalegislativa/
- title: Todo legislativo
url: casas/orgao/?tipo__legislativo__exact=1
- title: Câmaras Municipais
url: casas/casalegislativa/?tipo__id__exact=1
url: casas/orgao/?tipo__sigla__exact=CM
- title: Assembléias Legislativas
url: casas/casalegislativa/?tipo__id__exact=2
- title: Portfólio de relacionamento
url: casas/portfolio/
url: casas/orgao/?tipo__sigla__exact=AL
- title: Demais órgãos
url: casas/orgao/?tipo__legislativo__exact=0
- title: Gerência Interlegis
children:
- title: Carteira de relacionamentos
url: casas/carteira
- title: Tipos de Casas
url: casas/tipocasalegislativa/
- title: Legislaturas
url: parlamentares/legislatura/
children:
- title: Todas
url: parlamentares/legislatura/
- title: Parlamentares
url: parlamentares/parlamentar/
- title: Tabela de cargos
url: parlamentares/cargo/
- title: Tabela de partidos
url: parlamentares/partido/
- title: Diagnósticos
url: diagnosticos/diagnostico/
children:
- title: Administração
url: diagnosticos/diagnostico/
- title: Coleta de dados
url: diagnosticos/mobile/
- title: Gráficos e estatísticas
url: diagnosticos/graficos
- title: Organizar relacionamentos
url: casas/portfolio/
- title: Lista de gerentes
url: casas/gerentes/
- title: Convênios
url: convenios/convenio/
children:
- title: Convênios
url: convenios/convenio/
- title: Planos diretores
url: metas/planodiretor/
- title: Inventário
url: inventario/bem/
children:
- title: Bens
url: inventario/bem/
- title: Fornecedores
url: inventario/fornecedor/
- title: Equipamentos
url: inventario/equipamento/
- title: Fabricantes
url: inventario/fabricante/
- title: Tipos de equipamentos
url: inventario/tipoequipamento/
- title: Modelos de equipamentos
url: inventario/modeloequipamento/
- title: Servidores
url: servidores/servidor/?user__is_active__exact=1
children:
- title: Pessoal
url: servidores/servidor/?user__is_active__exact=1
- title: Funções
url: servidores/funcao
- title: Férias
url: servidores/ferias/
- title: Licenças
url: servidores/licenca/
- title: Serviços SEIT
url: servicos/casaatendida/
children:
- title: Tipos de serviço
url: servicos/tiposervico/
- title: Casas atendidas
url: servicos/casaatendida/
- title: Lista de serviços
url: servicos/servico/
- title: Ocorrências
url: ocorrencias/ocorrencia/?minhas=S&status__in=1,2
children:
- title: Painel de ocorrências
url: ocorrencias/painel/
- title: Registro de ocorrências
url: ocorrencias/ocorrencia/?minhas=S&status__in=1,2
- title: Tabela de categorias
url: ocorrencias/categoria/
- title: Tipos de contato
url: ocorrencias/tipocontato/
- title: Eventos
url: eventos/evento
children:
- title: Eventos
url: eventos/evento/
@ -105,21 +51,81 @@ main_menu:
url: eventos/calendario
- title: Alocação de equipe
url: eventos/alocacaoequipe/
- title: Servidores
children:
- title: Serviços (unidades do ILB)
url: servidores/servico/
- title: Servidores e colaboradores
url: servidores/servidor/
- title: Tabelas auxiliares
children:
- title: Tipos de órgãos
url: casas/tipoorgao/
- title: Acompanhamento convênios
url: convenios/statusconvenio/
- title: Tipos de serviço SEIT
url: servicos/tiposervico/
- title: Categorias de ocorrências
url: ocorrencias/categoria/
- title: Tipos de contato
url: ocorrencias/tipocontato/
- title: Tipos de evento
url: eventos/tipoevento/
- title: Funções na equipe
- title: Funções na equipe de eventos
url: eventos/funcao/
- title: Financeiro
url: financeiro/desembolso/
children:
- title: Desembolsos
url: financeiro/desembolso/
- title: Saberes
url: '/'
children:
- title: Dashboard
url: saberes/dashboard/
- title: Cursos sem Tutoria
url: saberes/dashboard/cursos-sem-turoria/
- title: Cursos com Tutoria
url: saberes/dashboard/cursos-com-turoria/
# Removidos
# - title: Legislaturas
# url: parlamentares/legislatura/
# children:
# - title: Todas
# url: parlamentares/legislatura/
# - title: Parlamentares
# url: parlamentares/parlamentar/
# - title: Tabela de cargos
# url: parlamentares/cargo/
# - title: Tabela de partidos
# url: parlamentares/partido/
# - title: Diagnósticos
# url: diagnosticos/diagnostico/
# children:
# - title: Administração
# url: diagnosticos/diagnostico/
# - title: Coleta de dados
# url: diagnosticos/mobile/
# - title: Gráficos e estatísticas
# url: diagnosticos/graficos
# - title: Inventário
# url: inventario/bem/
# children:
# - title: Bens
# url: inventario/bem/
# - title: Fornecedores
# url: inventario/fornecedor/
# - title: Equipamentos
# url: inventario/equipamento/
# - title: Fabricantes
# url: inventario/fabricante/
# - title: Tipos de equipamentos
# url: inventario/tipoequipamento/
# - title: Modelos de equipamentos
# url: inventario/modeloequipamento/
# - title: Servidores
# url: servidores/servidor/?user__is_active__exact=1
# children:
# - title: Pessoal
# url: servidores/servidor/?user__is_active__exact=1
# - title: Funções
# url: servidores/funcao
# - title: Férias
# url: servidores/ferias/
# - title: Licenças
# url: servidores/licenca/
# - title: Financeiro
# url: financeiro/desembolso/
# children:
# - title: Desembolsos
# url: financeiro/desembolso/

59
sigi/apps/home/views.py

@ -27,7 +27,7 @@ import calendar
from django.shortcuts import render, get_object_or_404
from django.utils.translation import ugettext as _
from itertools import cycle
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.convenios.models import Convenio, Projeto
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.metas.models import Meta
@ -126,9 +126,13 @@ def chart_carteira(request):
'data': [{'value': r['total_casas'],
'color': colors.next(),
'highlight': highlights.next(),
'label': Servidor.objects.get(pk=r['gerente_contas']).nome_completo
'label': r['gerentes_interlegis__nome_completo']
}
for r in CasaLegislativa.objects.all().values('gerente_contas').annotate(total_casas=Count('pk')).order_by('gerente_contas')
for r in Orgao.objects.exclude(
gerentes_interlegis=None).values(
'gerentes_interlegis__nome_completo').annotate(
total_casas=Count('pk')).order_by(
'gerentes_interlegis__nome_completo')
]
}
@ -140,7 +144,7 @@ def chart_performance(request):
servidor = request.GET.get('servidor', None)
if servidor is None:
casas = CasaLegislativa.objects.exclude(gerente_contas=None)
casas = Orgao.objects.exclude(gerentes_interlegis=None)
else:
gerente = get_object_or_404(Servidor, pk=servidor)
casas = gerente.casas_que_gerencia
@ -149,8 +153,12 @@ def chart_performance(request):
'type': 'pie',
'options': {'responsive': True},
'data': [
{'label': _(u"Utilizam serviços"), 'value': casas.exclude(servico=None).count(), 'color': '#91e8e1'},
{'label': _(u"Não utilizam serviços"), 'value': casas.filter(servico=None).count(), 'color': '#f7a35c'},
{'label': _(u"Utilizam serviços"),
'value': casas.exclude(servico=None).count(),
'color': '#91e8e1'},
{'label': _(u"Não utilizam serviços"),
'value': casas.filter(servico=None).count(),
'color': '#f7a35c'},
]
}
@ -160,43 +168,52 @@ def chart_performance(request):
@login_required
def report_sem_convenio(request):
modo = request.GET.get('modo', None)
format = request.GET.get('f', 'pdf')
fmt = request.GET.get('f', 'pdf')
sc = sem_convenio()
if modo == 'H':
casas = sc['hospedagem']
titulo = _(u"Casas sem convenio que utilizam algum serviço de hospedagem")
titulo = _(u"Casas sem convenio que utilizam algum serviço de "
u"hospedagem")
elif modo == 'R':
casas = sc['registro']
titulo = _(u"Casas sem convenio que utilizam somente serviço de registro")
titulo = _(u"Casas sem convenio que utilizam somente serviço de "
u"registro")
else:
casas = sc['total']
titulo = _(u"Casas sem convenio que utilizam algum serviço de registro e/ou hospedagem")
titulo = _(u"Casas sem convenio que utilizam algum serviço de registro "
u"e/ou hospedagem")
if format == 'csv':
if fmt == 'csv':
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=casas.csv'
writer = csv.writer(response)
writer.writerow([titulo.encode('utf8')])
writer.writerow([u''])
writer.writerow([u'casa', u'uf', u'gerente', u'serviços'.encode('utf8')])
writer.writerow([u'casa', u'uf', u'gerentes',
u'serviços'.encode('utf8')])
for casa in casas:
writer.writerow([
casa.nome.encode('utf8'),
casa.municipio.uf.sigla.encode('utf8'),
casa.gerente_contas.nome_completo.encode('utf8'),
(u', '.join(casa.servico_set.filter(data_desativacao__isnull=True).values_list('tipo_servico__nome', flat=True))).encode('utf8'),
casa.lista_gerentes(fmt='lista').encode('utf8'),
(u', '.join(casa.servico_set.filter(
data_desativacao__isnull=True).values_list(
'tipo_servico__nome', flat=True))).encode('utf8'),
])
return response
elif format == 'json':
elif fmt == 'json':
data = {
'titulo': titulo,
'casas': [
{'nome': casa.nome,
'uf': casa.municipio.uf.sigla,
'gerente': casa.gerente_contas.nome_completo,
'servicos': list(casa.servico_set.filter(data_desativacao__isnull=True).values_list('tipo_servico__nome', flat=True))}
'gerentes': list(casa.gerentes_interlegis.all().values_list(
'nome_completo', flat=True)),
'servicos': list(casa.servico_set.filter(
data_desativacao__isnull=True).values_list(
'tipo_servico__nome', flat=True))}
for casa in casas
]
}
@ -211,7 +228,7 @@ def busca_informacoes_camara():
Busca informacoes no banco para montar tabela de resumo de camaras por projeto
Retorna um dicionario de listas
"""
camaras = CasaLegislativa.objects.filter(tipo__sigla='CM')
camaras = Orgao.objects.filter(tipo__sigla='CM')
convenios = Convenio.objects.filter(casa_legislativa__tipo__sigla='CM')
projetos = Projeto.objects.all()
@ -292,10 +309,10 @@ def busca_informacoes_camara():
def sem_convenio():
total = CasaLegislativa.objects.exclude(servico=None).filter(servico__data_desativacao=None, convenio=None).order_by('municipio__uf__sigla', 'nome').distinct('municipio__uf__sigla', 'nome')
hospedagem = CasaLegislativa.objects.exclude(servico=None).filter(servico__data_desativacao=None, servico__tipo_servico__modo='H', convenio=None).order_by('municipio__uf__sigla', 'nome').distinct('municipio__uf__sigla', 'nome')
total = Orgao.objects.exclude(servico=None).filter(servico__data_desativacao=None, convenio=None).order_by('municipio__uf__sigla', 'nome').distinct('municipio__uf__sigla', 'nome')
hospedagem = Orgao.objects.exclude(servico=None).filter(servico__data_desativacao=None, servico__tipo_servico__modo='H', convenio=None).order_by('municipio__uf__sigla', 'nome').distinct('municipio__uf__sigla', 'nome')
reg_keys = set(total.values_list('pk', flat=True)).difference(set(hospedagem.values_list('pk', flat=True)))
registro = CasaLegislativa.objects.filter(pk__in=reg_keys).order_by('municipio__uf__sigla', 'nome')
registro = Orgao.objects.filter(pk__in=reg_keys).order_by('municipio__uf__sigla', 'nome')
return {
'total': total,
'hospedagem': hospedagem,

21
sigi/apps/inventario/migrations/0002_auto_20210406_1945.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('inventario', '0001_initial'),
('casas', '0014_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='bem',
name='casa_legislativa',
field=models.ForeignKey(to='casas.Orgao'),
preserve_default=True,
),
]

39
sigi/apps/inventario/migrations/0003_auto_20210416_0841.py

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventario', '0002_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='bem',
name='fornecedor',
field=models.ForeignKey(to='inventario.Fornecedor', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
migrations.AlterField(
model_name='equipamento',
name='fabricante',
field=models.ForeignKey(to='inventario.Fabricante', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
migrations.AlterField(
model_name='equipamento',
name='modelo',
field=models.ForeignKey(to='inventario.ModeloEquipamento', on_delete=django.db.models.deletion.PROTECT),
preserve_default=True,
),
migrations.AlterField(
model_name='modeloequipamento',
name='tipo',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='tipo de equipamento', to='inventario.TipoEquipamento'),
preserve_default=True,
),
]

20
sigi/apps/inventario/models.py

@ -46,6 +46,7 @@ class TipoEquipamento(models.Model):
class ModeloEquipamento(models.Model):
tipo = models.ForeignKey(
TipoEquipamento,
on_delete=models.PROTECT,
verbose_name=_(u'tipo de equipamento')
)
modelo = models.CharField(max_length=30)
@ -60,8 +61,14 @@ class ModeloEquipamento(models.Model):
class Equipamento(models.Model):
fabricante = models.ForeignKey(Fabricante)
modelo = models.ForeignKey(ModeloEquipamento)
fabricante = models.ForeignKey(
Fabricante,
on_delete=models.PROTECT
)
modelo = models.ForeignKey(
ModeloEquipamento,
on_delete=models.PROTECT
)
class Meta:
unique_together = (('fabricante', 'modelo'),)
@ -72,9 +79,12 @@ class Equipamento(models.Model):
class Bem(models.Model):
casa_legislativa = models.ForeignKey('casas.CasaLegislativa')
equipamento = models.ForeignKey(Equipamento)
fornecedor = models.ForeignKey(Fornecedor)
casa_legislativa = models.ForeignKey(
'casas.Orgao',
on_delete=models.CASCADE
)
equipamento = models.ForeignKey(Equipamento, on_delete=models.CASCADE)
fornecedor = models.ForeignKey(Fornecedor, on_delete=models.PROTECT)
num_serie = models.CharField(
_(u'número de série'),
max_length=64,

3
sigi/apps/mdl/admin.py

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

6007
sigi/apps/mdl/base_models.py

File diff suppressed because it is too large

116
sigi/apps/mdl/migrations/0001_initial.py

@ -1,116 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Cohort',
fields=[
],
options={
'db_table': 'mdl_cohort',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CohortMembers',
fields=[
],
options={
'db_table': 'mdl_cohort_members',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Context',
fields=[
],
options={
'db_table': 'mdl_context',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Course',
fields=[
],
options={
'ordering': ['sortorder'],
'db_table': 'mdl_course',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CourseCategories',
fields=[
],
options={
'ordering': ['sortorder'],
'db_table': 'mdl_course_categories',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CourseCompletions',
fields=[
],
options={
'db_table': 'mdl_course_completions',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='CourseStats',
fields=[
],
options={
'db_table': 'sigi_course_stats',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Enrol',
fields=[
],
options={
'ordering': ['sortorder'],
'db_table': 'mdl_enrol',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='User',
fields=[
],
options={
'db_table': 'mdl_user',
'managed': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='UserEnrolments',
fields=[
],
options={
'db_table': 'mdl_user_enrolments',
'managed': False,
},
bases=(models.Model,),
),
]

360
sigi/apps/mdl/models.py

@ -1,360 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class CourseStats(models.Model):
# databaseview: (postgresql dialect):
# -- View: sigi_course_stats
#
# DROP VIEW sigi_course_stats;
#
# CREATE OR REPLACE VIEW sigi_course_stats AS
# SELECT cc.id AS categoryid, c.id AS courseid,
# CASE
# WHEN e.enrol = 'ilbeadtutorado' AND ue.status = 1 THEN 'N' -- Rejeitada
# WHEN e.enrol = 'ilbead' AND ue.timeend > date_part('epoch', now()) THEN 'C' -- Em curso
# WHEN e.enrol = 'ilbead' and ue.timeend < date_part('epoch', now()) and co.timecompleted is null and gg.finalgrade is null then 'L' -- Abandono
# WHEN (co.timestarted = 0 OR co.timestarted IS NULL) AND gg.finalgrade IS NOT NULL THEN 'R' -- Reprovada
# WHEN co.timestarted = 0 OR co.timestarted IS NULL THEN 'L' -- Abandono
# WHEN co.timestarted > 0 AND co.timecompleted IS NULL THEN 'R' -- Reprovado
# WHEN co.timecompleted IS NOT NULL THEN 'A' -- Aprovado
# ELSE 'I' -- Indeterminado
# END AS completionstatus, count(ue.id) AS usercount, avg(gg.finalgrade) as gradeaverage
# FROM mdl_course_categories cc
# JOIN mdl_course c ON c.category = cc.id
# JOIN mdl_enrol e ON e.courseid = c.id
# JOIN mdl_user_enrolments ue ON ue.enrolid = e.id
# JOIN mdl_grade_items gi ON gi.courseid = c.id AND gi.itemtype = 'course'
# LEFT JOIN mdl_grade_grades gg ON gg.itemid = gi.id AND gg.userid = ue.userid
# LEFT JOIN mdl_course_completions co ON co.userid = ue.userid AND co.course = c.id
# GROUP BY cc.id, c.id, completionstatus;
COMPLETIONSTATUS_CHOICES = (
('N', u'Matrículas rejeitadas'),
('C', u'Em curso'),
('R', u'Reprovação'),
('L', u'Abandono'),
('A', u'Aprovação'),
('I', u'Indeterminado'),)
category = models.ForeignKey('CourseCategories', db_column='categoryid', primary_key=True)
course = models.ForeignKey('Course', db_column='courseid')
completionstatus = models.CharField(max_length=1, choices=COMPLETIONSTATUS_CHOICES)
usercount = models.IntegerField()
gradeaverage = models.FloatField()
class Meta:
managed = False
db_table = 'sigi_course_stats'
def __unicode__(self):
return '%s - %s: %s' % (self.category.name, self.course.fullname, self.usercount)
class Cohort(models.Model):
id = models.BigIntegerField(primary_key=True)
context = models.ForeignKey('Context', db_column='contextid')
name = models.CharField(max_length=254)
idnumber = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
descriptionformat = models.SmallIntegerField()
component = models.CharField(max_length=100)
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
visible = models.SmallIntegerField()
# Manytomany
members = models.ManyToManyField('User', through='CohortMembers')
class Meta:
managed = False
db_table = 'mdl_cohort'
def __unicode__(self):
return self.name
class CohortMembers(models.Model):
id = models.BigIntegerField(primary_key=True)
cohort = models.ForeignKey('Cohort', db_column='cohortid')
user = models.ForeignKey('User', db_column='userid')
timeadded = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_cohort_members'
class Context(models.Model):
CONTEXT_SYSTEM = 10 # System context level - only one instance in every system
CONTEXT_USER = 30 # User context level - one instance for each user describing what others can do to user
CONTEXT_COURSECAT = 40 # Course category context level - one instance for each category
CONTEXT_COURSE = 50 # Course context level - one instances for each course
CONTEXT_MODULE = 70 # Course module context level - one instance for each course module
CONTEXT_BLOCK = 80 # Block context level - one instance for each block, sticky blocks are tricky
# because ppl think they should be able to override them at lower contexts.
# Any other context level instance can be parent of block context.
id = models.BigIntegerField(primary_key=True)
contextlevel = models.BigIntegerField()
instanceid = models.BigIntegerField()
path = models.CharField(max_length=255, blank=True)
depth = models.SmallIntegerField()
class Meta:
managed = False
db_table = 'mdl_context'
def __unicode__(self):
return self.path
class Course(models.Model):
id = models.BigIntegerField(primary_key=True)
category = models.ForeignKey('CourseCategories', db_column='category', related_name='courses')
sortorder = models.BigIntegerField()
fullname = models.CharField(max_length=254)
shortname = models.CharField(max_length=255)
idnumber = models.CharField(max_length=100)
summary = models.TextField(blank=True)
format = models.CharField(max_length=21)
showgrades = models.SmallIntegerField()
newsitems = models.IntegerField()
startdate = models.BigIntegerField()
marker = models.BigIntegerField()
maxbytes = models.BigIntegerField()
showreports = models.SmallIntegerField()
visible = models.SmallIntegerField()
groupmode = models.SmallIntegerField()
groupmodeforce = models.SmallIntegerField()
lang = models.CharField(max_length=30)
theme = models.CharField(max_length=50)
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
requested = models.SmallIntegerField()
defaultgroupingid = models.BigIntegerField()
enrolmax = models.BigIntegerField()
enablecompletion = models.SmallIntegerField()
legacyfiles = models.SmallIntegerField()
summaryformat = models.SmallIntegerField()
completionnotify = models.SmallIntegerField()
visibleold = models.SmallIntegerField()
calendartype = models.CharField(max_length=30)
cacherev = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_course'
ordering = ['sortorder', ]
def __unicode__(self):
return self.fullname
def total_alunos(self):
return sum(e.user_enrolments.count() for e in self.enrols.all())
def total_ativos(self):
return sum(e.user_enrolments.filter(status=0).count() for e in self.enrols.all())
def get_matriculas(self):
q = UserEnrolments.objects.none()
for e in self.enrols.all():
q = q | e.user_enrolments.all()
return q
class CourseCategories(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
parent = models.ForeignKey('CourseCategories', db_column='parent', related_name='children')
sortorder = models.BigIntegerField()
coursecount = models.BigIntegerField()
visible = models.SmallIntegerField()
timemodified = models.BigIntegerField()
depth = models.BigIntegerField()
path = models.CharField(max_length=255)
theme = models.CharField(max_length=50, blank=True)
descriptionformat = models.SmallIntegerField()
visibleold = models.SmallIntegerField()
idnumber = models.CharField(max_length=100, blank=True)
class Meta:
managed = False
db_table = 'mdl_course_categories'
ordering = ['sortorder', ]
def __unicode__(self):
return self.name
def context(self):
return Context.objects.get(instanceid=self.id, contextlevel=Context.CONTEXT_COURSECAT)
def total_turmas(self):
return self.coursecount + sum([c.coursecount for c in self.children.all()])
def total_alunos(self):
total = 0
total = total + sum(c.total_alunos() for c in self.courses.all())
total = total + sum(c.total_alunos() for c in self.children.all())
return total
def cohortids(self):
cids = [c.pk for c in self.context().cohort_set.all()]
for c in self.children.all():
cids = cids + c.cohortids()
return cids
def total_alunos_cohort(self):
return sum([c.members.distinct().count() for c in Cohort.objects.filter(pk__in=self.cohortids())])
def get_all_courses(self, only_visible=False):
if only_visible:
q = self.courses.filter(visible=1)
else:
q = self.courses.all()
for c in self.children.all():
q = q | c.get_all_courses(only_visible=only_visible)
return q
class CourseCompletions(models.Model):
id = models.BigIntegerField(primary_key=True)
user = models.ForeignKey('User', db_column='userid')
course = models.ForeignKey('Course', db_column='course')
timeenrolled = models.BigIntegerField()
timestarted = models.BigIntegerField()
timecompleted = models.BigIntegerField(blank=True, null=True)
reaggregate = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_course_completions'
class Enrol(models.Model):
id = models.BigIntegerField(primary_key=True)
enrol = models.CharField(max_length=20)
status = models.BigIntegerField()
course = models.ForeignKey('Course', db_column='courseid', related_name='enrols')
sortorder = models.BigIntegerField()
name = models.CharField(max_length=255, blank=True)
enrolperiod = models.BigIntegerField(blank=True, null=True)
enrolstartdate = models.BigIntegerField(blank=True, null=True)
enrolenddate = models.BigIntegerField(blank=True, null=True)
expirynotify = models.SmallIntegerField(blank=True, null=True)
expirythreshold = models.BigIntegerField(blank=True, null=True)
notifyall = models.SmallIntegerField(blank=True, null=True)
password = models.CharField(max_length=50, blank=True)
cost = models.CharField(max_length=20, blank=True)
currency = models.CharField(max_length=3, blank=True)
roleid = models.BigIntegerField(blank=True, null=True)
customint1 = models.BigIntegerField(blank=True, null=True)
customint2 = models.BigIntegerField(blank=True, null=True)
customint3 = models.BigIntegerField(blank=True, null=True)
customint4 = models.BigIntegerField(blank=True, null=True)
customchar1 = models.CharField(max_length=255, blank=True)
customchar2 = models.CharField(max_length=255, blank=True)
customdec1 = models.DecimalField(max_digits=12, decimal_places=7, blank=True, null=True)
customdec2 = models.DecimalField(max_digits=12, decimal_places=7, blank=True, null=True)
customtext1 = models.TextField(blank=True)
customtext2 = models.TextField(blank=True)
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
customint5 = models.BigIntegerField(blank=True, null=True)
customint6 = models.BigIntegerField(blank=True, null=True)
customint7 = models.BigIntegerField(blank=True, null=True)
customint8 = models.BigIntegerField(blank=True, null=True)
customchar3 = models.CharField(max_length=1333, blank=True)
customtext3 = models.TextField(blank=True)
customtext4 = models.TextField(blank=True)
class Meta:
managed = False
db_table = 'mdl_enrol'
ordering = ['sortorder', ]
def __unicode__(self):
if not self.name:
return self.enrol
return self.name
class User(models.Model):
id = models.BigIntegerField(primary_key=True)
auth = models.CharField(max_length=20)
confirmed = models.SmallIntegerField()
policyagreed = models.SmallIntegerField()
deleted = models.SmallIntegerField()
mnethostid = models.BigIntegerField()
username = models.CharField(max_length=100)
password = models.CharField(max_length=255)
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
email = models.CharField(max_length=100)
emailstop = models.SmallIntegerField()
icq = models.CharField(max_length=15)
skype = models.CharField(max_length=50)
yahoo = models.CharField(max_length=50)
aim = models.CharField(max_length=50)
msn = models.CharField(max_length=50)
phone1 = models.CharField(max_length=20)
phone2 = models.CharField(max_length=20)
institution = models.CharField(max_length=255)
department = models.CharField(max_length=255)
address = models.CharField(max_length=255)
city = models.CharField(max_length=120)
country = models.CharField(max_length=2)
lang = models.CharField(max_length=30)
theme = models.CharField(max_length=50)
timezone = models.CharField(max_length=100)
firstaccess = models.BigIntegerField()
lastaccess = models.BigIntegerField()
lastlogin = models.BigIntegerField()
currentlogin = models.BigIntegerField()
lastip = models.CharField(max_length=45)
secret = models.CharField(max_length=15)
picture = models.BigIntegerField()
url = models.CharField(max_length=255)
description = models.TextField(blank=True)
mailformat = models.SmallIntegerField()
maildigest = models.SmallIntegerField()
maildisplay = models.SmallIntegerField()
autosubscribe = models.SmallIntegerField()
trackforums = models.SmallIntegerField()
timemodified = models.BigIntegerField()
trustbitmask = models.BigIntegerField()
imagealt = models.CharField(max_length=255, blank=True)
idnumber = models.CharField(max_length=255)
descriptionformat = models.SmallIntegerField()
timecreated = models.BigIntegerField()
suspended = models.SmallIntegerField()
lastnamephonetic = models.CharField(max_length=255, blank=True)
firstnamephonetic = models.CharField(max_length=255, blank=True)
middlename = models.CharField(max_length=255, blank=True)
alternatename = models.CharField(max_length=255, blank=True)
calendartype = models.CharField(max_length=30)
class Meta:
managed = False
db_table = 'mdl_user'
def __unicode__(self):
return u'%s %s' % (self.firstname, self.lastname)
class UserEnrolments(models.Model):
id = models.BigIntegerField(primary_key=True)
status = models.BigIntegerField()
enrol = models.ForeignKey('Enrol', db_column='enrolid', related_name='user_enrolments')
user = models.ForeignKey('User', db_column='userid', related_name='Enrolments')
timestart = models.BigIntegerField()
timeend = models.BigIntegerField()
modifierid = models.BigIntegerField()
timecreated = models.BigIntegerField()
timemodified = models.BigIntegerField()
class Meta:
managed = False
db_table = 'mdl_user_enrolments'

3
sigi/apps/mdl/views.py

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

21
sigi/apps/metas/migrations/0002_auto_20210406_1945.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('metas', '0001_initial'),
('casas', '0014_auto_20210406_1945'),
]
operations = [
migrations.AlterField(
model_name='planodiretor',
name='casa_legislativa',
field=models.ForeignKey(verbose_name='Casa Legislativa', to='casas.Orgao'),
preserve_default=True,
),
]

21
sigi/apps/metas/models.py

@ -3,7 +3,7 @@ from datetime import date
from django.db import models
from django.utils.translation import ugettext as _
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.casas.models import Orgao
from sigi.apps.convenios.models import Projeto, Convenio
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.financeiro.models import Desembolso
@ -18,7 +18,12 @@ class Meta(models.Model):
('COUNT_PDIR', _(u'Quantidade de planos diretores')),
('COUNT_CONV', _(u'Quantidade de casas conveniadas')),
)
projeto = models.ForeignKey(Projeto, verbose_name=_(u'Projeto'), help_text=_(u'Projeto ao qual a meta se refere'))
projeto = models.ForeignKey(
Projeto,
on_delete=models.CASCADE,
verbose_name=_(u'Projeto'),
help_text=_(u'Projeto ao qual a meta se refere')
)
titulo = models.CharField(_(u'Título'), max_length=40, help_text=_(u'Título da meta que aparecerá no dashboard'))
descricao = models.TextField(_(u'Descrição'))
data_inicio = models.DateField(_(u'Data inicial'), help_text=_(u'Início do período de cômputo da meta'))
@ -114,8 +119,16 @@ class PlanoDiretor(models.Model):
('E', _(u'Entregue')),
('I', _(u'Implantado')),
)
projeto = models.ForeignKey(Projeto, verbose_name=_(u'Projeto'))
casa_legislativa = models.ForeignKey(CasaLegislativa, verbose_name=_(u'Casa Legislativa'))
projeto = models.ForeignKey(
Projeto,
on_delete=models.CASCADE,
verbose_name=_(u'Projeto')
)
casa_legislativa = models.ForeignKey(
Orgao,
on_delete=models.CASCADE,
verbose_name=_(u'Casa Legislativa')
)
casa_legislativa.casa_uf_filter = True
status = models.CharField(_(u'Status'), max_length=1, choices=STATUS_CHOICE, default='E')
data_entrega = models.DateField(_(u'Data de entrega'), blank=True, null=True)

58
sigi/apps/metas/static/metas/css/openmap.css

@ -0,0 +1,58 @@
body, html, .mapbox, #map {
height: 100%;
}
.filterwrap {
background-color: rgba(255,255,255,0.5);
position: absolute;
top: 0;
left: 0;
z-index: 314159;
height: 100%;
max-height: 100%;
overflow-y: auto;
}
.sigi-logo {
pointer-events: none;
position: absolute;
top: 0;
left: 0;
z-index: 314159;
background-color: transparent;
width: 100%;
text-align: right;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
padding-right: 20px;
}
.sigi-logo h3 {
font-weight: bolder;
margin-bottom: 0px;
}
.sigi-logo a {
pointer-events: auto;
}
.sigi-logo div {
float: right;
}
.sigi-logo img {
margin: 15px;
width: 60px;
height: 60px;
}
.region-ufs {
margin-left: 15px;
}
#search-text {
min-width: 300px;
}
.ui-autocomplete {
max-width: 300px;
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.05);
box-shadow: 0 1px 2px rgba(0,0,0,.05);
border-color: #ddd;
margin-bottom: 20px;
background-color: #fff;
border: 1px solid transparent;
border-radius: 4px;
padding: 15px;
font-size: 10px;
}

93
sigi/apps/metas/templates/metas/lista_casas.html

@ -0,0 +1,93 @@
{% extends "base_report.html" %}
{% load mapa_tags %}
{% load i18n %}
{% block extra_head %}
<style>
table.data, table.data td, table.data th {
border: 1px solid #CCCCCC;
border-collapse: collapse;
font-size: 10px;
padding: 2px;
}
table.filters, table.filters td, table.filters th {
border-bottom: 1px solid #CCCCCC;
font-size: 10px;
padding-top: 3px;
vertical-align: bottom;
text-align: left;
line-height: 16px;
}
table.filters th {
width: 12%;
}
td.nome_uf {
padding: 0 5px !important;
}
ul {
list-style-type: none;
margin: 0px;
padding: 0px;
}
</style>
{% endblock %}
{% block pagesize %}A4 landscape{% endblock pagesize %}
{% block title %}{% trans 'Lista de Casas atendidas' %}{% endblock title %}
{% block report %}
<h1>{% trans 'Lista de Casas atendidas' %}</h1>
<table class="filters">
{% if tipos_orgao %}
<tr><th>{% trans 'Tipos de órgão' %}</th><td>{% for t in tipos_orgao %}{{ t.nome }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
{% endif %}
{% if tipos_servico %}
<tr><th>{% trans 'Tipos de serviço' %}</th><td>{% for s in tipos_servico %}{{ s.nome }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
{% endif %}
{% if tipos_convenio %}
<tr><th>{% trans 'Tipos de convênio' %}</th><td>{% for c in tipos_convenio %}{{ c.nome }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
{% endif %}
{% if gerentes %}
<tr><th>{% trans 'Gerentes Interlegis' %}</th><td>{% for g in gerentes %}{{ g.nome_completo }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
{% endif %}
{% if ufs %}
<tr><th>{% trans 'Estados' %}</th><td>{% for uf in ufs %}{{ uf.nome }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
{% endif %}
</table>
<br/>
<table class="data" repeat="1">
<tr>
<th>{% trans 'Casa Legislativa' %}</th>
<th>{% trans 'Estado' %}</th>
<th>{% trans 'Região' %}</th>
<th>{% trans 'Serviços' %}</th>
<th>{% trans 'Convênios' %}</th>
<th>{% trans 'Gerente(s)' %}</th>
</tr>
{% for casa in casas %}
<tr>
<td>{{ casa.nome }}&nbsp;</td>
<td>{{ casa.municipio.uf.nome }}</td>
<td>{{ casa.municipio.uf.get_regiao_display }}</td>
<td><ul>{% for s in casa.servico_set.all %}
{% if s.data_desativacao == None %}
<li>{{ s }}</li>
{% endif %}
{% endfor %}</ul></td>
<td><ul>{% for c in casa.convenio_set.all %}
<li>{{ c }}</li>
{% endfor %}
</ul></td>
<td><ul>{% for g in casa.gerentes_interlegis.all %}
<li>{{ g }}</li>
{% endfor %}</ul>
</td>
</tr>
{% endfor %}
</table>
{% endblock %}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save