Browse Source

migração da app 'parlamentares'

stable/2.0
Breno Teixeira 11 years ago
parent
commit
b110959f6a
  1. 0
      sigi/apps/casas/__init__.py
  2. 243
      sigi/apps/casas/admin.py
  3. 17
      sigi/apps/casas/forms.py
  4. 303
      sigi/apps/casas/models.py
  5. 574
      sigi/apps/casas/reports.py
  6. 234
      sigi/apps/casas/templates/casas/carrinho.html
  7. 14
      sigi/apps/casas/templates/casas/change_form.html
  8. 15
      sigi/apps/casas/templates/casas/change_list.html
  9. 377
      sigi/apps/casas/views.py
  10. 0
      sigi/apps/convenios/__init__.py
  11. 139
      sigi/apps/convenios/admin.py
  12. 188
      sigi/apps/convenios/models.py
  13. 316
      sigi/apps/convenios/reports.py
  14. 158
      sigi/apps/convenios/templates/convenios/carrinho.html
  15. 40
      sigi/apps/convenios/templates/convenios/change_list.html
  16. 145
      sigi/apps/convenios/templates/convenios/tabela_regiao.html
  17. 345
      sigi/apps/convenios/views.py
  18. 0
      sigi/apps/diagnosticos/__init__.py
  19. 129
      sigi/apps/diagnosticos/admin.py
  20. 23
      sigi/apps/diagnosticos/decorators.py
  21. 32502
      sigi/apps/diagnosticos/fixtures/initial_data.json
  22. 171
      sigi/apps/diagnosticos/forms.py
  23. 247
      sigi/apps/diagnosticos/models.py
  24. 0
      sigi/apps/diagnosticos/templatetags/__init__.py
  25. 401
      sigi/apps/diagnosticos/templatetags/smart_if.py
  26. 15
      sigi/apps/diagnosticos/tests.py
  27. 35
      sigi/apps/diagnosticos/urls.py
  28. 351
      sigi/apps/diagnosticos/views.py
  29. 61
      sigi/apps/diagnosticos/widgets.py
  30. 0
      sigi/apps/financeiro/__init__.py
  31. 9
      sigi/apps/financeiro/admin.py
  32. 3
      sigi/apps/financeiro/forms.py
  33. 18
      sigi/apps/financeiro/models.py
  34. 3
      sigi/apps/financeiro/urls.py
  35. 1
      sigi/apps/financeiro/views.py
  36. 1
      sigi/apps/geraldo
  37. 0
      sigi/apps/inventario/__init__.py
  38. 71
      sigi/apps/inventario/admin.py
  39. 280
      sigi/apps/inventario/fixtures/initial_data.json
  40. 90
      sigi/apps/inventario/models.py
  41. 0
      sigi/apps/mesas/__init__.py
  42. 102
      sigi/apps/mesas/admin.py
  43. 44
      sigi/apps/mesas/fixtures/initial_data.json
  44. 122
      sigi/apps/mesas/models.py
  45. 0
      sigi/apps/metas/__init__.py
  46. 46
      sigi/apps/metas/admin.py
  47. 3
      sigi/apps/metas/forms.py
  48. 0
      sigi/apps/metas/management/__init__.py
  49. 0
      sigi/apps/metas/management/commands/__init__.py
  50. 31
      sigi/apps/metas/management/commands/gera_map_data.py
  51. 128
      sigi/apps/metas/models.py
  52. 0
      sigi/apps/metas/templatetags/__init__.py
  53. 35
      sigi/apps/metas/templatetags/mapa_tags.py
  54. 3
      sigi/apps/metas/urls.py
  55. 345
      sigi/apps/metas/views.py
  56. 0
      sigi/apps/ocorrencias/__init__.py
  57. 105
      sigi/apps/ocorrencias/admin.py
  58. 79
      sigi/apps/ocorrencias/models.py
  59. 0
      sigi/apps/parlamentares/__init__.py
  60. 75
      sigi/apps/parlamentares/admin.py
  61. 218
      sigi/apps/parlamentares/fixtures/initial_data.json
  62. 81
      sigi/apps/parlamentares/models.py
  63. 539
      sigi/apps/parlamentares/reports.py
  64. 78
      sigi/apps/parlamentares/templates/parlamentares/carrinho.html
  65. 14
      sigi/apps/parlamentares/templates/parlamentares/change_form.html
  66. 9
      sigi/apps/parlamentares/templates/parlamentares/change_list.html
  67. 149
      sigi/apps/parlamentares/views.py
  68. 0
      sigi/apps/relatorios/__init__.py
  69. 3
      sigi/apps/relatorios/models.py
  70. 76
      sigi/apps/relatorios/reports.py
  71. 23
      sigi/apps/relatorios/tests.py
  72. 1
      sigi/apps/relatorios/views.py
  73. 0
      sigi/apps/servicos/__init__.py
  74. 214
      sigi/apps/servicos/admin.py
  75. 1
      sigi/apps/servicos/fixtures/initial_data.json
  76. 0
      sigi/apps/servicos/management/__init__.py
  77. 0
      sigi/apps/servicos/management/commands/__init__.py
  78. 35
      sigi/apps/servicos/management/commands/atualiza_uso_servico.py
  79. 196
      sigi/apps/servicos/models.py
  80. 122
      sigi/apps/servicos/models.py~
  81. 127
      sigi/apps/servicos/views.py
  82. 11
      sigi/settings.py

0
sigi/apps/casas/__init__.py

243
sigi/apps/casas/admin.py

@ -0,0 +1,243 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.contrib.contenttypes import generic
from django.http import HttpResponse, HttpResponseRedirect
from geraldo.generators import PDFGenerator
from sigi.apps.casas.forms import CasaLegislativaForm
from sigi.apps.casas.models import CasaLegislativa, Presidente, Funcionario, TipoCasaLegislativa
from sigi.apps.casas.reports import CasasLegislativasLabels, CasasLegislativasReport
from sigi.apps.casas.views import report_complete, labels_report, export_csv, \
labels_report_sem_presidente, report, \
adicionar_casas_carrinho
from sigi.apps.utils import queryset_ascii
from sigi.apps.contatos.models import Telefone
from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo
from sigi.apps.mesas.models import Legislatura
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.inventario.models import Bem
from sigi.apps.servicos.models import Servico
from sigi.apps.metas.models import PlanoDiretor
from sigi.apps.ocorrencias.models import Ocorrencia
class TelefonesInline(generic.GenericTabularInline):
model = Telefone
readonly_fields = ('ult_alteracao',)
extra = 1
class PresidenteInline(admin.StackedInline):
model = Presidente
exclude = ['cargo','funcao']
readonly_fields = ('ult_alteracao',)
extra = 1
max_num = 1
inlines = (TelefonesInline)
class FuncionariosInline(admin.StackedInline):
model = Funcionario
fieldsets = ((None, {
'fields': (('nome', 'sexo', 'nota', 'email'), ('cargo', 'funcao', 'setor', 'tempo_de_servico'), 'ult_alteracao')
}),)
readonly_fields = ('ult_alteracao',)
extra = 1
inlines = (TelefonesInline,)
def queryset(self, request):
return self.model.objects.exclude(cargo="Presidente")
class ConveniosInline(admin.StackedInline):
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'),
('data_devolucao_sem_assinatura','data_retorno_sem_assinatura',),
('get_tramitacoes', 'get_anexos', 'get_equipamentos',),
)}
),
)
readonly_fields = ['get_tramitacoes', 'get_anexos', 'get_equipamentos', 'link_convenio',]
extra = 0
def get_tramitacoes(self, obj):
return '<br/>'.join([t.__unicode__() for t in obj.tramitacao_set.all()])
get_tramitacoes.short_description = '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 = '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 = '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"/>
<a id="lookup_edit_convenio-%s" href="%s" class="changelink" onclick="return showRelatedObjectLookupPopup(this)">
Editar
</a>""" % (obj.pk, obj.pk, url)
link_convenio.short_description = '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 = '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 ""
from django.core.urlresolvers import reverse
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 = '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']
extra = 0
max_num = 0
can_delete = False
class PlanoDiretorInline(admin.TabularInline):
model = PlanoDiretor
class OcorrenciaInline(admin.TabularInline):
model = Ocorrencia
fields = ('data_criacao', 'assunto', 'prioridade', 'status', 'data_modificacao', 'setor_responsavel',)
readonly_fields = ('data_criacao', 'assunto', 'prioridade', 'status', 'data_modificacao', 'setor_responsavel',)
extra = 0
max_num = 0
can_delete = False
class CasaLegislativaAdmin(admin.ModelAdmin):
form = CasaLegislativaForm
change_form_template = 'casas/change_form.html'
change_list_template = 'casas/change_list.html'
actions = ['adicionar_casas',]
inlines = (TelefonesInline, PresidenteInline, FuncionariosInline, ConveniosInline, LegislaturaInline,
DiagnosticoInline, BemInline, ServicoInline, PlanoDiretorInline, OcorrenciaInline, )
list_display = ('nome','municipio','logradouro', 'ult_alt_endereco', 'get_convenios')
list_display_links = ('nome',)
list_filter = ('tipo', 'municipio', 'search_text')
ordering = ('nome','municipio__uf')
queyrset = queryset_ascii
fieldsets = (
(None, {
'fields': ('tipo', 'nome', 'cnpj', 'num_parlamentares')
}),
('Endereço', {
'fields': ('data_instalacao', 'logradouro', 'bairro',
'municipio', 'cep', 'pagina_web','email', 'ult_alt_endereco'),
}),
('Outras informações', {
'classes': ('collapse',),
'fields': ('observacoes', 'foto'),
}),
)
raw_id_fields = ('municipio',)
readonly_fields = ['num_parlamentares',]
search_fields = ('search_text','cnpj', 'bairro', 'logradouro',
'cep', 'municipio__nome', 'municipio__uf__nome',
'municipio__codigo_ibge', 'pagina_web', 'observacoes')
def get_convenios(self, obj):
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 changelist_view(self, request, extra_context=None):
return super(CasaLegislativaAdmin, 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']
def etiqueta(self,request,queryset):
return labels_report(request,queryset=queryset)
etiqueta.short_description = "Gerar etiqueta(s) da(s) casa(s) selecionada(s)"
def etiqueta_sem_presidente(self,request,queryset):
return labels_report_sem_presidente(request,queryset=queryset)
etiqueta_sem_presidente.short_description = "Gerar etiqueta(s) sem presidente da(s) casa(s) 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"
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)"
def relatorio_csv(self,request,queryset):
return export_csv(request)
relatorio_csv.short_description = u"Exportar casa(s) selecionada(s) para CSV"
def adicionar_casas(self, request, queryset):
if 'carrinho_casas' in request.session:
#if request.session.has_key('carrinho_casas'):
q1 = len(request.session['carrinho_casas'])
else:
q1 = 0
response = adicionar_casas_carrinho(request,queryset=queryset)
q2 = len(request.session['carrinho_casas'])
quant = q2 - q1
if quant:
self.message_user(request,str(q2-q1)+" Casas Legislativas adicionadas no carrinho" )
else:
self.message_user(request,"As Casas Legislativas selecionadas já foram adicionadas anteriormente" )
return HttpResponseRedirect('.')
adicionar_casas.short_description = u"Armazenar casas no carrinho para exportar"
def get_actions(self, request):
actions = super(CasaLegislativaAdmin, self).get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected']
return actions
admin.site.register(CasaLegislativa, CasaLegislativaAdmin)
admin.site.register(TipoCasaLegislativa)

17
sigi/apps/casas/forms.py

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from django import forms
from localflavor.br.forms import BRZipCodeField
from sigi.apps.casas.models import CasaLegislativa
class CasaLegislativaForm(forms.ModelForm):
#cnpj = BRCNPJField(
# label='CNPJ',
# required=False,
# help_text='Utilize o formato <em>XX.XXX.XXX/XXXX-XX</em> ou '
# 'insira apenas os dígitos.'
#)
cep = BRZipCodeField(label='CEP', help_text='Formato: <em>XXXXX-XXX</em>.')
class Meta:
model = CasaLegislativa

303
sigi/apps/casas/models.py

@ -0,0 +1,303 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.contenttypes import generic
from sigi.apps.parlamentares.models import Parlamentar
from sigi.apps.utils import SearchField
from datetime import datetime
import random
from unicodedata import normalize
from sigi.apps.contatos.models import Municipio
class TipoCasaLegislativa(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
)
def __unicode__(self):
return self.nome
class CasaLegislativa(models.Model):
""" Modelo para representar uma Casa Legislativa
"""
nome = models.CharField(
max_length=60,
help_text='Exemplo: <em>Câmara Municipal de Pains</em>.'
)
# 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)
# num_parlamentares = models.PositiveIntegerField('Número de parlamentares')
codigo_interlegis = models.CharField('Código Interlegis', max_length=3, blank=True)
codigo_interlegis.ts_filter = True
# Informações de contato
logradouro = models.CharField(
max_length=100,
help_text='Avenida, rua, praça, jardim, parque...'
)
bairro = models.CharField(max_length=100, blank=True)
municipio = models.ForeignKey(
'contatos.Municipio',
verbose_name='município'
)
municipio.uf_filter = True
cep = models.CharField(max_length=32)
email = models.EmailField('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>.',
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(
upload_to='imagens/casas',
width_field='foto_largura',
height_field='foto_altura',
blank=True
)
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)
class Meta:
ordering = ('nome',)
unique_together = ('municipio', 'tipo')
verbose_name = 'Casa Legislativa'
verbose_name_plural = 'Casas Legislativas'
@property
def num_parlamentares(self):
if not self.legislatura_set.exists():
return 0
return self.legislatura_set.latest('data_inicio').total_parlamentares
@property
def telefone(self):
""" Link para acessar diretamente o primeiro telefone cadastrado da casa
Util para relatorios antigos
"""
telefones = self.telefones.all()
if telefones:
return telefones[0]
return None
@property
def presidente(self):
""" Link para acessar diretamente o contato do presidente da casa
Util para relatorios antigos
"""
try:
if self.funcionario_set.filter(setor='presidente').count() > 1:
return self.funcionario_set.filter(setor='presidente')[0]
else:
return self.funcionario_set.get(setor='presidente')
except Funcionario.DoesNotExist:
return None
@property
def total_parlamentares(self):
"""
Calcula o total de parlamentares atual da Casa:
- O total de parlamentares da mesas.legislatura mais recente, ou
- num_parlamentares ou
- 0 se não tiver nenhuma das informações
"""
if self.legislatura_set.exists():
return self.legislatura_set.all()[0].total_parlamentares
if self.num_parlamentares is not None:
return self.num_parlamentares
return 0
def gerarCodigoInterlegis(self):
codigo = self.codigo_interlegis
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:
# Só grava o código se ele for inédito
self.codigo_interlegis = codigo
self.save()
return codigo
# Se já existe, então trata a Assembleia como uma Casa qualquer.
cityName = normalize('NFKD', unicode(self.municipio.nome)).encode('ascii','ignore')
cityName = cityName.upper().strip()
cityName = cityName.replace(' DA ',' ')
cityName = cityName.replace(' DE ',' ')
cityName = cityName.replace(' DO ',' ')
# estratégia 1 - Pegar as 1ª letra de cada nome da cidade
codigo = ''.join([x[0] for x in cityName.split(' ')[:3]])
# Se o código ficou com menos que três letras, pegar as 2 primeiras
if len(codigo) < 3:
codigo = ''.join([x[0:2] for x in cityName.split(' ')[:3]])[:3]
# Se ainda ficou com menos de três letras, então o nome da cidade só
# tem uma palavra. Pegue as três primeiras letras da palavra
if len(codigo) < 3:
codigo = cityName[:3]
# Se o código já existir, substituir a última letra do código pela
# última letra do nome da cidade, e ir recuando, letra a letra,
# até achar um novo código.
cityName = cityName.replace(' ', '')
ultima = len(cityName)
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
count() > 0 and ultima > 0:
codigo = codigo[:2] + cityName[ultima - 1: ultima]
ultima -= 1
# Se usou todas as letras do nome na última posição e ainda assim
# 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:
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:
codigo = codigo_cons
# Se ainda não gerou um nome único, vamos colocar dígitos no
# último caractere, de A a Z
i = 'A'
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
count() > 0 and i <= 'Z':
codigo = codigo[:2] + str(i)
i = chr(ord(i) + 1)
# Se não encontrou, comece a gerar strings com 3 letras aleatórias
# tiradas do nome da cidade, até gerar uma que não existe. Tentar
# 100 vezes apenas
i = 0
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
count() > 0 and i < 100:
codigo = random.choice(cityName) + random.choice(cityName) + \
random.choice(cityName)
i += 1
# Caramba! Só resta então gerar o código com 3 letras aleatórias
# quaisquer do alfabeto!
i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
while CasaLegislativa.objects.filter(codigo_interlegis=codigo). \
count() > 0:
codigo = random.choice(i) + random.choice(i) + \
random.choice(i)
self.codigo_interlegis = codigo
self.save()
return codigo
def __unicode__(self):
return self.nome
def save(self, *args, **kwargs):
address_changed = False
if self.pk is not None:
original = CasaLegislativa.objects.get(pk=self.pk)
if (self.logradouro != original.logradouro or
self.bairro != original.bairro or
self.municipio != original.municipio or
self.cep != original.cep):
address_changed = True
else:
address_changed = True
if address_changed:
self.ult_alt_endereco = datetime.now()
return super(CasaLegislativa, self).save(*args, **kwargs)
class Funcionario(models.Model):
""" Modelo para registrar contatos vinculados às
Casas Legislativas
"""
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"),
]
SEXO_CHOICES = [
("M", "Masculino"),
("F", "Feminino")
]
casa_legislativa = models.ForeignKey(CasaLegislativa)
nome = models.CharField('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=False)
class Meta:
ordering = ('nome',)
verbose_name = 'contato Casa Legislativa'
verbose_name_plural = 'contatos Casas Legislativa'
def __unicode__(self):
return self.nome
class PresidenteManager(models.Manager):
def get_query_set(self):
qs = super(PresidenteManager, self).get_query_set()
qs = qs.filter(setor='presidente')
return qs
class Presidente(Funcionario):
class Meta:
proxy = True
objects = PresidenteManager()
def save(self, *args, **kwargs):
self.setor = 'presidente'
self.cargo = 'Presidente'
self.funcao = 'Presidente'
return super(Presidente, self).save(*args, **kwargs)

574
sigi/apps/casas/reports.py

@ -0,0 +1,574 @@
# -*- coding: utf-8 -*-
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib.enums import TA_CENTER, TA_RIGHT
from geraldo import Report, DetailBand, Label, ObjectValue, ManyElements, \
ReportGroup, ReportBand, landscape, SubReport, BAND_WIDTH,SystemField
from sigi.apps.relatorios.reports import ReportDefault
from geraldo.graphics import Image
def string_to_cm(texto):
tamanho = 0
minEspeciais = {
'f':0.1,
'i':0.05,
'j':0.05,
'l':0.05,
'm':0.2,
'r':0.1,
't':0.15,
}
maiuEspeciais = {
'I':0.05,
'J':0.15,
'L':0.15,
'P':0.15,
}
for c in texto:
if c > 'a' and c<'z':
if c in minEspeciais:
tamanho += minEspeciais[c]
else:
tamanho += 0.17
else:
if c in maiuEspeciais:
tamanho += maiuEspeciais[c]
else:
tamanho += 0.2
return tamanho
class CasasLegislativasLabels(Report):
"""
Usage example::
>>> from geraldo.generators import PDFGenerator
>>> queryset = CasaLegislativa.objects.filter(municipio__uf__sigla='MG')
>>> report = LabelsReport(queryset)
>>> report.generate_by(PDFGenerator, filename='./inline-detail-report.pdf')
"""
formato = ''
label_margin_top = 0.6
label_margin_left = 0.2
label_margin_right = 0.2
largura_etiqueta = 6.9
altura_etiqueta = 3.25
tamanho_fonte = 6
delta = start = 0.5
def __init__(self, queryset, formato):
super(CasasLegislativasLabels, self).__init__(queryset=queryset)
self.formato = formato
self.page_size = A4
if formato == '3x9_etiqueta':
self.margin_top = 0.25*cm
self.margin_bottom = 0.0*cm
self.margin_left = 0.2*cm
self.margin_right = 0.0*cm
self.delta = 0.3
self.start = 0
self.label_margin_top = 0.35
self.label_margin_left = 0.4
self.label_margin_right = 0.2
else:
self.margin_top = 0.8*cm
self.margin_bottom = 0.8*cm
self.margin_left = 0.4*cm
self.margin_right = 0.4*cm
self.largura_etiqueta = 9.9
self.altura_etiqueta = 5.6
self.tamanho_fonte = 11
self.label_margin_top = 0.5
self.label_margin_left = 0.5
self.label_margin_right = 0.5
calc_width = (self.largura_etiqueta-self.label_margin_left-self.label_margin_right)*cm
calc_height = lambda rows: (self.delta*rows)*cm
calc_top = lambda row: (self.label_margin_top+row*self.delta)*cm
calc_left = self.label_margin_left*cm
my_elements = [
Label(
text='A Sua Excelência o(a) Senhor(a):',
top=calc_top(0), left=calc_left, width=calc_width,
),
ObjectValue(
attribute_name='presidente',
top=calc_top(1), left=calc_left, width=calc_width,
get_value=lambda instance:
unicode(instance.presidente or "").upper()
),
ObjectValue(
attribute_name='nome',
top=calc_top(2), left=calc_left, width=calc_width, height=calc_height(2),
get_value=lambda instance:
("Presidente da %s" % instance.nome)
),
ObjectValue(
attribute_name='logradouro',
top=calc_top(4), left=calc_left, width=calc_width, height=calc_height(2),
get_value=lambda instance:
"%s - %s - %s." % (instance.logradouro, instance.bairro, instance.municipio),
),
ObjectValue(
attribute_name='cep',
top=calc_top(8), left=calc_left, width=calc_width,
get_value=lambda instance:
"CEP: %s" % instance.cep
),
]
self.band_detail = DetailBand(
width=(self.largura_etiqueta)*cm,
height=(self.altura_etiqueta)*cm,
elements=my_elements,
display_inline=True,
default_style={'fontName': 'Helvetica', 'fontSize': self.tamanho_fonte})
class CasasLegislativasLabelsSemPresidente(CasasLegislativasLabels):
def __init__(self, queryset, formato):
super(CasasLegislativasLabelsSemPresidente, self).__init__(queryset=queryset, formato=formato)
calc_width = (self.largura_etiqueta-self.label_margin_left-self.label_margin_right)*cm
calc_height = lambda rows: (self.delta*rows)*cm
calc_top = lambda row: (self.label_margin_top+row*self.delta)*cm
calc_left = self.label_margin_left*cm
my_elements = [
Label(
text='A Sua Excelência o(a) Senhor(a):',
top=calc_top(0), left=calc_left, width=calc_width,
),
ObjectValue(
attribute_name='nome',
top=calc_top(1), left=calc_left, width=calc_width, height=calc_height(2),
get_value=lambda instance:
("Presidente da %s" % instance.nome)
),
ObjectValue(
attribute_name='logradouro',
top=calc_top(3), left=calc_left, width=calc_width, height=calc_height(2),
get_value=lambda instance:
"%s - %s - %s." % (instance.logradouro, instance.bairro, instance.municipio),
),
ObjectValue(
attribute_name='cep',
top=calc_top(8), left=calc_left, width=calc_width,
get_value=lambda instance:
"CEP: %s" % instance.cep
),
]
self.band_detail = DetailBand(
width=(self.largura_etiqueta)*cm,
height=(self.altura_etiqueta)*cm,
elements=my_elements,
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= ReportDefault.band_page_header.BASE_DIR + '/media/images/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= ReportDefault.band_page_header.BASE_DIR + '/media/images/logo-senado.png',
left=1*cm,right=1*cm,top=0.1*cm,bottom=1*cm,
width=3*cm,height=3*cm,
),
Label(text="SENADO FEDERAL",top=1*cm,left=0,width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold','fontSize':14, 'alignment': TA_CENTER}
),
Label(text="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="UF",
left=label_left[0]*cm,
top=label_top,
),
Label(
text="Municipio",
left=label_left[1]*cm,
top=label_top,
),
Label(
text="Presidente",
left=label_left[2]*cm,
top=label_top,
),
Label(
text="Endereço",
left=label_left[3]*cm,
top=label_top,
),
Label(
text="Endereço na Internet",
left=label_left[4]*cm,
top=label_top,
),
Label(
text="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="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="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': 'Sul','SD': 'Sudeste','CO': 'Centro-Oeste','NE': 'Nordeste','NO': 'Norte',}
[instance.municipio.uf.regiao]
),
Label(
text="U.F.: ",
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="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="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="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="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="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="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="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="Telefone(s)",
style = {'fontSize':14,'alignment': TA_CENTER},
width=BAND_WIDTH,
top=1*cm,
),
Label(text="Número",left=tel_left[0]*cm,top=tel_top),
Label(text="Tipo",left=tel_left[1]*cm,top=tel_top),
Label(text="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':'Fixo','M':u'Móvel','X':'Fax','I':'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="Contato(s)",
style = {'fontSize':14,'alignment': TA_CENTER},
width=BAND_WIDTH,
top=1*cm,
),
Label(text="Nome",left=cont_left[0]*cm,top=cont_top),
Label(text="Nota",left=cont_left[1]*cm,top=cont_top),
Label(text="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="Convênio(s)",
style = {'fontSize':14,'alignment': TA_CENTER},
width=BAND_WIDTH,
top=1*cm,
),
Label(text="Projeto",left=convenio_left[0]*cm,top=convenio_top),
Label(text="Nº Convenio",left=convenio_left[1]*cm,top=convenio_top),
Label(text="Nº Processo SF",left=convenio_left[2]*cm,top=convenio_top),
Label(text="Adesão",left=convenio_left[3]*cm,top=convenio_top),
Label(text="Convênio",left=convenio_left[4]*cm,top=convenio_top),
Label(text="Equipada",left=convenio_left[5]*cm,top=convenio_top),
Label(text="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 != 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 != 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 != 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 != None else '-'
),
],
#borders = {'all':True},
),
)
]

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

@ -0,0 +1,234 @@
{% extends "admin/carrinho.html" %}
{% load admin_list i18n %}
{% block extrastyle %}
{{ block.super }}
{% include "admin/tabs_style.html" %}
{% endblock %}
{% block title %}Casas legislativas no Carrinho | SIGI{% endblock %}
{% block content_title %}<h1>Casas Legislativas no Carrinho</h1>{% endblock %}
{% block mensagem%}
<ul class="messagelist">
{%if carIsEmpty%}
<li class="warning">O carrinho está vazio, sendo assim todas as casas entram na lista para exportação de acordo com os filtros aplicados.</li>
{%else%}
<li>{{paginas.paginator.count}} Casas Legislativas no carrinho.</li>
{%endif%}
</ul>
{% endblock %}
{% block action %}deleta_itens_carrinho{% endblock %}
{% block tabela %}
<table>
<thead>
<tr>
{%if not carIsEmpty%}
<th class="sorted ascending"><!-- <input type="checkbox" id="action-toggle" style="display: inline;">-->
</th>
{% endif %}
<th class="sorted ascending">Nome</th>
<th class="sorted ascending">Município</th>
<th class="sorted ascending">Presidente</th>
<th class="sorted ascending">Endereço</th>
</tr>
</thead>
<tbody>
{% for casa in paginas.object_list %}
<tr class="{% cycle 'row1' 'row2' %}">
{%if not carIsEmpty%}
<th><input type="checkbox" name="_selected_action"
value="{{casa.id}}" class="action-select" /></th>
{% endif %}
<td style="text-align: left;">{{casa.nome}}</td>
<td>{{casa.municipio}}</td>
<td>{{casa.presidente|default_if_none:""}}</td>
<td>{{casa.logradouro}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block botoes %}
<div id="tabs">
<ul>
<li><a href="#tabs-1">Etiqueta</a></li>
<li><a href="#tabs-2">Relatório</a></li>
<li><a href="#tabs-3">Arquivo CSV (Excel, Calc)</a></li>
<li><a href="#tabs-4">Etiqueta Parlamentares</a></li>
</ul>
<div id="tabs-1">
<form action="../labels/{{query_str}}" method="post">
<fieldset><legend>Tipo de etiqueta</legend>
<ul class="tabs-conteudo">
<li><input type="radio" name="tipo_etiqueta"
value="com_presidente"><label>Com Presidente</label></li>
<li><input type="radio" name="tipo_etiqueta"
value="sem_presidente" checked="checked">
<label>Sem Presidente</label></li>
</ul>
</fieldset>
<fieldset><legend>Formato da Etiqueta</legend>
<ul class="formato_etiqueta">
<li><input type="radio" name="tamanho_etiqueta"
value="2x5_etiqueta"><label>2x5</label></li>
<li><input type="radio" name="tamanho_etiqueta"
value="3x9_etiqueta" checked="checked"><label>3x9</label></li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Gerar Etiqueta" /></li>
</ul>
</form>
</div>
<div id="tabs-2">
<form action="../reports/{{query_str}}" method="post">
<fieldset><legend>Tipo de relatório</legend>
<ul class="tabs-conteudo">
<li><input type="radio" name="tipo_relatorio" value="simples"
checked="checked"><label>Simples</label></li>
<li><input type="radio" name="tipo_relatorio" value="completo"><label>Completo</label></li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Gerar Relatório" /></li>
</ul>
</form>
</div>
<div id="tabs-3">
<form action="../csv/{{query_str}}" method="post">
<fieldset><legend>Escolha os atributos para exportar</legend>
<ul id="sortable" class="tabs-conteudo">
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="CNPJ"
class="action-select" checked="checked" />
<label>CNPJ</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Código IBGE" class="action-select" checked="checked" />
<label>Código IBGE</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Código TSE" class="action-select" checked="checked" />
<label>Código TSE</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Nome"
class="action-select" checked="checked" />
<label>Nome</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Município" class="action-select" checked="checked" />
<label>Município</label></li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Presidente" class="action-select" checked="checked" />
<label>Presidente</label></li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Logradouro" class="action-select" checked="checked" />
<label>Endereço</label></li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Bairro" class="action-select" checked="checked" />
<label>Bairro</label></li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="CEP"
class="action-select" checked="checked" />
<label>CEP</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Telefone" class="action-select" checked="checked" />
<label>Telefone</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Página web" class="action-select" checked="checked" />
<label>Página Web</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Email" class="action-select" checked="checked" />
<label>Email</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Número de parlamentares" class="action-select" checked="checked" />
<label>Número de parlamentares</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Última alteração de endereco" class="action-select" checked="checked" />
<label>Data da última alteração de endereço</label>
</li>
</ul>
</fieldset>
<fieldset><legend>Contato Interlegis</legend>
<ul id="sortable" class="tabs-conteudo">
<li><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Nome contato" class="action-select" checked="checked" />
<label>Nome</label>
</li>
<li><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Cargo contato" class="action-select" checked="checked" />
<label>Cargo</label>
</li>
<li><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected"
value="Email contato" class="action-select" checked="checked" />
<label>Email</label>
</li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Exportar CSV" /></li>
</ul>
</form>
</div>
<div id="tabs-4">
<form action="../labels_parlamentar/{{query_str}}" method="post">
<fieldset><legend>Formato da Etiqueta</legend>
<ul class="formato_etiqueta">
<li><input type="radio" name="tamanho_etiqueta"
value="2x5_etiqueta"><label>2x5</label></li>
<li><input type="radio" name="tamanho_etiqueta"
value="3x9_etiqueta" checked="checked"><label>3x9</label></li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Gerar Etiqueta" /></li>
</ul>
</form>
</div>
</div>
{% endblock %}

14
sigi/apps/casas/templates/casas/change_form.html

@ -0,0 +1,14 @@
{% extends "admin/change_form.html" %}
{% load i18n reporting_tags %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
<li><a href="report_complete/">Relatório</a></li>
<li><a href="labels/">Etiqueta</a></li>
<li><a href="labels_sem_presidente/">Etiqueta sem presidente</a></li>
<li><a href="history/" class="historylink">{% trans "History" %}</a></li>
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
</ul>
{% endif %}{% endif %}
{% endblock %}

15
sigi/apps/casas/templates/casas/change_list.html

@ -0,0 +1,15 @@
{% extends "admin/change_list.html" %}
{% load admin_list i18n reporting_tags %}
{% block object-tools %}
<ul class="object-tools">
<li><a href="casas_sem_convenio_report/{{query_str}}">Casas sem Processo de Convênio</a></li>
<li><a onclick="return showRelatedObjectLookupPopup(this);" href="carrinho/{{query_str}}">Carrinho / Exportar</a></li>
<li>
<a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
</ul>
{% endblock %}

377
sigi/apps/casas/views.py

@ -0,0 +1,377 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from geraldo.generators import PDFGenerator
from sigi.apps.casas.models import CasaLegislativa, Funcionario
from sigi.apps.casas.reports import CasasLegislativasLabels
from sigi.apps.casas.reports import CasasLegislativasLabelsSemPresidente
from sigi.apps.casas.reports import CasasLegislativasReport
from sigi.apps.casas.reports import CasasSemConvenioReport
from sigi.apps.casas.reports import InfoCasaLegislativa
from sigi.apps.parlamentares.models import Parlamentar
from sigi.apps.parlamentares.reports import ParlamentaresLabels
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.conf import settings
import csv
def query_ordena(qs,o,ot):
list_display = ('nome','municipio','logradouro')
aux = list_display[(int(o)-1)]
if ot =='asc':
qs = qs.order_by(aux)
else:
qs = qs.order_by("-"+aux)
return qs
def get_for_qs(get,qs):
"""
Verifica atributos do GET e retorna queryset correspondente
"""
kwargs = {}
for k,v in get.iteritems():
if not (k == 'page' or k == 'pop' or k == 'q'):
if not k == 'o':
if k == "ot":
qs = query_ordena(qs,get["o"],get["ot"])
else:
kwargs[str(k)] = v
qs = qs.filter(**kwargs)
return qs
def carrinhoOrGet_for_qs(request):
"""
Verifica se existe casas na sessão se não verifica get e retorna qs correspondente.
"""
if request.session.has_key('carrinho_casas'):
ids = request.session['carrinho_casas']
qs = CasaLegislativa.objects.filter(pk__in=ids)
else:
qs = CasaLegislativa.objects.all()
if request.GET:
qs = get_for_qs(request.GET,qs)
return qs
def adicionar_casas_carrinho(request,queryset=None,id=None):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if not request.session.has_key('carrinho_casas'):
request.session['carrinho_casas'] = ids_selecionados
else:
lista = request.session['carrinho_casas']
# Verifica se id já não está adicionado
for id in ids_selecionados:
if not id in lista:
lista.append(id)
request.session['carrinho_casas'] = lista
def visualizar_carrinho(request):
qs = carrinhoOrGet_for_qs(request)
paginator = Paginator(qs, 100)
# Make sure page request is an int. If not, deliver first page.
# Esteja certo de que o `page request` é um inteiro. Se não, mostre a primeira página.
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
# Se o page request (9999) está fora da lista, mostre a última página.
try:
paginas = paginator.page(page)
except (EmptyPage, InvalidPage):
paginas = paginator.page(paginator.num_pages)
carrinhoIsEmpty = not(request.session.has_key('carrinho_casas'))
return render_to_response(
'casas/carrinho.html',
{
"ADMIN_MEDIA_PREFIX":settings.ADMIN_MEDIA_PREFIX,
'MEDIA_URL':settings.MEDIA_URL,
'carIsEmpty':carrinhoIsEmpty,
'paginas':paginas,
'query_str':'?'+request.META['QUERY_STRING']
}
)
def excluir_carrinho(request):
if request.session.has_key('carrinho_casas'):
del request.session['carrinho_casas']
return HttpResponseRedirect('.')
def deleta_itens_carrinho(request):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if request.session.has_key('carrinho_casas'):
lista = request.session['carrinho_casas']
for item in ids_selecionados:
lista.remove(item)
if lista:
request.session['carrinho_casas'] = lista
else:
del lista;
del request.session['carrinho_casas']
return HttpResponseRedirect('.')
def labels_report(request, id=None, tipo=None, formato='3x9_etiqueta'):
""" TODO: adicionar suporte para resultado de pesquisa do admin.
"""
if request.POST:
if request.POST.has_key('tipo_etiqueta'):
tipo = request.POST['tipo_etiqueta']
if request.POST.has_key('tamanho_etiqueta'):
formato = request.POST['tamanho_etiqueta']
if tipo =='sem_presidente':
return labels_report_sem_presidente(request, id, formato)
if id:
qs = CasaLegislativa.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
report = CasasLegislativasLabels(queryset=qs, formato=formato)
report.generate_by(PDFGenerator, filename=response)
return response
def labels_report_parlamentar(request, id=None, formato='3x9_etiqueta'):
""" TODO: adicionar suporte para resultado de pesquisa do admin.
"""
if request.POST:
if request.POST.has_key('tamanho_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()]
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:
qs = carrinhoOrGet_for_parlamentar_qs(request)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
report = ParlamentaresLabels(queryset=qs, formato=formato)
report.generate_by(PDFGenerator, filename=response)
return response
def carrinhoOrGet_for_parlamentar_qs(request):
"""
Verifica se existe parlamentares na sessão se não verifica get e retorna qs correspondente.
"""
if request.session.has_key('carrinho_casas'):
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()]
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()]
mandatos = reduce(lambda x, y: x | y, [l.mandato_set.all() for l in legislaturas])
parlamentares = [m.parlamentar for m in mandatos]
qs = parlamentares
if request.GET:
qs = get_for_qs(request.GET,qs)
return qs
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)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
report = CasasLegislativasLabelsSemPresidente(queryset=qs, formato=formato)
report.generate_by(PDFGenerator, filename=response)
return response
def report(request, id=None,tipo=None):
if request.POST:
if request.POST.has_key('tipo_relatorio'):
tipo = request.POST['tipo_relatorio']
if tipo =='completo':
return report_complete(request, id)
if id:
qs = CasaLegislativa.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
#qs.order_by('municipio__uf','nome')
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
report = CasasLegislativasReport(queryset=qs)
report.generate_by(PDFGenerator, filename=response)
return response
def report_complete(request,id=None):
if id:
qs = CasaLegislativa.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
# 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
def casas_sem_convenio_report(request):
qs = CasaLegislativa.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(mimetype='application/pdf')
report = CasasSemConvenioReport(queryset=qs)
report.generate_by(PDFGenerator, filename=response)
return response
def export_csv(request):
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=casas.csv'
writer = csv.writer(response)
casas = carrinhoOrGet_for_qs(request)
if not casas or not request.POST:
return HttpResponseRedirect('../')
atributos = request.POST.getlist("itens_csv_selected")
atributos2 = [s.encode("utf-8") for s in atributos]
try:
atributos2.insert(atributos2.index('Município'), u'UF')
except ValueError:
pass
writer.writerow(atributos2)
for casa in casas:
lista = []
contatos = casa.funcionario_set.filter(setor="contato_interlegis")
for atributo in atributos:
if u"CNPJ" == atributo:
lista.append(casa.cnpj.encode("utf-8"))
elif u"Código IBGE" == atributo:
lista.append(str(casa.municipio.codigo_ibge).encode("utf-8"))
elif u"Código TSE" == atributo:
lista.append(str(casa.municipio.codigo_tse).encode("utf-8"))
elif u"Nome" == atributo:
lista.append(casa.nome.encode("utf-8"))
elif u"Município" == atributo:
lista.append(unicode(casa.municipio.uf.sigla).encode("utf-8"))
lista.append(unicode(casa.municipio.nome).encode("utf-8"))
elif u"Presidente" == atributo:
#TODO: Esse encode deu erro em 25/04/2012. Comentei para que o usuário pudesse continuar seu trabalho
# É preciso descobrir o porque do erro e fazer a correção definitiva.
# lista.append(str(casa.presidente or "").encode("utf-8"))
lista.append(str(casa.presidente or ""))
elif u"Logradouro" == atributo:
lista.append(casa.logradouro.encode("utf-8"))
elif u"Bairro" == atributo:
lista.append(casa.bairro.encode("utf-8"))
elif u"CEP" == atributo:
lista.append(casa.cep.encode("utf-8"))
elif u"Telefone" == atributo:
lista.append(str(casa.telefone or ""))
elif u"Página web" == atributo:
lista.append(casa.pagina_web.encode("utf-8"))
elif u"Email" == atributo:
lista.append(casa.email.encode("utf-8"))
elif u"Número de parlamentares" == atributo:
lista.append(casa.total_parlamentares)
elif u"Última alteração de endereco" == atributo:
lista.append(casa.ult_alt_endereco)
elif u"Nome contato" == atributo:
if contatos and contatos[0].nome:
lista.append(contatos[0].nome.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"))
else:
lista.append('')
elif u"Email contato" == atributo:
if contatos and contatos[0].email:
lista.append(contatos[0].email.encode("utf-8"))
else:
lista.append('')
else:
pass
writer.writerow(lista)
return response

0
sigi/apps/convenios/__init__.py

139
sigi/apps/convenios/admin.py

@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo, Tramitacao, UnidadeAdministrativa
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.servicos.models import Servico
from django.http import HttpResponse, HttpResponseRedirect
from sigi.apps.convenios.reports import ConvenioReport
from sigi.apps.utils import queryset_ascii
from geraldo.generators import PDFGenerator
from sigi.apps.convenios.views import adicionar_convenios_carrinho
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 AnexoAdmin(admin.ModelAdmin):
date_hierarchy = 'data_pub'
exclude = ['data_pub',]
list_display = ('arquivo', 'descricao', 'data_pub', 'convenio')
raw_id_fields = ('convenio',)
search_fields = ('descricao', 'convenio__id', 'arquivo',
'convenio__casa_legislativa__nome')
class ConvenioAdmin(admin.ModelAdmin):
change_list_template = 'convenios/change_list.html'
fieldsets = (
(None,
{'fields': ('casa_legislativa', 'num_processo_sf','num_convenio','projeto','observacao')}
),
('Datas',
{'fields': ('data_adesao', 'data_retorno_assinatura',
'data_termo_aceite', 'data_pub_diario',
'data_devolucao_via', 'data_postagem_correio')}
),
('Datas - Convenio sem assinatura',
{'fields': ('data_devolucao_sem_assinatura','data_retorno_sem_assinatura',)}
),
)
actions = ['adicionar_convenios']
inlines = (TramitacaoInline, AnexosInline, EquipamentoPrevistoInline)
list_display = ('num_convenio', 'casa_legislativa', 'get_uf',
'data_adesao','data_retorno_assinatura','data_pub_diario','data_termo_aceite',
'projeto',
)
list_display_links = ('num_convenio','casa_legislativa',)
list_filter = ('projeto','casa_legislativa','conveniada', 'equipada')
#date_hierarchy = 'data_adesao'
ordering = ('casa_legislativa__tipo__sigla','casa_legislativa__municipio__uf','casa_legislativa')
raw_id_fields = ('casa_legislativa',)
queryset = queryset_ascii
search_fields = ('id', 'search_text',#'casa_legislativa__nome',
'num_processo_sf','num_convenio')
def get_uf(self, obj):
return obj.casa_legislativa.municipio.uf.sigla
get_uf.short_description = 'UF'
get_uf.admin_order_field = 'casa_legislativa__municipio__uf__sigla'
def changelist_view(self, request, extra_context=None):
import re
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
request.GET._mutable=False
return super(ConvenioAdmin, self).changelist_view(
request,
extra_context={'query_str': '?' + request.META['QUERY_STRING']}
)
def relatorio(self, request, queryset):
#queryset.order_by('casa_legislativa__municipio__uf')
response = HttpResponse(mimetype='application/pdf')
report = ConvenioReport(queryset=queryset)
report.generate_by(PDFGenerator, filename=response)
return response
relatorio.short_description = u'Exportar convênios selecionados para PDF'
def adicionar_convenios(self, request, queryset):
if request.session.has_key('carrinho_convenios'):
q1 = len(request.session['carrinho_convenios'])
else:
q1 = 0
adicionar_convenios_carrinho(request,queryset=queryset)
q2 = len(request.session['carrinho_convenios'])
quant = q2 - q1
if quant:
self.message_user(request,str(q2-q1)+" Convênios adicionados no carrinho" )
else:
self.message_user(request,"Os Convênios selecionados já foram adicionadas anteriormente" )
return HttpResponseRedirect('.')
adicionar_convenios.short_description = u"Armazenar convênios no carrinho para exportar"
def get_actions(self, request):
actions = super(ConvenioAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
def lookup_allowed(self, lookup, value):
return super(ConvenioAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact']
class EquipamentoPrevistoAdmin(admin.ModelAdmin):
list_display = ('convenio', 'equipamento', 'quantidade')
list_display_links = ('convenio', 'equipamento')
ordering = ('convenio', 'equipamento')
raw_id_fields = ('convenio', 'equipamento')
search_fields = ('convenio__id', 'equipamento__fabricante__nome',
'equipamento__modelo__modelo', 'equipamento__modelo__tipo__tipo')
#admin.site.register(Projeto)
admin.site.register(Convenio, ConvenioAdmin)
#admin.site.register(CasaLegislativa)
admin.site.register(EquipamentoPrevisto, EquipamentoPrevistoAdmin)

188
sigi/apps/convenios/models.py

@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from django.db import models
from django.contrib.contenttypes import generic
from sigi.apps.utils import SearchField
class Projeto(models.Model):
""" Modelo para representar os projetos do programa
Interlegis
"""
nome = models.CharField(max_length=50)
sigla = models.CharField(max_length=10)
def __unicode__(self):
return self.sigla
class Convenio(models.Model):
""" Modelo que representa um convênio do Interlegis
com uma Casa Legislativa.
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
"""
casa_legislativa = models.ForeignKey(
'casas.CasaLegislativa',
verbose_name='Casa Legislativa'
)
# campo de busca em caixa baixa e sem acentos
search_text = SearchField(field_names=['casa_legislativa'])
casa_legislativa.convenio_uf_filter = True
casa_legislativa.convenio_cl_tipo_filter = True
projeto = models.ForeignKey(
Projeto
)
# numero designado pelo Senado Federal para o convênio
num_processo_sf = models.CharField(
'número do processo SF (Senado Federal)',
max_length=20,
blank=True,
help_text='Formatos:<br/>Antigo: <em>XXXXXX/XX-X</em>.<br/><em>SIGAD: XXXXX.XXXXXX/XXXX-XX</em>'
)
num_convenio = models.CharField(
'número do convênio',
max_length=10,
blank=True
)
data_adesao = models.DateField(
'Aderidas',
null=True,
blank=True,
)
data_retorno_assinatura = models.DateField(
'Conveniadas',
null=True,
blank=True,
help_text='Convênio firmado.'
)
data_pub_diario = models.DateField(
'data da publicação no Diário Oficial',
null=True,
blank=True
)
data_termo_aceite = models.DateField(
'Equipadas',
null=True,
blank=True,
help_text='Equipamentos recebidos.'
)
data_devolucao_via = models.DateField(
'data de devolução da via',
null=True,
blank=True,
help_text=u'Data de devolução da via do convênio à Câmara Municipal.'
)
data_postagem_correio = models.DateField(
'data postagem correio',
null=True,
blank=True,
)
data_devolucao_sem_assinatura = models.DateField(
'data de devolução por falta de assinatura',
null=True,
blank=True,
help_text=u'Data de devolução por falta de assinatura',
)
data_retorno_sem_assinatura = models.DateField(
'data do retorno sem assinatura',
null=True,
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()
equipada = models.BooleanField()
def save(self, *args, **kwargs):
self.conveniada = self.data_retorno_assinatura!=None
self.equipada = self.data_termo_aceite!=None
super(Convenio, self).save(*args, **kwargs)
class Meta:
get_latest_by = 'id'
ordering = ('id',)
verbose_name = u'convênio'
def __unicode__(self):
if self.data_retorno_assinatura != None:
return u"Convênio nº %s - projeto %s, em %s" % (self.num_convenio, self.projeto.sigla, self.data_retorno_assinatura)
else:
return u"Adesão ao projeto %s, em %s" % (self.projeto.sigla, self.data_adesao)
class EquipamentoPrevisto(models.Model):
""" Modelo utilizado para registrar os equipamentos
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')
quantidade = models.PositiveSmallIntegerField(default=1)
class Meta:
verbose_name = 'equipamento previsto'
verbose_name_plural = 'equipamentos previstos'
def __unicode__(self):
return u'%s %s(s)' % (self.quantidade, self.equipamento)
class Anexo(models.Model):
""" Modelo para giardar os documentos gerados
no processo de convênio
"""
convenio = models.ForeignKey(Convenio, verbose_name=u'convênio')
# caminho no sistema para o documento anexo
arquivo = models.FileField(upload_to='apps/convenios/anexo/arquivo',)
descricao = models.CharField('descrição', max_length='70')
data_pub = models.DateTimeField(
'data da publicação do anexo',
default=datetime.now
)
class Meta:
ordering = ('-data_pub',)
def __unicode__(self):
return unicode("%s publicado em %s" % (self.descricao, self.data_pub))
class UnidadeAdministrativa(models.Model):
""" Modelo para representar uma Unidade Administrativa
que pode ser um servivo do próprio Interlegis, assim como
uma unidade do Senado Federal
"""
sigla = models.CharField(max_length='10')
nome = models.CharField(max_length='100')
def __unicode__(self):
return unicode(self.sigla)
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')
data = models.DateField()
observacao = models.CharField(
'observação',
max_length='512',
null=True,
blank=True,
)
class Meta:
verbose_name_plural = u'Tramitações'
def __unicode__(self):
if self.observacao:
return unicode("%s em %s (%s)" % (self.unid_admin, self.data, self.observacao))
else:
return unicode("%s em %s" % (self.unid_admin, self.data))

316
sigi/apps/convenios/reports.py

@ -0,0 +1,316 @@
# -*- coding: utf-8 -*-
import os
from ctypes import alignment
from operator import attrgetter
from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label, \
landscape,SystemField, BAND_WIDTH,ReportGroup, \
FIELD_ACTION_SUM, FIELD_ACTION_COUNT, FIELD_ACTION_AVG
from geraldo.graphics import Image
from reportlab.lib.units import cm
from reportlab.lib.pagesizes import A4
from reportlab.lib.enums import TA_CENTER, TA_RIGHT
from sigi.apps.relatorios.reports import ReportDefault
#from abc import ABCMeta
class CasasAderidasReport(object):
pass
class CasasNaoAderidasReport(object):
pass
class CasasComEquipamentosReport(object):
pass
class SemEquipamentosReport(object):
pass
class ConvenioReport(ReportDefault):
title = u'Relatório de Convênios'
class band_page_header(ReportDefault.band_page_header):
label_top = ReportDefault.band_page_header.label_top
label_left = [0,1.5,7,9,11,13,15,17]
elements = list(ReportDefault.band_page_header.elements)
height = 4.7*cm
elements += [
Label(
text="UF",
left=label_left[0]*cm,
top=label_top + 0.4*cm,
),
Label(
text="Municipio",
left=label_left[1]*cm,
top=label_top + 0.4*cm,
),
Label(
text="Data de Adesão",
left=label_left[2]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Número do Convênio",
left=label_left[3]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Data do Convênio",
left=label_left[4]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Data de Publicação",
left=label_left[5]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Data de Aceite",
left=label_left[6]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Projeto",
left=label_left[7]*cm,
top=label_top + 0.4*cm,
width=2*cm,
),
]
class band_page_footer(ReportDefault.band_page_footer):
pass
class band_detail(ReportDefault.band_detail):
label_left = [0,1.5,7,9,11,13,15,17]
elements=[
ObjectValue(
attribute_name='casa_legislativa.municipio.uf.sigla',
left=label_left[0]*cm
),
ObjectValue(
attribute_name='casa_legislativa.municipio.nome',
left=label_left[1]*cm
),
ObjectValue(
attribute_name='data_adesao',
left=label_left[2]*cm,
get_value=lambda instance:
instance.data_adesao.strftime('%d/%m/%Y') if instance.data_adesao != None else '-'
),
ObjectValue(
attribute_name='num_convenio',
left=label_left[3]*cm
),
ObjectValue(
attribute_name='data_retorno_assinatura',
left=label_left[4]*cm,
get_value=lambda instance:
instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura != None else '-'
),
ObjectValue(
attribute_name='data_pub_diario',
left=label_left[5]*cm,
get_value=lambda instance:
instance.data_pub_diario.strftime('%d/%m/%Y') if instance.data_pub_diario != None else '-'
),
ObjectValue(
attribute_name='data_termo_aceite',
left=label_left[6]*cm,
get_value=lambda instance:
instance.data_termo_aceite.strftime('%d/%m/%Y') if instance.data_termo_aceite != None else '-'
),
ObjectValue(
attribute_name='projeto.sigla',
left=label_left[7]*cm
),
]
groups = [
ReportGroup(attribute_name='casa_legislativa.municipio.uf',
band_header=ReportBand(
height=0.7*cm,
elements= [
ObjectValue(attribute_name='casa_legislativa.municipio.uf',
get_Value= lambda instance: 'CasaLegislativa: '+ (instance.casa_legislativa.uf)
)
],
borders={'top': True},
)
)
]
class ConvenioReportSemAceite(ConvenioReport):
class band_page_header(ReportDefault.band_page_header):
label_top = ReportDefault.band_page_header.label_top
label_left = [0,1.5,7,9,11,13,15,17]
elements = list(ReportDefault.band_page_header.elements)
height = 4.7*cm
elements += [
Label(
text="UF",
left=label_left[0]*cm,
top=label_top + 0.4*cm,
),
Label(
text="Município",
left=label_left[1]*cm,
top=label_top + 0.4*cm,
),
Label(
text="Data de Adesão",
left=label_left[3]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Número do Convênio",
left=label_left[4]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Data do Convênio",
left=label_left[5]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Data de Publicação",
left=label_left[6]*cm,
top=label_top,
width=2*cm,
),
Label(
text="Projeto",
left=label_left[7]*cm,
top=label_top + 0.4*cm,
width=2*cm,
),
]
class band_detail(ReportDefault.band_detail):
label_left = [0,1.5,7,9,11,13,15,17]
elements=[
ObjectValue(
attribute_name='casa_legislativa.municipio.uf.sigla',
left=label_left[0]*cm
),
ObjectValue(
attribute_name='casa_legislativa.municipio.nome',
left=label_left[1]*cm
),
ObjectValue(
attribute_name='data_adesao',
left=label_left[3]*cm,
get_value=lambda instance:
instance.data_adesao.strftime('%d/%m/%Y') if instance.data_adesao != None else '-'
),
ObjectValue(
attribute_name='num_convenio',
left=label_left[4]*cm
),
ObjectValue(
attribute_name='data_retorno_assinatura',
left=label_left[5]*cm,
get_value=lambda instance:
instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura != None else '-'
),
ObjectValue(
attribute_name='data_pub_diario',
left=label_left[6]*cm,
get_value=lambda instance:
instance.data_pub_diario.strftime('%d/%m/%Y') if instance.data_pub_diario != None else '-'
),
ObjectValue(
attribute_name='projeto.sigla',
left=label_left[7]*cm
),
]
float_duas_casas = lambda instance: '%.2f' % (instance)
class ConvenioReportRegiao(ReportDefault):
title = u'Relatório de Convênios por Região'
class band_page_header(ReportDefault.band_page_header):
label_top = ReportDefault.band_page_header.label_top
label_left = [0.5,6,8,10,12,14]
map(lambda x:x-0.4,label_left)
elements = list(ReportDefault.band_page_header.elements)
elements += [
Label(text="UF", left=label_left[0]*cm,top=label_top,),
Label(text="Total", left=label_left[1]*cm,top=label_top,),
Label(text="Aderidas", left=label_left[2]*cm,top=label_top,),
Label(text="%", left=label_left[3]*cm,top=label_top),
Label(text="Ñ Aderidas", left=label_left[4]*cm,top=label_top,),
Label(text="%", left=label_left[5]*cm,top=label_top),
]
class band_detail(ReportDefault.band_detail):
label_left = [0.5,6,8,10,12,14]
display_inline = True
float_duas_casas = lambda instance: '%.2f' % (instance.porc_casas_aderidas)
default_style = {'fontName': 'Helvetica', 'fontSize': 11}
elements=[
ObjectValue(attribute_name='estado', left=label_left[0]*cm, ),
ObjectValue(attribute_name='quant_casas', left=label_left[1]*cm,),
ObjectValue(attribute_name='quant_casas_aderidas', left=label_left[2]*cm),
ObjectValue(attribute_name='porc_casas_aderidas', left=label_left[3]*cm),
ObjectValue(attribute_name='quant_casas_nao_aderidas', left=label_left[4]*cm),
ObjectValue(attribute_name='porc_casas_nao_aderidas', left=label_left[5]*cm,),
]
class band_summary(ReportBand):
label_left = [0.5,6,8,10,12,14]
elements = [
Label(text="Total", top=0.1*cm, left=label_left[0]*cm),
ObjectValue(attribute_name='quant_casas', action=FIELD_ACTION_SUM, left=label_left[1]*cm, ),
ObjectValue(attribute_name='quant_casas_aderidas', action=FIELD_ACTION_SUM, left=label_left[2]*cm),
# ObjectValue(attribute_name='porc_casas_aderidas', action=FIELD_ACTION_AVG, left=label_left[3]*cm,
# #get_value= lambda instance : lambda instance: '%.2f' % (instance.porc_casas_aderidas),
# ),
ObjectValue(attribute_name='quant_casas_nao_aderidas', action=FIELD_ACTION_SUM, left=label_left[4]*cm),
# ObjectValue(attribute_name='porc_casas_nao_aderidas', left=label_left[5]*cm,
# get_value=lambda x: teste(),
# ),
]
borders = {'top':True}
class ConvenioPorCMReport(ConvenioReport):
title = u'Relatório de Convênios por Câmara Municipal'
class ConvenioPorALReport(ConvenioReport):
title = u'Relatório de Convênios por Assembléia Legislativa'
class ConvenioReportSemAceiteCM(ConvenioReportSemAceite):
title = u'Relatório de Convênios por Câmara Municipal'
class ConvenioReportSemAceiteAL(ConvenioReportSemAceite):
title = u'Relatório de Convênios por Assembléia Legislativa'

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

@ -0,0 +1,158 @@
{% extends "admin/carrinho.html" %}
{% load adminmedia admin_list i18n %}
{% block extrastyle %}
{{ block.super }}
{% include "admin/tabs_style.html" %}
{% endblock %}
{% block title %}Convênios no Carrinho | SIGI{% endblock %}
{% block content_title %}<h1>Convênios no Carrinho</h1>{% endblock %}
{% block mensagem%}
<ul class="messagelist">
{%if carIsEmpty%}
<li class="warning">O carrinho está vazio, sendo assim todos os convênios entram na lista para exportação de acordo com os filtros aplicados.</li>
{%else%}
<li>{{paginas.paginator.count}} Convênios no carrinho.</li>
{%endif%}
</ul>
{% endblock %}
{% block action %}deleta_itens_carrinho{% endblock %}
{% block tabela %}
<table>
<thead>
<tr>
{%if not carIsEmpty%}
<th class="sorted ascending"><!-- <input type="checkbox" id="action-toggle" style="display: inline;">-->
</th>
{% endif %}
<th class="sorted ascending">Numero do convênio</th>
<th class="sorted ascending">Casa Legislativa</th>
<th class="sorted ascending">Aderidas</th>
<th class="sorted ascending">Convêniadas</th>
<th class="sorted ascending">Equipadas</th>
<th class="sorted ascending">Projeto</th>
</tr>
</thead>
<tbody>
{% for convenio in paginas.object_list %}
<tr class="{% cycle 'row1' 'row2' %}">
{%if not carIsEmpty%}
<th><input type="checkbox" name="_selected_action"
value="{{convenio.id}}" class="action-select" /></th>
{% endif %}
<td style="text-align: left;">{{convenio.num_convenio}}</td>
<td>{{convenio.casa_legislativa}}</td>
<td>{{convenio.data_adesao}}</td>
<td>{{convenio.data_retorno_assinatura}}</td>
<td>{{convenio.data_termo_aceite}}</td>
<td>{{convenio.projeto}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block botoes %}
<div id="tabs">
<ul>
<li><a href="#tabs-1">Relatório</a></li>
<li><a href="#tabs-2">Arquivo CSV (Excel, Calc)</a></li>
</ul>
<div id="tabs-1">
<form action="../reports/{{ query_str }}" method="post">
<fieldset>
<legend>Relatório por</legend>
<ul class="tabs-conteudo">
<li>
<input type="radio" name="filtro_casa" value="cm" checked="checked"/>
<label>Câmara Municipal</label>
</li>
<li>
<input type="radio" name="filtro_casa" value="al" />
<label>Assembléia Legislativa</label>
</li>
</ul>
</fieldset>
<fieldset>
<legend>Com data de aceite? (Equipada)</legend>
<ul class="tabs-conteudo">
<li>
<input type="radio" name="data_aceite" value="sim" checked="checked" />
<label>Sim</label>
</li>
<li>
<input type="radio" name="data_aceite" value="nao" />
<label>Não</label>
</li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Gerar Relatório"></li>
</ul>
</form>
</div>
<div id="tabs-2">
<form action="../csv/{{query_str}}" method="post">
<fieldset><legend>Escolha os atributos para exportar</legend>
<ul id="sortable" class="tabs-conteudo">
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="No. Processo"
class="action-select" checked="checked" />
<label>Nº Processo</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="No. Convênio"
class="action-select" checked="checked" />
<label>Nº Convênio</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Projeto"
class="action-select" checked="checked" />
<label>Projeto</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Casa Legislativa"
class="action-select" checked="checked" />
<label>Casa Legislativa</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Data de Adesão"
class="action-select" checked="checked" />
<label>Data de Adesão</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Data de Convênio"
class="action-select" checked="checked" />
<label>Data de Convênio</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Data da Publicacao no D.O."
class="action-select" checked="checked" />
<label>Data da Publicação no Diário Oficial</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Data Equipada"
class="action-select" checked="checked" />
<label>Data Equipada</label>
</li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Exportar CSV" /></li>
</ul>
</form>
</div>
</div>
{% endblock %}

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

@ -0,0 +1,40 @@
{% extends "admin/change_list.html" %}
{% load i18n reporting_tags admin_list %}
{% block extrastyle %}
{{ block.super }}
{% include "admin/tabs_style.html" %}
{% endblock %}
{% block object-tools %}
{% if has_add_permission %}
<ul class="object-tools">
<li><a onclick="return showRelatedObjectLookupPopup(this);" href="carrinho/{{query_str}}">Carrinho / Exportar</a></li>
<li>
<a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
</ul>
{% endif %}
{% endblock %}
{% block search %}
<div id="toolbar">
<form id="changelist-search" action="" method="get">
<div><!-- DIV needed for valid HTML -->
<label for="searchbar"><img src="/sigi/admin_media/img/admin/icon_searchbox.png" alt="Search" /></label>
<input type="text" size="40" name="q" value="" id="searchbar" />
<label for="data_retorno_assinatura__gte">Conveniadas a partir de:</label>
<input type="text" size="10" name="data_retorno_assinatura__gte" value="" id="data_retorno_assinatura__gte" class="vDateField"/>
<label for="data_retorno_assinatura__lte">até:</label>
<input type="text" size="10" name="data_retorno_assinatura__lte" value="" id="data_retorno_assinatura__lte" />
<input type="submit" value="Pesquisar" />
Datas podem ser: Um ano (aaaa), um mês (aaaa-mm) ou um dia (aaaa-mm-dd)
</div>
</form>
</div>
{% endblock %}

145
sigi/apps/convenios/templates/convenios/tabela_regiao.html

@ -0,0 +1,145 @@
<html>
<head>
<title>Relatório por Região</title>
<style>
@page {
size: a4;
margin-top: 6.5cm;
margin-left: 1.5cm;
margin-right: 1cm;
margin-bottom: 3.5cm;
@frame top{
-pdf-frame-content: cabecalho;
top: 2cm;
margin-left: 1cm;
margin-right: 1cm;
/*height: 1cm; */
}
/* @frame midle{
-pdf-frame-content: midle;
top: 6cm;
height: 1cm;
margin: 2cm;
}*/
@frame footer {
-pdf-frame-content: footerContent;
bottom: 2cm;
margin-left: 1cm;
margin-right: 1cm;
height: 1cm;
}
}
body{
font-family: 'Helvetica';
font-size: 9pt;
}
#corpo h1{
text-align: center;
}
#cabecalho {
text-align: center;
font-weight: bold;
font-size: 14pt;
}
#cabecalho .item2{
font-size: 13pt;
}
#cabecalho .titulo{
font-size: 14pt;
}
#footerContent {
border-top: black outset;
padding-top: 0.15cm;
}
#footerContent #esquerda{
text-align: left;
}
#footerContent #direita{
text-align: right;
background-image: url("/media/images/logo-senado.png");
}
.tabela {
padding-top: 0.1cm;
padding-left: 0.1cm;
border: black solid;
width: 2cm;
background-color: #B5B5B5;
}
.tabela caption{
text-align: center;
font-weight: bold;
font-size: 11pt;
}
.tabela th{
background-color: #CFCFCF;
text-align: left;
}
.tabela .conteudo {
background-color: white;/*#E8E8E8;*/
}
.tabela .sumario{
font-weight: bold;
background-color: #CFCFCF;
}
.tabela .cabecalho_esquerda{
background-color: #E8E8E8;
font-weight: bold;
}
</style>
</head>
<body>
<div id="cabecalho">
<table>
<tr>
<td id="imagem1"><img src="../media/images/logo-senado.png" width="80" height="80" alt="Logo Senado"/></td>
<td id="centro" colspan="3">SENADO FEDERAL<br/><span class="item2">SINTER - Secretaria Especial do Interlegis</span></td>
<td id="imagem2"><img src="../media/images/logo-interlegis.jpg" width="90" height="65" alt="Logo Interlegis"/></td>
</tr>
</table>
<h1 class="titulo">{{regiao}}</h1>
</div>
<div id="midle">
{% for tabela in tabelas %}
<table class="tabela" repeat="1">
<caption>{{tabela.projeto}} - {{regiao}}</caption>
<thead>
<tr>
{%for item in tabela.cabecalho%}
<th>{{item}}</th>
{%endfor%}
</tr>
</thead>
<tbody>
{% for linha in tabela.linhas %}
<tr class="conteudo">
<th class="cabecalho_esquerda">{{linha.estado}}</th>
{% for item in linha.lista %}
<td>{{item}}</td>
{% endfor %}
</tr>
{% endfor %}
<tr>
<th>Total</th>
{% for item in tabela.sumario %}
<th>{{item}}</th>
{% endfor %}
</tr>
</tbody>
</table>
<br />
{% endfor %}
</div>
<div id="footerContent">
<table>
<tr>
<td id="esquerda">{{data}} às {{hora}}</td>
<td id="direita">Página <pdf:pagenumber /> </td>
</tr>
</table>
</div>
</body>
</html>

345
sigi/apps/convenios/views.py

@ -0,0 +1,345 @@
#-*- coding:utf-8 -*-
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, get_list_or_404
from geraldo.generators import PDFGenerator
from sigi.apps.convenios.models import Convenio, Projeto
from sigi.apps.convenios.reports import ConvenioReport \
,ConvenioPorCMReport \
,ConvenioPorALReport \
,ConvenioReportSemAceiteAL \
,ConvenioReportSemAceiteCM
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.contatos.models import UnidadeFederativa
import ho.pisa as pisa
from django.template import Context, loader
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.conf import settings
import datetime
import csv
def query_ordena(qs,o,ot):
list_display = ('num_convenio', 'casa_legislativa',
'data_adesao','data_retorno_assinatura','data_termo_aceite',
'projeto',
)
aux = list_display[(int(o)-1)]
if ot =='asc':
qs = qs.order_by(aux)
else:
qs = qs.order_by("-"+aux)
return qs
def get_for_qs(get,qs):
kwargs = {}
ids = 0
for k,v in get.iteritems():
if not (k == 'page' or k == 'pop' or k == 'q'):
if not k == 'o':
if k == "ot":
qs = query_ordena(qs,get["o"],get["ot"])
else:
kwargs[str(k)] = v
if(str(k)=='ids'):
ids = 1
break
qs = qs.filter(**kwargs)
if ids:
query = 'id IN ('+ kwargs['ids'].__str__()+')'
qs = Convenio.objects.extra(where=[query])
return qs
def carrinhoOrGet_for_qs(request):
"""
Verifica se existe convênios na sessão se não verifica get e retorna qs correspondente.
"""
if request.session.has_key('carrinho_convenios'):
ids = request.session['carrinho_convenios']
qs = Convenio.objects.filter(pk__in=ids)
else:
qs = Convenio.objects.all()
if request.GET:
qs = qs.order_by("casa_legislativa__municipio__uf","casa_legislativa__municipio")
qs = get_for_qs(request.GET,qs)
return qs
def adicionar_convenios_carrinho(request,queryset=None,id=None):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if not request.session.has_key('carrinho_convenios'):
request.session['carrinho_convenios'] = ids_selecionados
else:
lista = request.session['carrinho_convenios']
# Verifica se id já não está adicionado
for id in ids_selecionados:
if not id in lista:
lista.append(id)
request.session['carrinho_convenios'] = lista
def excluir_carrinho(request):
if request.session.has_key('carrinho_convenios'):
del request.session['carrinho_convenios']
return HttpResponseRedirect('.')
def deleta_itens_carrinho(request):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if request.session.has_key('carrinho_convenios'):
lista = request.session['carrinho_convenios']
for item in ids_selecionados:
lista.remove(item)
if lista:
request.session['carrinho_convenios'] = lista
else:
del lista;
del request.session['carrinho_convenios']
return HttpResponseRedirect('.')
def visualizar_carrinho(request):
qs = carrinhoOrGet_for_qs(request)
paginator = Paginator(qs, 100)
# Make sure page request is an int. If not, deliver first page.
# Esteja certo de que o `page request` é um inteiro. Se não, mostre a primeira página.
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
# Se o page request (9999) está fora da lista, mostre a última página.
try:
paginas = paginator.page(page)
except (EmptyPage, InvalidPage):
paginas = paginator.page(paginator.num_pages)
carrinhoIsEmpty = not(request.session.has_key('carrinho_convenios'))
return render_to_response(
'convenios/carrinho.html',
{
"ADMIN_MEDIA_PREFIX":settings.ADMIN_MEDIA_PREFIX,
'MEDIA_URL':settings.MEDIA_URL,
'carIsEmpty':carrinhoIsEmpty,
'paginas':paginas,
'query_str':'?'+request.META['QUERY_STRING']
}
)
def report(request, id=None):
if id:
qs = Convenio.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
tipo = ''
data_aceite_has = ''
report = None
if request.POST:
if request.POST.has_key('filtro_casa'):
tipo = request.POST['filtro_casa']
if request.POST.has_key('data_aceite'):
data_aceite_has = request.POST['data_aceite']
# Verifica filtro se é por Assembleia
if tipo == 'al':
qs = qs.filter(casa_legislativa__tipo__sigla='AL')
# Verifica se é com data de aceite
if data_aceite_has == 'nao':
report = ConvenioReportSemAceiteAL(queryset=qs)
else:
report = ConvenioPorALReport(queryset=qs)
else:
qs = qs.filter(casa_legislativa__tipo__sigla='CM')
if data_aceite_has == 'nao':
report = ConvenioReportSemAceiteCM(queryset=qs)
else:
report = ConvenioPorCMReport(queryset=qs)
response = HttpResponse(mimetype='application/pdf')
if report:
report.generate_by(PDFGenerator, filename=response)
else:
return HttpResponseRedirect('../')
return response
def casas_estado_to_tabela(casas,convenios,regiao):
estados = get_list_or_404(UnidadeFederativa,regiao=regiao)
class LinhaEstado():
pass
lista = []
for estado in estados:
linha = LinhaEstado()
convenios_est = convenios.filter(casa_legislativa__municipio__uf=estado)
convenios_est_publicados = convenios_est.exclude(data_pub_diario=None)
convenios_est_equipados = convenios_est.exclude(data_termo_aceite=None)
casas_est = casas.filter(municipio__uf=estado)
casas_est_nao_aderidas = casas_est.exclude(convenio__in=convenios_est).distinct()
casas_est_aderidas = casas_est.filter(convenio__in=convenios_est).distinct()
casas_est_conveniadas = casas_est.filter(convenio__in=convenios_est_publicados).distinct()
casas_est_equipadas = casas_est.filter(convenio__in=convenios_est_equipados).distinct()
linha.lista = (
casas_est.count(),
casas_est_nao_aderidas.count(),
casas_est_aderidas.count(),
casas_est_conveniadas.count(),
casas_est_equipadas.count(),
)
linha.estado = estado
lista.append(linha)
casas_regiao = casas.filter(municipio__uf__regiao=regiao)
convenios_regiao = convenios.filter(casa_legislativa__municipio__uf__regiao=regiao)
convenios_regiao_publicados = convenios_regiao.exclude(data_pub_diario=None)
convenios_regiao_equipados = convenios_regiao.exclude(data_termo_aceite=None)
sumario = (
casas_regiao.count(),
casas_regiao.exclude(convenio__in=convenios_regiao).distinct().count(),
casas_regiao.filter(convenio__in=convenios_regiao).distinct().count(),
casas_regiao.filter(convenio__in=convenios_regiao_publicados).distinct().count(),
casas_regiao.filter(convenio__in=convenios_regiao_equipados).distinct().count(),
)
cabecalho_topo = (
u'UF',
u'Câmaras municipais',
u'Não Aderidas',
u'Aderidas',
u'Conveniadas',
u'Equipadas'
)
return {
"linhas":lista,
"cabecalho":cabecalho_topo,
"sumario":sumario,
}
def report_regiao(request,regiao='NE'):
if request.POST:
if request.POST.has_key('regiao'):
regiao = request.POST['regiao']
REGIAO_CHOICES = {
'SL': 'Sul',
'SD': 'Sudeste',
'CO': 'Centro-Oeste',
'NE': 'Nordeste',
'NO': 'Norte',
}
projetos = Projeto.objects.all()
camaras = CasaLegislativa.objects.filter(tipo__sigla='CM')
tabelas = list()
# Geral
convenios = Convenio.objects.filter(casa_legislativa__tipo__sigla='CM')
tabela = casas_estado_to_tabela(camaras,convenios,regiao)
tabela["projeto"] = "Geral"
tabelas.append(tabela)
for projeto in projetos:
convenios_proj = convenios.filter(projeto=projeto)
tabela = casas_estado_to_tabela(camaras, convenios_proj,regiao)
tabela["projeto"] = projeto.nome
tabelas.append(tabela)
data = datetime.datetime.now().strftime('%d/%m/%Y')
hora = datetime.datetime.now().strftime('%H:%M')
pisa.showLogging()
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=RelatorioRegiao_' + regiao + '.pdf'
#tabelas = ({'projeto':"PI"},{'projeto':"PML"},)
t = loader.get_template('convenios/tabela_regiao.html')
c = Context({'tabelas':tabelas,'regiao':REGIAO_CHOICES[regiao],'data':data,'hora':hora})
pdf = pisa.CreatePDF(t.render(c),response)
if not pdf.err:
pisa.startViewer(response)
return response
def export_csv(request):
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=convenios.csv'
csv_writer = csv.writer(response)
convenios = carrinhoOrGet_for_qs(request)
if not convenios:
return HttpResponseRedirect('../')
atributos = [ u"No. Processo", u"No. Convênio", u"Projeto", u"Casa Legislativa", u"Data de Adesão", u"Data de Convênio",
u"Data da Publicacao no D.O.", u"Data Equipada", ]
if request.POST:
atributos = request.POST.getlist("itens_csv_selected")
col_titles = atributos
if u"Casa Legislativa" in col_titles:
pos = col_titles.index(u"Casa Legislativa") + 1
col_titles.insert(pos, u"uf")
csv_writer.writerow([s.encode("utf-8") for s in col_titles])
for convenio in convenios:
lista = []
for atributo in atributos:
if u"No. Processo" == atributo:
lista.append(convenio.num_processo_sf.encode("utf-8"))
elif u"No. Convênio" == atributo:
lista.append(convenio.num_convenio.encode("utf-8"))
elif u"Projeto" == atributo:
lista.append(convenio.projeto.nome.encode("utf-8"))
elif u"Casa Legislativa" == atributo:
lista.append(convenio.casa_legislativa.nome.encode("utf-8"))
lista.append(convenio.casa_legislativa.municipio.uf.sigla.encode("utf-8"))
elif u"Data de Adesão" == atributo:
data = ''
if convenio.data_adesao:
data = convenio.data_adesao.strftime("%d/%m/%Y")
lista.append(data.encode("utf-8"))
elif u"Data de Convênio" == atributo:
data = ''
if convenio.data_retorno_assinatura:
data = convenio.data_retorno_assinatura.strftime("%d/%m/%Y")
lista.append(data.encode("utf-8"))
elif u"Data da Publicacao no D.O." == atributo:
data = ''
if convenio.data_pub_diario:
data = convenio.data_pub_diario.strftime("%d/%m/%Y")
lista.append(data.encode("utf-8"))
data = ''
elif u"Data Equipada" == atributo:
if convenio.data_termo_aceite:
data = convenio.data_termo_aceite.strftime("%d/%m/%Y")
lista.append(data.encode("utf-8"))
else:
pass
csv_writer.writerow(lista)
return response

0
sigi/apps/diagnosticos/__init__.py

129
sigi/apps/diagnosticos/admin.py

@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from django.contrib import admin
from eav.admin import BaseEntityAdmin, BaseSchemaAdmin
from sigi.apps.diagnosticos.models import Diagnostico, Pergunta, Escolha, Equipe, Anexo, Categoria
from sigi.apps.diagnosticos.forms import DiagnosticoForm
from sigi.apps.contatos.models import UnidadeFederativa
def publicar_diagnostico(self, request, queryset):
for registro in queryset:
diagnostico = Diagnostico.objects.get(pk=registro.id)
diagnostico.publicado = True
diagnostico.data_publicacao= datetime.now()
diagnostico.save()
# Enviando o email avisando que o diagnóstico foi publicado
email = diagnostico.responsavel.user.email
if email:
diagnostico.email_diagnostico_publicado(email, request.get_host())
self.message_user(request, "Diagnóstico(s) publicado(s) com sucesso!")
publicar_diagnostico.short_description = u"""
Definir diagnósticos como publicado"""
def despublicar_diagnostico(self, request, queryset):
queryset.update(publicado=False)
despublicar_diagnostico.short_description = u"""
Definir diagnósticos como não publicado"""
class EquipeInline(admin.TabularInline):
model = Equipe
class AnexosInline(admin.TabularInline):
model = Anexo
extra = 2
exclude = ['data_pub', ]
class AnexoAdmin(admin.ModelAdmin):
date_hierarchy = 'data_pub'
exclude = ['data_pub', ]
list_display = ('arquivo', 'descricao', 'data_pub', 'diagnostico')
raw_id_fields = ('diagnostico',)
search_fields = ('descricao', 'diagnostico__id', 'arquivo',
'diagnostico__casa_legislativa__nome')
class DiagnosticoAdmin(BaseEntityAdmin):
form = DiagnosticoForm
actions = [publicar_diagnostico, despublicar_diagnostico]
inlines = (EquipeInline, AnexosInline)
search_fields = ('casa_legislativa__nome',)
list_display = ('casa_legislativa','get_uf', 'data_visita_inicio', 'data_visita_fim', 'responsavel', 'publicado')
list_filter = ('publicado', 'casa_legislativa', 'data_publicacao', 'data_visita_inicio', 'data_visita_fim')
raw_id_fields = ('casa_legislativa',)
ordering = ('casa_legislativa',)
eav_fieldsets = [
(u'00. Identificação do Diagnóstico', {'fields': ('responsavel', 'data_visita_inicio', 'data_visita_fim',)}),
(u'01. Identificação da Casa Legislativa', {'fields': ('casa_legislativa',)}),
(u'02. Identificação de Competências da Casa Legislativa', {'fields': ()})
]
# popula o eav fieldsets ordenando as categorias e as perguntas
# para serem exibidas no admin
for categoria in Categoria.objects.all():
# ordena as perguntas pelo title e utiliza o name no fieldset
perguntas_by_title = [(p.title, p.name) for p in categoria.perguntas.all()]
perguntas = [pergunta[1] for pergunta in sorted(perguntas_by_title)]
eav_fieldsets.append((categoria, {
'fields': tuple(perguntas),
'classes': ['collapse']
}))
def get_uf(self, obj):
return '%s' % (obj.casa_legislativa.municipio.uf)
get_uf.short_description = 'UF'
get_uf.admin_order_field = 'casa_legislativa__municipio__uf__nome'
def lookup_allowed(self, lookup, value):
return super(DiagnosticoAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact']
def changelist_view(self, request, extra_context=None):
import re
request.GET._mutable=True
if 'data_visita_inicio__gte' in request.GET:
value = request.GET.get('data_visita_inicio__gte','')
if value == '':
del request.GET['data_visita_inicio__gte']
elif re.match('^\d*$', value): # Year only
request.GET['data_visita_inicio__gte'] = "%s-01-01" % value #Complete with january 1st
elif re.match('^\d*\D\d*$', value): # Year and month
request.GET['data_visita_inicio__gte'] = '%s-01' % value #Complete with 1st day of month
if 'data_visita_inicio__lte' in request.GET:
value = request.GET.get('data_visita_inicio__lte','')
if value == '':
del request.GET['data_visita_inicio__lte']
elif re.match('^\d*$', value): # Year only
request.GET['data_visita_inicio__lte'] = "%s-01-01" % value #Complete with january 1st
elif re.match('^\d*\D\d*$', value): # Year and month
request.GET['data_visita_inicio__lte'] = '%s-01' % value #Complete with 1st day of month
request.GET._mutable=False
return super(DiagnosticoAdmin, self).changelist_view(request, extra_context)
class EscolhaAdmin(admin.ModelAdmin):
search_fields = ('title',)
list_display = ('title', 'schema', 'schema_to_open')
raw_id_fields = ('schema', 'schema_to_open')
ordering = ('schema', 'title')
class EscolhaInline(admin.TabularInline):
model = Escolha
fk_name = 'schema'
raw_id_fields = ('schema_to_open',)
verbose_name = 'Escolhas (apenas para choices ou multiple choices)'
extra = 0
class PerguntaAdmin (BaseSchemaAdmin):
search_fields = ('title', 'help_text', 'name',)
list_display = ('title', 'categoria', 'datatype', 'help_text', 'required')
list_filter = ('datatype', 'categoria', 'required')
inlines = (EscolhaInline,)
admin.site.register(Diagnostico, DiagnosticoAdmin)
admin.site.register(Pergunta, PerguntaAdmin)
admin.site.register(Escolha, EscolhaAdmin)
admin.site.register(Anexo, AnexoAdmin)
admin.site.register(Categoria)

23
sigi/apps/diagnosticos/decorators.py

@ -0,0 +1,23 @@
# -*- coding: utf8 -*-
from django.template import RequestContext
from django.shortcuts import render_to_response
from sigi.apps.diagnosticos.models import Diagnostico
def validate_diagnostico(func):
def decorator(request, id_diagnostico, *args, **kwargs):
""" Retorna 404 caso o diagnostico esteja publicado
ou o usuario nao seja um membro da equipe
"""
try:
diagnostico = Diagnostico.objects.filter(publicado=False).get(pk=id_diagnostico)
if (request.user.servidor in diagnostico.membros):
# continua o processamento normal da view
return func(request, id_diagnostico, *args, **kwargs)
except Diagnostico.DoesNotExist:
pass
# renderiza a pagina de 404
context = RequestContext(request, {})
return render_to_response('mobile/404.html', context)
return decorator

32502
sigi/apps/diagnosticos/fixtures/initial_data.json

File diff suppressed because it is too large

171
sigi/apps/diagnosticos/forms.py

@ -0,0 +1,171 @@
# -*- coding: utf8 -*-
from copy import deepcopy
from django import forms
from django.forms.forms import BoundField
from django.forms import (BooleanField, CharField, DateField,
FloatField, ModelChoiceField, Textarea,
ModelMultipleChoiceField)
from django.contrib.contenttypes.generic import generic_inlineformset_factory
from sigi.apps.casas.models import CasaLegislativa, Funcionario
from sigi.apps.contatos.models import Telefone
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.diagnosticos.widgets import EavCheckboxSelectMultiple, EavRadioSelect
from eav.forms import BaseDynamicEntityForm
from eav.fields import RangeField
class DiagnosticoForm(BaseDynamicEntityForm):
"""Classe responsável por contruir o formulário,
vinculando ao modelo Diagnostico
"""
model = Diagnostico
def __init__(self, *args, **kwargs):
super(DiagnosticoForm, self).__init__(*args, **kwargs)
for k, f in self.fields.iteritems():
if isinstance(f, CharField):
f.widget = forms.widgets.Textarea(attrs={'cols':'80'})
class DiagnosticoMobileForm(BaseDynamicEntityForm):
"""Classe responsável por construir o formulário
para ser usado no ambiente mobile, a partir do
do modelo Diagnostico, como também organizar sua
estrutura via categorias.
"""
FIELD_CLASSES = {
'text': CharField,
'float': FloatField,
'date': DateField,
'bool': BooleanField,
'one': ModelChoiceField,
'many': ModelMultipleChoiceField,
'range': RangeField,
}
FIELD_EXTRA = {
'one': {'widget': EavRadioSelect},
'many': {'widget': EavCheckboxSelectMultiple},
}
FIELD_WIDGET = {
'consideracoes_gerais' : {'widget': Textarea},
'descreva_5_cursos_prioritarios_para_treinamento_de_parlamentares_da_camara_municipal' : {'widget': Textarea},
'descreva_5_cursos_prioritarios_para_treinamento_de_servidores_da_camara_municipal' : {'widget': Textarea},
'sugestoes_para_a_area_de_capacitacao' : {'widget': Textarea},
'sugestoes_para_a_area_de_comunicacao' : {'widget': Textarea},
'sugestoes_para_a_area_de_informacao' : {'widget': Textarea},
'sugestoes_para_a_area_de_ti' : {'widget': Textarea},
'inscricoes_para_lista_gitec' : {'widget': Textarea},
'inscricoes_para_lista_gial' : {'widget': Textarea},
'inscricoes_para_lista_gicom' : {'widget': Textarea},
}
class Meta:
model = Diagnostico
def __init__(self, data=None, category=None, *args, **kwargs):
super(BaseDynamicEntityForm, self).__init__(data, *args, **kwargs)
self._build_dynamics_fields(category)
def __iter__(self):
# ordena os campos do formulario usando o atributo label
fields_by_label = [(field.label, name, field) for name, field in self.fields.items()]
for label, name, field in sorted(fields_by_label):
yield BoundField(self, field, name)
def _build_dynamics_fields(self, category):
"""Método da classe ``BaseDynamicEntityForm`` sobrescrita,
para que as perguntas sejam agrupadas dentro das suas
categorias.
* category = ID da Categoria
"""
# Caso seja as duas primeiras categorias, utilize
# os campos do modelo
if int(category) in (0, 1, ):
self.fields = deepcopy(self.base_fields)
else:
self.fields = dict()
# Se determinada pergunta é da categoria pesquisada,
# então, gere o campo no formulário.
for schema in self.instance.get_schemata(int(category)):
defaults = {
'label': schema.title,
'required': schema.required,
'help_text': schema.help_text,
}
datatype = schema.datatype
if datatype == schema.TYPE_MANY:
choices = getattr(self.instance, schema.name)
defaults.update({'queryset': schema.get_choices(),
'initial': [x.pk for x in choices]})
elif datatype == schema.TYPE_ONE:
choice = getattr(self.instance, schema.name)
defaults.update({'queryset': schema.get_choices(),
'initial': choice.pk if choice else None,
# if schema is required remove --------- from ui
'empty_label': None if schema.required else u"---------"})
extra = self.FIELD_EXTRA.get(datatype, {})
extra.update(self.FIELD_WIDGET.get(schema.name, {}))
if hasattr(extra, '__call__'):
extra = extra(schema)
defaults.update(extra)
MappedField = self.FIELD_CLASSES[datatype]
self.fields[schema.name] = MappedField(**defaults)
# fill initial data (if attribute was already defined)
value = getattr(self.instance, schema.name)
if value and not datatype in (schema.TYPE_ONE, schema.TYPE_MANY): # choices are already done above
self.initial[schema.name] = value
class CasaLegislativaMobileForm(forms.ModelForm):
data_instalacao = forms.DateField(label = u'Data de instalação da Casa Legislativa', required=False)
class Meta:
model = CasaLegislativa
fields = ('cnpj', 'data_criacao', 'data_instalacao', 'logradouro', 'bairro', 'cep', 'email', 'pagina_web')
def __init__(self, *args, **kwargs):
super(CasaLegislativaMobileForm, 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)
self.instance.municipio.data_criacao = self.cleaned_data['data_criacao']
if commit:
self.instance.municipio.save()
return self.instance
class TelefoneMobileForm(forms.ModelForm):
pass
class Meta:
model = Telefone
fields = ('numero', 'tipo')
class FuncionariosMobileForm(forms.ModelForm):
TelefoneFormSet = generic_inlineformset_factory(Telefone, TelefoneMobileForm, extra=1, can_delete=False)
def __init__(self, data=None, prefix=None, instance=None, *args, **kwargs):
super(FuncionariosMobileForm, self).__init__(data, prefix=prefix, instance=instance, *args, **kwargs)
self.telefones = self.TelefoneFormSet(data, prefix=prefix, instance=instance)
def is_valid(self):
return self.telefones.is_valid() and super(FuncionariosMobileForm, self).is_valid()
def save(self, commit=True):
self.telefones.save(commit)
return super(FuncionariosMobileForm, self).save(commit)
class Meta:
model = Funcionario
fields = ('nome', 'email', 'cargo', 'funcao', 'tempo_de_servico', 'sexo')

247
sigi/apps/diagnosticos/models.py

@ -0,0 +1,247 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from django.db import models
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.utils import SearchField
from sigi.apps.utils.email import enviar_email
from eav.models import BaseChoice, BaseEntity, BaseSchema, BaseAttribute
class Diagnostico(BaseEntity):
""" Modelo para representar unm diagnostico realizado
em uma Casa Legislativa
"""
casa_legislativa = models.ForeignKey(
'casas.CasaLegislativa',
verbose_name='Casa Legislativa')
# campo de busca em caixa baixa e sem acento
search_text = SearchField(field_names=['casa_legislativa'])
casa_legislativa.casa_uf_filter = True
# casa_legislativa.casa_tipo_filter = True
data_visita_inicio = models.DateField(
u'data inicial da visita',
null=True,
blank=True,
)
data_visita_fim = models.DateField(
u'data final da visita',
null=True,
blank=True,
)
publicado = models.BooleanField(default=False)
data_publicacao = models.DateField(
u'data de publicação do diagnóstico',
null=True,
blank=True,
)
responsavel = models.ForeignKey('servidores.Servidor',
verbose_name=u'responsável')
class Meta:
verbose_name, verbose_name_plural = u'diagnóstico', u'diagnósticos'
@property
def membros(self):
""" Retorna a lista de membros do diagnostico,
isto é responsavel + equipe
"""
membros = set([self.responsavel])
for equipe in self.equipe_set.all():
membros.add(equipe.membro)
return list(membros)
@property
def contatos_respondidos(self):
"""Retorna uma lista de contatos que foram
respondidos
"""
return list(self.casa_legislativa.funcionario_set.all())
@property
def categorias_respondidas(self):
""" Retorna uma listas das categorias dinamicas que tem
ao menos uma resposta
"""
# unifica as categorias das perguntas dessas respostas
categoria_com_respostas = set([r.schema.categoria for r in self._get_respostas()])
return list(categoria_com_respostas)
def _get_respostas(self):
# obtem todas as respostas dinamicas desse diagnostico
respostas = Resposta.objects.filter(entity_id=self.id).all()
# remove as respostas nulas ou em branco
return [r for r in respostas if r._get_value()]
def email_diagnostico_publicado(self, from_email, host):
"""Enviando email quando o diagnóstico for publicado. Os
argumentos acima são:
* from_email - Email de remetente
* host - O Host do sistema, para ser usado na
construção do endereço do diagnóstico
"""
enviar_email(from_email, u"Diagnóstico publicado",
'diagnosticos/email_diagnostico_publicado.txt',
{
'responsavel': self.responsavel.nome_completo,
'casa_legislativa': self.casa_legislativa,
'data_diagnostico': self.data_visita_inicio,
'host': host,
'url_diagnostico': self.get_absolute_url(),
'status': u"Publicado",
})
def email_diagnostico_alterado(self, from_email, host):
"""Enviando email quando o status do diagnóstico
for alterado. Os argumentos acima são:
* from_email - Email do destinatário
* host - O Host do sistema, para ser usado na
construção do endereço do diagnóstico
"""
enviar_email(from_email, u"Diagnóstico alterado",
'diagnosticos/email_diagnostico_alterado.txt',
{
'servidor': self.responsavel.nome_completo,
'casa_legislativa': self.casa_legislativa,
'data_diagnostico': self.data_visita_inicio,
'host': host,
'url_diagnostico': self.get_absolute_url(),
'status': "Alterado",
})
def get_schemata(self, category=None, *args, **kwargs):
""" Se existir uma categoria retorna apenas as questões dessa.
"""
schemas = super(Diagnostico,self).get_schemata(*args, **kwargs)
if category:
schemas = [s for s in schemas if s.categoria_id == category]
schemas= sorted(schemas, lambda x,y: cmp(x.title, y.title))
return schemas
@classmethod
def get_schemata_for_model(self):
return Pergunta.objects.all()
def __unicode__(self):
return str(self.casa_legislativa).decode('utf8')
def get_absolute_url(self):
return "/sigi/diagnosticos/diagnostico/%i.pdf" % (self.id, )
class Categoria(models.Model):
""" Modelo para representar a categoria de uma pergunta
e sua ordem na hora de exibir no formulário
"""
nome = models.CharField(max_length=255)
class Meta:
ordering = ('nome',)
def __unicode__(self):
return self.nome
class Pergunta(BaseSchema):
""" Modelo que representa uma pergunta no questionário
e sua ordem dentro da categoria
Uma pergunta tem o nome e o tipo da resposta
"""
categoria = models.ForeignKey(Categoria, related_name='perguntas')
def group_choices(self):
from django.db import connection, transaction
cursor = connection.cursor()
cursor.execute("""
SELECT choice_id, sum(1)
FROM diagnosticos_resposta
WHERE schema_id=%s and choice_id is not null
GROUP BY choice_id;
""", [self.id])
return [
(Escolha.objects.get(id=int(row[0])), row[1])
for row in cursor.fetchall()
]
def total_anwsers(self):
from django.db import connection, transaction
cursor = connection.cursor()
cursor.execute("""
SELECT sum(1)
FROM diagnosticos_resposta
WHERE schema_id=%s
""", [self.id])
return cursor.fetchone()
class Meta:
ordering = ('title',)
verbose_name, verbose_name_plural = 'pergunta', 'perguntas'
class Escolha(BaseChoice):
""" Perguntas de multiplas escolhas tem as opções
cadastradas neste modelo
"""
schema = models.ForeignKey(Pergunta,
related_name='choices', verbose_name='pergunta')
schema_to_open = models.ForeignKey(Pergunta, related_name='',
verbose_name='pergunta para abrir', blank=True, null=True)
ordem = models.PositiveIntegerField(blank=True, null=True)
class Meta:
ordering = ('schema','ordem')
verbose_name, verbose_name_plural = 'escolha', 'escolhas'
class Resposta(BaseAttribute):
""" Modelo para guardar as respostas das perguntas
de um diagnosico
"""
schema = models.ForeignKey(Pergunta, related_name='attrs',
verbose_name='pergunta')
choice = models.ForeignKey(Escolha, verbose_name='escolha',
blank=True, null=True)
class Meta:
verbose_name, verbose_name_plural = 'resposta', 'respostas'
class Equipe(models.Model):
""" Modelo que representa a equipe de um diagnóstico
"""
diagnostico = models.ForeignKey(Diagnostico)
membro = models.ForeignKey('servidores.Servidor')
class Meta:
verbose_name, verbose_name_plural = u'equipe', u'equipe'
def __unicode__(self):
return self.membro.__unicode__()
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')
arquivo = models.FileField(upload_to='apps/diagnostico/anexo/arquivo',)
descricao = models.CharField('descrição', max_length='70')
data_pub = models.DateTimeField('data da publicação do anexo',
default=datetime.now)
class Meta:
ordering = ('-data_pub',)
def __unicode__(self):
return unicode(self.arquivo.name)

0
sigi/apps/diagnosticos/templatetags/__init__.py

401
sigi/apps/diagnosticos/templatetags/smart_if.py

@ -0,0 +1,401 @@
"""
A smarter {% if %} tag for django templates.
While retaining current Django functionality, it also handles equality,
greater than and less than operators. Some common case examples::
{% if articles|length >= 5 %}...{% endif %}
{% if "ifnotequal tag" != "beautiful" %}...{% endif %}
"""
import unittest
from django import template
register = template.Library()
#==============================================================================
# Calculation objects
#==============================================================================
class BaseCalc(object):
def __init__(self, var1, var2=None, negate=False):
self.var1 = var1
self.var2 = var2
self.negate = negate
def resolve(self, context):
try:
var1, var2 = self.resolve_vars(context)
outcome = self.calculate(var1, var2)
except:
outcome = False
if self.negate:
return not outcome
return outcome
def resolve_vars(self, context):
var2 = self.var2 and self.var2.resolve(context)
return self.var1.resolve(context), var2
def calculate(self, var1, var2):
raise NotImplementedError()
class Or(BaseCalc):
def calculate(self, var1, var2):
return var1 or var2
class And(BaseCalc):
def calculate(self, var1, var2):
return var1 and var2
class Equals(BaseCalc):
def calculate(self, var1, var2):
return var1 == var2
class Greater(BaseCalc):
def calculate(self, var1, var2):
return var1 > var2
class GreaterOrEqual(BaseCalc):
def calculate(self, var1, var2):
return var1 >= var2
class In(BaseCalc):
def calculate(self, var1, var2):
return var1 in var2
#==============================================================================
# Tests
#==============================================================================
class TestVar(object):
"""
A basic self-resolvable object similar to a Django template variable. Used
to assist with tests.
"""
def __init__(self, value):
self.value = value
def resolve(self, context):
return self.value
class SmartIfTests(unittest.TestCase):
def setUp(self):
self.true = TestVar(True)
self.false = TestVar(False)
self.high = TestVar(9000)
self.low = TestVar(1)
def assertCalc(self, calc, context=None):
"""
Test a calculation is True, also checking the inverse "negate" case.
"""
context = context or {}
self.assert_(calc.resolve(context))
calc.negate = not calc.negate
self.assertFalse(calc.resolve(context))
def assertCalcFalse(self, calc, context=None):
"""
Test a calculation is False, also checking the inverse "negate" case.
"""
context = context or {}
self.assertFalse(calc.resolve(context))
calc.negate = not calc.negate
self.assert_(calc.resolve(context))
def test_or(self):
self.assertCalc(Or(self.true))
self.assertCalcFalse(Or(self.false))
self.assertCalc(Or(self.true, self.true))
self.assertCalc(Or(self.true, self.false))
self.assertCalc(Or(self.false, self.true))
self.assertCalcFalse(Or(self.false, self.false))
def test_and(self):
self.assertCalc(And(self.true, self.true))
self.assertCalcFalse(And(self.true, self.false))
self.assertCalcFalse(And(self.false, self.true))
self.assertCalcFalse(And(self.false, self.false))
def test_equals(self):
self.assertCalc(Equals(self.low, self.low))
self.assertCalcFalse(Equals(self.low, self.high))
def test_greater(self):
self.assertCalc(Greater(self.high, self.low))
self.assertCalcFalse(Greater(self.low, self.low))
self.assertCalcFalse(Greater(self.low, self.high))
def test_greater_or_equal(self):
self.assertCalc(GreaterOrEqual(self.high, self.low))
self.assertCalc(GreaterOrEqual(self.low, self.low))
self.assertCalcFalse(GreaterOrEqual(self.low, self.high))
def test_in(self):
list_ = TestVar([1,2,3])
invalid_list = TestVar(None)
self.assertCalc(In(self.low, list_))
self.assertCalcFalse(In(self.low, invalid_list))
def test_parse_bits(self):
var = IfParser([True]).parse()
self.assert_(var.resolve({}))
var = IfParser([False]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([False, 'or', True]).parse()
self.assert_(var.resolve({}))
var = IfParser([False, 'and', True]).parse()
self.assertFalse(var.resolve({}))
var = IfParser(['not', False, 'and', 'not', False]).parse()
self.assert_(var.resolve({}))
var = IfParser(['not', 'not', True]).parse()
self.assert_(var.resolve({}))
var = IfParser([1, '=', 1]).parse()
self.assert_(var.resolve({}))
var = IfParser([1, 'not', '=', 1]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([1, 'not', 'not', '=', 1]).parse()
self.assert_(var.resolve({}))
var = IfParser([1, '!=', 1]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([3, '>', 2]).parse()
self.assert_(var.resolve({}))
var = IfParser([1, '<', 2]).parse()
self.assert_(var.resolve({}))
var = IfParser([2, 'not', 'in', [2, 3]]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([1, 'or', 1, '=', 2]).parse()
self.assert_(var.resolve({}))
def test_boolean(self):
var = IfParser([True, 'and', True, 'and', True]).parse()
self.assert_(var.resolve({}))
var = IfParser([False, 'or', False, 'or', True]).parse()
self.assert_(var.resolve({}))
var = IfParser([True, 'and', False, 'or', True]).parse()
self.assert_(var.resolve({}))
var = IfParser([False, 'or', True, 'and', True]).parse()
self.assert_(var.resolve({}))
var = IfParser([True, 'and', True, 'and', False]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([False, 'or', False, 'or', False]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([False, 'or', True, 'and', False]).parse()
self.assertFalse(var.resolve({}))
var = IfParser([False, 'and', True, 'or', False]).parse()
self.assertFalse(var.resolve({}))
def test_invalid(self):
self.assertRaises(ValueError, IfParser(['not']).parse)
self.assertRaises(ValueError, IfParser(['==']).parse)
self.assertRaises(ValueError, IfParser([1, 'in']).parse)
self.assertRaises(ValueError, IfParser([1, '>', 'in']).parse)
self.assertRaises(ValueError, IfParser([1, '==', 'not', 'not']).parse)
self.assertRaises(ValueError, IfParser([1, 2]).parse)
OPERATORS = {
'=': (Equals, True),
'==': (Equals, True),
'!=': (Equals, False),
'>': (Greater, True),
'>=': (GreaterOrEqual, True),
'<=': (Greater, False),
'<': (GreaterOrEqual, False),
'or': (Or, True),
'and': (And, True),
'in': (In, True),
}
BOOL_OPERATORS = ('or', 'and')
class IfParser(object):
error_class = ValueError
def __init__(self, tokens):
self.tokens = tokens
def _get_tokens(self):
return self._tokens
def _set_tokens(self, tokens):
self._tokens = tokens
self.len = len(tokens)
self.pos = 0
tokens = property(_get_tokens, _set_tokens)
def parse(self):
if self.at_end():
raise self.error_class('No variables provided.')
var1 = self.get_bool_var()
while not self.at_end():
op, negate = self.get_operator()
var2 = self.get_bool_var()
var1 = op(var1, var2, negate=negate)
return var1
def get_token(self, eof_message=None, lookahead=False):
negate = True
token = None
pos = self.pos
while token is None or token == 'not':
if pos >= self.len:
if eof_message is None:
raise self.error_class()
raise self.error_class(eof_message)
token = self.tokens[pos]
negate = not negate
pos += 1
if not lookahead:
self.pos = pos
return token, negate
def at_end(self):
return self.pos >= self.len
def create_var(self, value):
return TestVar(value)
def get_bool_var(self):
"""
Returns either a variable by itself or a non-boolean operation (such as
``x == 0`` or ``x < 0``).
This is needed to keep correct precedence for boolean operations (i.e.
``x or x == 0`` should be ``x or (x == 0)``, not ``(x or x) == 0``).
"""
var = self.get_var()
if not self.at_end():
op_token = self.get_token(lookahead=True)[0]
if isinstance(op_token, basestring) and (op_token not in
BOOL_OPERATORS):
op, negate = self.get_operator()
return op(var, self.get_var(), negate=negate)
return var
def get_var(self):
token, negate = self.get_token('Reached end of statement, still '
'expecting a variable.')
if isinstance(token, basestring) and token in OPERATORS:
raise self.error_class('Expected variable, got operator (%s).' %
token)
var = self.create_var(token)
if negate:
return Or(var, negate=True)
return var
def get_operator(self):
token, negate = self.get_token('Reached end of statement, still '
'expecting an operator.')
if not isinstance(token, basestring) or token not in OPERATORS:
raise self.error_class('%s is not a valid operator.' % token)
if self.at_end():
raise self.error_class('No variable provided after "%s".' % token)
op, true = OPERATORS[token]
if not true:
negate = not negate
return op, negate
#==============================================================================
# Actual templatetag code.
#==============================================================================
class TemplateIfParser(IfParser):
error_class = template.TemplateSyntaxError
def __init__(self, parser, *args, **kwargs):
self.template_parser = parser
return super(TemplateIfParser, self).__init__(*args, **kwargs)
def create_var(self, value):
return self.template_parser.compile_filter(value)
class SmartIfNode(template.Node):
def __init__(self, var, nodelist_true, nodelist_false=None):
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.var = var
def render(self, context):
if self.var.resolve(context):
return self.nodelist_true.render(context)
if self.nodelist_false:
return self.nodelist_false.render(context)
return ''
def __repr__(self):
return "<Smart If node>"
def __iter__(self):
for node in self.nodelist_true:
yield node
if self.nodelist_false:
for node in self.nodelist_false:
yield node
def get_nodes_by_type(self, nodetype):
nodes = []
if isinstance(self, nodetype):
nodes.append(self)
nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
if self.nodelist_false:
nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
return nodes
@register.tag('if')
def smart_if(parser, token):
"""
A smarter {% if %} tag for django templates.
While retaining current Django functionality, it also handles equality,
greater than and less than operators. Some common case examples::
{% if articles|length >= 5 %}...{% endif %}
{% if "ifnotequal tag" != "beautiful" %}...{% endif %}
Arguments and operators _must_ have a space between them, so
``{% if 1>2 %}`` is not a valid smart if tag.
All supported operators are: ``or``, ``and``, ``in``, ``=`` (or ``==``),
``!=``, ``>``, ``>=``, ``<`` and ``<=``.
"""
bits = token.split_contents()[1:]
var = TemplateIfParser(parser, bits).parse()
nodelist_true = parser.parse(('else', 'endif'))
token = parser.next_token()
if token.contents == 'else':
nodelist_false = parser.parse(('endif',))
parser.delete_first_token()
else:
nodelist_false = None
return SmartIfNode(var, nodelist_true, nodelist_false)
if __name__ == '__main__':
unittest.main()

15
sigi/apps/diagnosticos/tests.py

@ -0,0 +1,15 @@
# -*- coding: utf8 -*-
from django.test import TestCase
class DiagnosticosViewsTest(TestCase):
"""Testes feitos para verificar o funcionamento
do view de diagnósticos.
"""
def test_diagnostico_list_success(self):
response = self.client.get('/sigi/mobile/diagnosticos')
self.assertEquals(200, response.status_code)
self.assertTemplateUsed(response, 'diagnosticos/diagnosticos_list.html')

35
sigi/apps/diagnosticos/urls.py

@ -0,0 +1,35 @@
# -*- coding: utf8 -*-
from django.conf.urls.defaults import patterns, url
LOGIN_REDIRECT_URL = '/sigi/mobile/diagnosticos/login'
urlpatterns = patterns('',
# Lista de Diagnósticos
url(r'^$', 'sigi.apps.diagnosticos.views.lista', name='lista_diagnosticos'),
# Login do Diagnóstico
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name':
'diagnosticos/diagnosticos_login.html'}, name='login'),
# Logout do Diagnóstico
url(r'^logout/$', 'django.contrib.auth.views.logout',
{'next_page': LOGIN_REDIRECT_URL}, name='logout'),
# Lista de Categorias
url(r'^(?P<id_diagnostico>\d+)/categorias/$', 'sigi.apps.diagnosticos.views.categorias', name='lista_categorias'),
# Detalhes da Categoria da Casa Legislativa
url(r'^(?P<id_diagnostico>\d+)/categorias/1/$',
'sigi.apps.diagnosticos.views.categoria_casa_legislativa',
name='detalhes_categoria_casa_legislativa'),
# Detalhes da Categoria de Contatos
url(r'^(?P<id_diagnostico>\d+)/categorias/2/$',
'sigi.apps.diagnosticos.views.categoria_contatos',
name='detalhes_categoria_contatos'),
# Detalhes de Categorias Dinamicas
url(r'^(?P<id_diagnostico>\d+)/categorias/(?P<id_categoria>\d+)/$',
'sigi.apps.diagnosticos.views.categoria_detalhes',
name='detalhes_categoria'),
)

351
sigi/apps/diagnosticos/views.py

@ -0,0 +1,351 @@
# -*- coding: utf8 -*-
import new
from django.http import HttpResponse, QueryDict
from django.utils import simplejson
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.views.decorators.cache import never_cache
from geraldo.generators import PDFGenerator
from sigi.apps.diagnosticos.urls import LOGIN_REDIRECT_URL
from sigi.apps.utils.decorators import login_required
from sigi.apps.diagnosticos.decorators import validate_diagnostico
from sigi.apps.diagnosticos.models import Diagnostico, Categoria, Pergunta
from sigi.apps.casas.models import Funcionario
from sigi.apps.diagnosticos.forms import (DiagnosticoMobileForm,
CasaLegislativaMobileForm, FuncionariosMobileForm)
from sigi.apps.contatos.models import Telefone
from sigi.shortcuts import render_to_pdf
@never_cache
@login_required(login_url=LOGIN_REDIRECT_URL)
def lista(request):
"""Consulta os diagnosticos do servidor logado,
que contenham o status de não publicado.
"""
servidor = request.user.servidor
diagnosticos = servidor.diagnosticos
context = RequestContext(request, {'diagnosticos': diagnosticos})
return render_to_response('diagnosticos/diagnosticos_list.html', context)
@never_cache
@login_required(login_url=LOGIN_REDIRECT_URL)
@validate_diagnostico
def categorias(request, id_diagnostico):
"""Consulta as categorias do diagnostico selecionado
a partir da sua identificação
"""
categorias = Categoria.objects.all()
diagnostico = Diagnostico.objects.get(pk=id_diagnostico)
# Estilizando a lista de categorias para que ajude a identificar
# qual categoria foi a ultima a ser usada, como também as outras
# que ainda não foram acessadas
ultima_categoria = request.session.get('ultima_categoria', 0)
context = RequestContext(request, {'categorias': categorias,
'diagnostico': diagnostico, 'ultima_categoria': ultima_categoria})
return render_to_response('diagnosticos/diagnosticos_categorias_list.html',
context)
@never_cache
@login_required(login_url=LOGIN_REDIRECT_URL)
@validate_diagnostico
def categoria_detalhes(request, id_diagnostico, id_categoria):
"""Captura as perguntas da categoria
selecionada. Durante o preenchimento das perguntas, o camada
template do projeto, vai requisitar a inserção dos campos via
AJAX a cada mudança de pergunta
Caso alguma inserção não passe na validação do formulário em
questão, será enviado as mensagens de erro no formato JSON,
para que a camada de template do projeto trate-as de forma adequada.
"""
# Grava na sessão a categoria atual, para destacar que
# era foi a última visitada.
request.session['ultima_categoria'] = int(id_categoria)
try:
categoria = Categoria.objects.get(pk=id_categoria)
except Categoria.DoesNotExist:
context = RequestContext(request)
return render_to_response('mobile/404.html', context)
diagnostico = Diagnostico.objects.filter(publicado=False).get(pk=id_diagnostico)
if request.method == "POST":
form = DiagnosticoMobileForm(request.POST,
instance=diagnostico, category=id_categoria)
if form.is_valid():
form.save()
resposta = {
'mensagem': 'sucesso'
}
else:
# Montando a estrutura das mensagens de erro no formato JSON
resposta = {
'mensagem': 'erro',
'erros': form.errors
}
json = simplejson.dumps(resposta)
return HttpResponse(json, mimetype="application/json")
else:
form = DiagnosticoMobileForm(instance=diagnostico,
category=id_categoria)
context = RequestContext(request, {'form': form, 'categoria': categoria,
'diagnostico': diagnostico})
return render_to_response('diagnosticos/diagnosticos_categorias_form.html',
context)
@never_cache
@login_required(login_url=LOGIN_REDIRECT_URL)
@validate_diagnostico
def categoria_casa_legislativa(request, id_diagnostico):
# Grava na sessão a categoria atual, para destacar que
# era foi a última visitada.
request.session['ultima_categoria'] = 1
diagnostico = Diagnostico.objects.get(pk=id_diagnostico)
casa_legislativa = diagnostico.casa_legislativa
if request.method == "POST":
form = CasaLegislativaMobileForm(request.POST,
instance=casa_legislativa)
if form.is_valid():
form.save()
resposta = {
'mensagem': 'sucesso'
}
else:
# Montando a estrutura das mensagens de erro no formato JSON
resposta = {
'mensagem': 'erro',
'erros': form.errors
}
json = simplejson.dumps(resposta)
return HttpResponse(json, mimetype="application/json")
else:
form = CasaLegislativaMobileForm(instance=casa_legislativa)
context = RequestContext(request, {'form': form,
'diagnostico': diagnostico, 'casa_legislativa': casa_legislativa})
return render_to_response(
'diagnosticos/diagnosticos_categoria_casa_legislativa_form.html',
context)
@never_cache
@login_required(login_url=LOGIN_REDIRECT_URL)
@validate_diagnostico
def categoria_contatos(request, id_diagnostico):
# Grava na sessão a categoria atual, para destacar que
# era foi a última visitada.
request.session['ultima_categoria'] = 2
diagnostico = Diagnostico.objects.get(pk=id_diagnostico)
casa_legislativa = diagnostico.casa_legislativa
funcionarios = []
for n, l in Funcionario.SETOR_CHOICES:
if casa_legislativa.funcionario_set.filter(setor=n).count() <= 1:
funcionarios.append(casa_legislativa.funcionario_set.get_or_create(setor=n))
else:
for f in casa_legislativa.funcionario_set.filter(setor=n):
funcionarios.append((f, False))
if request.method == "POST":
forms = []
for f, c in funcionarios:
try:
forms.append(FuncionariosMobileForm(request.POST, prefix=f.setor, instance=f))
except:
pass
resposta = {
'mensagem': 'sucesso',
'erros' : {},
'fones' : {},
'clean' : (),
}
# valida e salva um formulario por vez
for form in forms:
if form.is_valid():
form.save()
s = ''
for form_telefones in form.telefones.forms:
tel = form_telefones.instance
if tel._state.adding and tel.numero != '':
s += '<p>Novo telefone %s: %s</p>' % (form_telefones.instance.get_tipo_display(), form_telefones.instance.numero)
resposta['clean'] += ('id_' + form_telefones.prefix + '-numero',)
if s != '':
resposta['fones'][form.prefix] = s
else:
# Montando a estrutura das mensagens de erro no formato JSON
resposta['mensagem'] = 'erro'
for key, value in form.errors.iteritems():
resposta['erros'][form.prefix + '-' + key + '-errors'] = value
for form_telefones in form.telefones.forms:
if not form_telefones.is_valid():
if (form_telefones.fields['id'].initial is not None
and form_telefones.fields['tipo'].initial == 'I'
and form_telefones.fields['numero'].initial is None):
if Telefone.objects.filter(pk=form_telefones.fields['id'].initial).exists():
Telefone.objects.get(pk=form_telefones.fields['id'].initial).delete()
if not resposta['fones'].has_key(form.prefix):
resposta['fones'][form.prefix] = ''
resposta['fones'][form.prefix] += u'<p>O telefone %s %s foi excluído da base de dados</p>' % (
form_telefones.instance.get_tipo_display(), form_telefones.instance.numero)
else:
for key, value in form_telefones.errors.iteritems():
key = form_telefones.prefix + "-id-errors"
resposta['erros'][key] = value
json = simplejson.dumps(resposta)
return HttpResponse(json, mimetype="application/json")
else:
forms = [FuncionariosMobileForm(prefix=f.setor, instance=f)
for f, c in funcionarios]
context = RequestContext(request, {'forms': forms,
'diagnostico': diagnostico, 'casa_legislativa': casa_legislativa})
return render_to_response('diagnosticos/diagnosticos_categoria_contatos_form.html',
context)
def diagnostico_pdf(request, id_diagnostico):
diagnostico = Diagnostico.objects.get(pk=id_diagnostico)
categorias = Categoria.objects.all()
casa_legislativa = diagnostico.casa_legislativa
funcionarios = []
for n, l in Funcionario.SETOR_CHOICES:
if casa_legislativa.funcionario_set.filter(setor=n).count() <= 1:
funcionarios.append(casa_legislativa.funcionario_set.get_or_create(setor=n))
else:
for f in casa_legislativa.funcionario_set.filter(setor=n):
funcionarios.append(f)
schemas_by_categoria = []
for categoria in categorias:
schemas = []
for schema in diagnostico.get_schemata(categoria.id):
datatype = schema.datatype
data = getattr(diagnostico, schema.name)
if datatype == schema.TYPE_MANY:
schema.value = [x.pk for x in data]
elif datatype == schema.TYPE_ONE:
schema.value = data.pk if data else None,
else:
schema.value = data
schemas.append(schema)
schemas_by_categoria.append((categoria,schemas))
context = RequestContext(request, {
'pagesize':'A4',
'casa_legislativa': casa_legislativa,
'funcionarios': funcionarios,
'diagnostico': diagnostico,
'schemas_by_categoria': schemas_by_categoria,
})
return render_to_pdf('diagnosticos/diagnostico_pdf.html', context)
#return render_to_response('diagnosticos/diagnostico_pdf.html', context)
def graficos(request):
categorias = Categoria.objects.all()
sel_categoria = int(request.REQUEST.get("categoria","3"))
perguntas = Pergunta.objects.filter(categoria=sel_categoria).all()
context = RequestContext(request, {
'categorias': categorias,
'sel_categoria': sel_categoria,
'perguntas': perguntas,
})
return render_to_response('diagnosticos/graficos.html',
context)
def percentage(fraction, population):
try:
return "%.0f%%" % ((float(fraction) / float(population)) * 100)
except ValueError:
return ''
def grafico_api(request):
colors = ['ffff00', 'cc7900', 'ff0000', '92d050', '006600', '0097cc', '002776', 'ae78d6', 'ff00ff', '430080',
'28d75c', '0000ff', 'fff200']
graph_url = "http://chart.apis.google.com/chart"
#graph_params = QueryDict("chxt=y&chbh=a&chco=A2C180,3D7930")
graph_params = QueryDict("")
graph_params = graph_params.copy() # to make it mutable
width = request.REQUEST.get('width', '800')
height = request.REQUEST.get('height', '300')
graph_params.update({'chs': width + 'x' + height})
pergunta_slug = request.REQUEST.get('id', None)
pergunta = get_object_or_404(Pergunta, name=pergunta_slug)
if pergunta.datatype == 'one':
total = sum([r[1] for r in pergunta.group_choices()])
choices = [str(r[1]) for r in pergunta.group_choices()]
legend = [percentage(r[1],total) + " " + str(r[0]) for r in pergunta.group_choices()]
colors = ['ff0000', 'fff200', '0000ff', '28d75c'] + ["%0.6x" % (0x48d1 + (0xda74 * c))
for c in range(0,len(pergunta.group_choices()))]
graph_params.update({
'cht': 'p',
'chd': 't:' + ",".join(choices),
'chdl': '' + "|".join(legend),
'chco': '' + '|'.join(colors[:len(pergunta.group_choices())])
})
elif pergunta.datatype == 'many':
total = sum([r[1] for r in pergunta.group_choices()])
percent = [str(float(r[1])*100/total) for r in pergunta.group_choices()]
choices = [str(r[1]) for r in pergunta.group_choices()]
legend = [str(r[0]) for r in pergunta.group_choices()]
colors = ['ffff00', 'cc7900', 'ff0000', '92d050', '006600', '0097cc', '002776', 'ae78d6', 'ff00ff', '430080'] + \
["%0.6x" % (0x48d1 + (0xda74 * c)) for c in range(0,len(pergunta.group_choices()))]
graph_params.update({
'cht': 'bvg',
'chxt': 'y',
'chd': 't:' + ",".join(percent),
'chdl': '' + "|".join(legend),
'chl': '' + "|".join(choices),
'chco': '' + '|'.join(colors[:len(pergunta.group_choices())])
})
response = {
"type": "photo",
"width": width,
"height": height,
"title": pergunta.title,
"url": graph_url + "?" + graph_params.urlencode(),
"provider_name": "SIGI",
"provider_url": "https://intranet.interlegis.gov.br/sigi/"
}
json = simplejson.dumps(response)
return HttpResponse(json, mimetype="application/json")
def municipios_diagnosticados(self):
municipios = []
for d in Diagnostico.objects.all():
m = d.casa_legislativa.municipio
municipio = {'nome': d.casa_legislativa.nome + ', ' + m.uf.sigla, 'lat': str(m.latitude), 'lng': str(m.longitude), 'inicio': d.data_visita_inicio.strftime('%d/%m/%Y'),
'fim': d.data_visita_fim.strftime('%d/%m/%Y'), 'equipe': "<ul><li>" + "</li><li>".join([m.user.get_full_name() for m in d.membros]) + "</li></ul>",}
municipios.append(municipio)
return HttpResponse(simplejson.dumps(municipios), mimetype="application/json")

61
sigi/apps/diagnosticos/widgets.py

@ -0,0 +1,61 @@
from itertools import chain
from django.forms.widgets import CheckboxInput, CheckboxSelectMultiple, RadioSelect, RadioFieldRenderer, RadioInput
from django.utils.html import conditional_escape
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from sigi.apps.diagnosticos.models import Escolha
class EavCheckboxSelectMultiple(CheckboxSelectMultiple):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<ul>']
str_values = set([force_unicode(v) for v in value])
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
label_for = u' for="%s"' % final_attrs['id']
# Caso exista uma pergunta para abrir
# adiciona um atripbuto no checkbox
schema_to_open = Escolha.objects.get(pk=option_value).schema_to_open
if schema_to_open:
final_attrs['schema_to_open'] = schema_to_open.name
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
option_label = conditional_escape(force_unicode(option_label))
output.append(u'<li><label%s>%s %s</label></li>' % (label_for, rendered_cb, option_label))
output.append(u'</ul>')
return mark_safe(u'\n'.join(output))
class EavRadioFieldRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
final_attrs = self.attrs.copy()
# Caso exista uma pergunta para abrir
# adiciona um atripbuto no checkbox
if choice[0]:
schema_to_open = Escolha.objects.get(pk=choice[0]).schema_to_open
if schema_to_open:
final_attrs['schema_to_open'] = schema_to_open.name
yield RadioInput(self.name, self.value, final_attrs, choice, i)
def __getitem__(self, idx):
choice = self.choices[idx]
final_attrs = self.attrs.copy()
# Caso exista uma pergunta para abrir
# adiciona um atripbuto no checkbox
schema_to_open = Escolha.objects.get(pk=self.value).schema_to_open
if schema_to_open:
final_attrs['schema_to_open'] = schema_to_open.name
return RadioInput(self.name, self.value,final_attrs, choice, idx)
class EavRadioSelect(RadioSelect):
renderer = EavRadioFieldRenderer

0
sigi/apps/financeiro/__init__.py

9
sigi/apps/financeiro/admin.py

@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from sigi.apps.financeiro.models import Desembolso
class DesembolsoAdmin(admin.ModelAdmin):
list_display = ('projeto', 'descricao', 'data', 'valor_reais', 'valor_dolar',)
fields = ('projeto', 'descricao', 'data', 'valor_reais', 'valor_dolar', )
list_filter = ('projeto',)
date_hierarchy = 'data'

3
sigi/apps/financeiro/forms.py

@ -0,0 +1,3 @@
from django import forms
# place form definition here

18
sigi/apps/financeiro/models.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from django.db import models
from sigi.apps.convenios.models import Projeto
class Desembolso(models.Model):
projeto = models.ForeignKey(Projeto, 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)
valor_dolar = models.DecimalField(u'Valor em US$', max_digits=18, decimal_places=2)
class Meta:
verbose_name = 'Desembolso'
verbose_name_plural = 'Desembolsos'
def __unicode__(self):
return u"%s (US$ %s)" % (self.descricao, self.valor_dolar)

3
sigi/apps/financeiro/urls.py

@ -0,0 +1,3 @@
from django.conf.urls.defaults import *
# place app url patterns here

1
sigi/apps/financeiro/views.py

@ -0,0 +1 @@
# Create your views here.

1
sigi/apps/geraldo

@ -0,0 +1 @@
Subproject commit 868ebdce67176d9b6205cddc92476f642c783fff

0
sigi/apps/inventario/__init__.py

71
sigi/apps/inventario/admin.py

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.contrib.contenttypes import generic
from sigi.apps.contatos.models import Contato, Telefone
from sigi.apps.inventario.models import (Fornecedor, Fabricante, Equipamento,
TipoEquipamento, ModeloEquipamento,
Bem)
class ContatosInline(generic.GenericTabularInline):
model = Contato
extra = 2
raw_id_fields = ('municipio',)
class TelefonesInline(generic.GenericTabularInline):
model = Telefone
extra = 2
class FornecedorAdmin(admin.ModelAdmin):
inlines = (TelefonesInline, ContatosInline)
list_display = ('id', 'nome', 'email', 'pagina_web')
list_display_links = ('id', 'nome')
list_filter = ('nome',)
search_fields = ('id', 'nome', 'email', 'pagina_web')
class FabricanteAdmin(admin.ModelAdmin):
list_display = ('id', 'nome')
list_display_links = list_display
list_filter = ('nome',)
search_fields = ('id', 'nome')
class TipoEquipamentoAdmin(admin.ModelAdmin):
list_display = ('id', 'tipo')
list_display_links = list_display
list_filter = ('tipo',)
search_fields = ('id', 'tipo')
class ModeloEquipamentoAdmin(admin.ModelAdmin):
list_display = ('id', 'tipo', 'modelo')
list_filter = ('tipo', 'modelo')
ordering = ('tipo', 'modelo')
search_fields = ('id', 'tipo', 'modelo')
raw_id_fields = ('tipo',)
class EquipamentoAdmin(admin.ModelAdmin):
list_display = ('id', 'fabricante', 'modelo', 'get_tipo')
list_display_links = ('id',)
list_filter = ('fabricante',)
ordering = ('fabricante', 'modelo')
raw_id_fields = ('fabricante', 'modelo')
search_fields = ('id', 'modelo', 'fabricante')
def get_tipo(self, obj):
return obj.modelo.tipo.tipo
get_tipo.short_description = 'tipo'
class BemAdmin(admin.ModelAdmin):
list_display = ('equipamento', 'fornecedor', 'num_serie',
'casa_legislativa')
list_filter = ('fornecedor',)
ordering = ('casa_legislativa', 'fornecedor', 'equipamento')
raw_id_fields = ('casa_legislativa', 'equipamento', 'fornecedor')
search_fields = ('fornecedor__nome', 'equipamento__fabricante__nome',
'equipamento__modelo__modelo', 'num_serie',
'num_tombamento', 'casa_legislativa__nome')
admin.site.register(Fornecedor, FornecedorAdmin)
admin.site.register(Fabricante, FabricanteAdmin)
admin.site.register(TipoEquipamento, TipoEquipamentoAdmin)
admin.site.register(ModeloEquipamento,ModeloEquipamentoAdmin)
admin.site.register(Equipamento, EquipamentoAdmin)
admin.site.register(Bem, BemAdmin)

280
sigi/apps/inventario/fixtures/initial_data.json

@ -0,0 +1,280 @@
[
{
"pk": 3,
"model": "inventario.fornecedor",
"fields": {
"pagina_web": "http://www.dell.com.br/",
"email": "",
"nome": "Dell"
}
},
{
"pk": 1,
"model": "inventario.fornecedor",
"fields": {
"pagina_web": "",
"email": "",
"nome": "Desconhecido"
}
},
{
"pk": 2,
"model": "inventario.fornecedor",
"fields": {
"pagina_web": "http://www.submarino.com.br/",
"email": "",
"nome": "Submarino"
}
},
{
"pk": 2,
"model": "inventario.fabricante",
"fields": {
"nome": "Dell"
}
},
{
"pk": 1,
"model": "inventario.fabricante",
"fields": {
"nome": "Desconhecido"
}
},
{
"pk": 4,
"model": "inventario.fabricante",
"fields": {
"nome": "HP"
}
},
{
"pk": 3,
"model": "inventario.fabricante",
"fields": {
"nome": "Microsoft"
}
},
{
"pk": 2,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Computador Desktop"
}
},
{
"pk": 1,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Desconhecido"
}
},
{
"pk": 8,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Estabilizador"
}
},
{
"pk": 3,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Impressora"
}
},
{
"pk": 5,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Modem"
}
},
{
"pk": 4,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Monitor"
}
},
{
"pk": 9,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Notebook/Laptop"
}
},
{
"pk": 6,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Roteador"
}
},
{
"pk": 7,
"model": "inventario.tipoequipamento",
"fields": {
"tipo": "Webcam"
}
},
{
"pk": 1,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 1
}
},
{
"pk": 2,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 3
}
},
{
"pk": 3,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 2
}
},
{
"pk": 4,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 8
}
},
{
"pk": 5,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 5
}
},
{
"pk": 6,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 4
}
},
{
"pk": 7,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 9
}
},
{
"pk": 8,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 6
}
},
{
"pk": 9,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Desconhecido",
"tipo": 7
}
},
{
"pk": 10,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "PSC 500",
"tipo": 3
}
},
{
"pk": 11,
"model": "inventario.modeloequipamento",
"fields": {
"modelo": "Vostro 1310",
"tipo": 9
}
},
{
"pk": 1,
"model": "inventario.equipamento",
"fields": {
"modelo": 1,
"fabricante": 1
}
},
{
"pk": 2,
"model": "inventario.equipamento",
"fields": {
"modelo": 2,
"fabricante": 1
}
},
{
"pk": 3,
"model": "inventario.equipamento",
"fields": {
"modelo": 3,
"fabricante": 1
}
},
{
"pk": 4,
"model": "inventario.equipamento",
"fields": {
"modelo": 4,
"fabricante": 1
}
},
{
"pk": 5,
"model": "inventario.equipamento",
"fields": {
"modelo": 5,
"fabricante": 1
}
},
{
"pk": 6,
"model": "inventario.equipamento",
"fields": {
"modelo": 6,
"fabricante": 1
}
},
{
"pk": 7,
"model": "inventario.equipamento",
"fields": {
"modelo": 7,
"fabricante": 1
}
},
{
"pk": 8,
"model": "inventario.equipamento",
"fields": {
"modelo": 8,
"fabricante": 1
}
},
{
"pk": 9,
"model": "inventario.equipamento",
"fields": {
"modelo": 9,
"fabricante": 1
}
}
]

90
sigi/apps/inventario/models.py

@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.contenttypes import generic
class Fornecedor(models.Model):
nome = models.CharField(max_length=40)
nome.alphabetic_filter = True
email = models.EmailField('e-mail', blank=True)
pagina_web = models.URLField('página web', blank=True)
telefones = generic.GenericRelation('contatos.Telefone')
contatos = generic.GenericRelation('contatos.Contato')
class Meta:
ordering = ('nome',)
verbose_name_plural = 'fornecedores'
def __unicode__(self):
return self.nome
class Fabricante(models.Model):
nome = models.CharField(max_length=40, unique=True)
nome.alphabetic_filter = True
class Meta:
ordering = ('nome',)
def __unicode__(self):
return self.nome
class TipoEquipamento(models.Model):
tipo = models.CharField(max_length=40)
tipo.alphabetic_filter = True
class Meta:
ordering = ('tipo',)
verbose_name = 'tipo de equipamento'
verbose_name_plural = 'tipos de equipamentos'
def __unicode__(self):
return self.tipo
class ModeloEquipamento(models.Model):
tipo = models.ForeignKey(
TipoEquipamento,
verbose_name='tipo de equipamento'
)
modelo = models.CharField(max_length=30)
modelo.alphabetic_filter = True
class Meta:
ordering = ('modelo',)
verbose_name = 'modelo de equipamento'
verbose_name_plural = 'modelos de equipamentos'
def __unicode__(self):
return self.modelo
class Equipamento(models.Model):
fabricante = models.ForeignKey(Fabricante)
modelo = models.ForeignKey(ModeloEquipamento)
class Meta:
unique_together = (('fabricante', 'modelo'),)
def __unicode__(self):
return unicode('%s %s %s' % (self.modelo.tipo, self.fabricante.nome,
self.modelo.modelo))
class Bem(models.Model):
casa_legislativa = models.ForeignKey('casas.CasaLegislativa')
equipamento = models.ForeignKey(Equipamento)
fornecedor = models.ForeignKey(Fornecedor)
num_serie = models.CharField(
'número de série',
max_length=64,
help_text='Número fornecido pelo fabricante.',
unique=True
)
recebido_por = models.CharField(
max_length=64,
blank=True,
help_text='Nome de quem recebeu o equipamento.'
)
observacoes = models.TextField('observações', blank=True)
class Meta:
verbose_name_plural = 'bens'
def __unicode__(self):
return unicode('%s (%s)') % (self.equipamento, self.casa_legislativa)

0
sigi/apps/mesas/__init__.py

102
sigi/apps/mesas/admin.py

@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.http import HttpResponse
from django.utils.html import escape
from sigi.apps.mesas.models import (Legislatura, Coligacao, ComposicaoColigacao,
SessaoLegislativa, MesaDiretora, Cargo,
MembroMesaDiretora)
from sigi.apps.parlamentares.models import Mandato
class MandatoInline(admin.TabularInline):
model = Mandato
raw_id_fields = ['parlamentar',]
class LegislaturaAdmin(admin.ModelAdmin):
date_hierarchy = 'data_inicio'
list_display = ('numero', 'casa_legislativa', 'uf', 'data_inicio', 'data_fim', 'data_eleicao', 'total_parlamentares')
raw_id_fields = ('casa_legislativa',)
list_display_links = ('numero',)
list_filter = ('casa_legislativa', )
search_fields = ('casa_legislativa__nome', 'casa_legislativa__municipio__nome' )
inlines = (MandatoInline,)
def uf(self, obj):
return obj.casa_legislativa.municipio.uf.sigla
uf.short_description = 'UF'
uf.admin_order_field = 'casa_legislativa__municipio__uf'
def lookup_allowed(self, lookup, value):
return super(LegislaturaAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact']
def response_change(self, request, obj):
response = super(LegislaturaAdmin, self).response_change(request, obj)
if request.POST.has_key("_popup"):
response = HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(obj.pk), escapejs(obj)))
return response
class ColigacaoAdmin(admin.ModelAdmin):
list_display = ('nome', 'legislatura', 'numero_votos')
list_display_links = ('nome',)
raw_id_fields = ('legislatura',)
search_fields = ('nome', 'legislatura__numero')
class ComposicaoColigacaoAdmin(admin.ModelAdmin):
list_display = ('coligacao', 'partido')
list_display_links = ('coligacao', 'partido')
list_filter = ('partido',)
raw_id_fields = ('coligacao', 'partido')
search_fields = ('coligacao__nome', 'partido__nome', 'partido__sigla')
class SessaoLegislativaAdmin(admin.ModelAdmin):
list_display = ('numero', 'mesa_diretora', 'legislatura', 'tipo',
'data_inicio', 'data_fim')
list_display_links = ('numero',)
list_filter = ('tipo',)
fieldsets = (
(None, {
'fields': ('numero', 'mesa_diretora', 'legislatura', 'tipo')
}),
(None, {
'fields': (('data_inicio', 'data_fim'),
('data_inicio_intervalo', 'data_fim_intervalo'))
}),
)
radio_fields = {'tipo': admin.VERTICAL}
raw_id_fields = ('mesa_diretora', 'legislatura')
search_fields = ('numero', 'mesa_diretora__casa_legislativa__nome')
class CargoAdmin(admin.ModelAdmin):
list_display = ('descricao',)
search_fields = ('descricao',)
class MembroMesaDiretoraInline(admin.TabularInline):
model = MembroMesaDiretora
max_num = 11
extra = 4
raw_id_fields = ('parlamentar', 'cargo')
class MembroMesaDiretoraAdmin(admin.ModelAdmin):
list_display = ('parlamentar', 'cargo', 'mesa_diretora')
list_display_links = ('parlamentar',)
list_filter = ('cargo',)
raw_id_fields = ('parlamentar', 'cargo', 'mesa_diretora')
search_fields = ('cargo__descricao', 'parlamentar__nome_completo',
'parlamentar__nome_parlamentar',
'mesa_diretora__casa_legislativa__nome')
class MesaDiretoraAdmin(admin.ModelAdmin):
inlines = (MembroMesaDiretoraInline,)
raw_id_fields = ('casa_legislativa',)
list_display = ('id', 'casa_legislativa')
search_fields = ('casa_legislativa__nome',)
admin.site.register(Legislatura, LegislaturaAdmin)
admin.site.register(Coligacao, ColigacaoAdmin)
admin.site.register(ComposicaoColigacao, ComposicaoColigacaoAdmin)
admin.site.register(SessaoLegislativa, SessaoLegislativaAdmin)
admin.site.register(MesaDiretora, MesaDiretoraAdmin)
admin.site.register(Cargo, CargoAdmin)
admin.site.register(MembroMesaDiretora, MembroMesaDiretoraAdmin)

44
sigi/apps/mesas/fixtures/initial_data.json

@ -0,0 +1,44 @@
[
{
"pk": 4,
"model": "mesas.cargo",
"fields": {
"descricao": "1\u00ba Secret\u00e1rio"
}
},
{
"pk": 2,
"model": "mesas.cargo",
"fields": {
"descricao": "1\u00ba Vice-Presidente"
}
},
{
"pk": 5,
"model": "mesas.cargo",
"fields": {
"descricao": "2\u00ba Secret\u00e1rio"
}
},
{
"pk": 3,
"model": "mesas.cargo",
"fields": {
"descricao": "2\u00ba Vice-Presidente"
}
},
{
"pk": 6,
"model": "mesas.cargo",
"fields": {
"descricao": "Corregedor"
}
},
{
"pk": 1,
"model": "mesas.cargo",
"fields": {
"descricao": "Presidente"
}
}
]

122
sigi/apps/mesas/models.py

@ -0,0 +1,122 @@
# coding: utf-8
from django.db import models
from sigi.apps.casas.models import CasaLegislativa
class Legislatura(models.Model):
casa_legislativa = models.ForeignKey(CasaLegislativa)
numero = models.PositiveSmallIntegerField(u'número legislatura')
data_inicio = models.DateField(u'início')
data_fim = models.DateField(u'fim')
data_eleicao = models.DateField(u'data da eleição')
total_parlamentares = models.PositiveIntegerField(u"Total de parlamentares")
casa_legislativa.convenio_uf_filter = True
casa_legislativa.convenio_cl_tipo_filter = True
def meta(self):
unique_together = (('casa_legislativa', 'numero'))
ordering = ['casa_legislativa__municipio__uf__sigla', '-data_inicio']
def __unicode__(self):
return u"%sª legislatura da %s (%s-%s)" % (self.numero, self.casa_legislativa.__unicode__(), self.data_inicio.year, self.data_fim.year)
class Coligacao(models.Model):
nome = models.CharField(max_length=50)
legislatura = models.ForeignKey(Legislatura)
numero_votos = models.PositiveIntegerField(
u'número de votos',
blank=True,
null=True,
)
class Meta:
ordering = ('legislatura', 'nome')
verbose_name = 'coligação'
verbose_name_plural = 'coligações'
def __unicode__(self):
return self.nome
class ComposicaoColigacao(models.Model):
coligacao = models.ForeignKey(Coligacao, verbose_name='coligação')
partido = models.ForeignKey('parlamentares.Partido')
class Meta:
verbose_name = 'composição da coligação'
verbose_name_plural = 'composições das coligações'
def __unicode__(self):
return str(self.id)
class SessaoLegislativa(models.Model):
SESSAO_CHOICES = (
('O', 'Ordinária'),
('E', 'Extraordinária'),
)
numero = models.PositiveSmallIntegerField(u'número da sessão', unique=True)
mesa_diretora = models.ForeignKey(
'MesaDiretora',
verbose_name='Mesa Diretora'
)
legislatura = models.ForeignKey(Legislatura)
tipo = models.CharField(
max_length=1,
choices=SESSAO_CHOICES,
default='O'
)
data_inicio = models.DateField(u'início')
data_fim = models.DateField('fim')
data_inicio_intervalo = models.DateField(
u'início de intervalo',
blank=True,
null=True
)
data_fim_intervalo = models.DateField(
'fim de intervalo',
blank=True,
null=True
)
class Meta:
ordering = ('legislatura', 'numero')
verbose_name = 'Sessão Legislativa'
verbose_name_plural = 'Sessões Legislativas'
def __unicode__(self):
return str(self.numero)
class MesaDiretora(models.Model):
casa_legislativa = models.ForeignKey(
'casas.CasaLegislativa',
verbose_name='Casa Legislativa'
)
class Meta:
verbose_name = 'Mesa Diretora'
verbose_name_plural = 'Mesas Diretoras'
def __unicode__(self):
return 'Mesa Diretora da %s' % unicode(self.casa_legislativa)
class Cargo(models.Model):
descricao = models.CharField(u'descrição', max_length=30)
class Meta:
ordering = ('descricao',)
def __unicode__(self):
return self.descricao
class MembroMesaDiretora(models.Model):
parlamentar = models.ForeignKey('parlamentares.Parlamentar')
cargo = models.ForeignKey(Cargo)
mesa_diretora = models.ForeignKey(MesaDiretora)
class Meta:
ordering = ('parlamentar',)
unique_together = ('cargo', 'mesa_diretora')
verbose_name = 'membro de Mesa Diretora'
verbose_name_plural = 'membros de Mesas Diretora'
def __unicode__(self):
return '%s (%s)' % (unicode(self.parlamentar), unicode(self.cargo))

0
sigi/apps/metas/__init__.py

46
sigi/apps/metas/admin.py

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from sigi.apps.metas.models import Meta, PlanoDiretor
class MetaAdmin(admin.ModelAdmin):
list_display = ('projeto', 'titulo', 'data_inicio', 'data_fim', 'valor_meta', 'valor_executado', 'percentual_concluido',)
fields = ('projeto', 'titulo', 'descricao', 'data_inicio', 'data_fim', 'algoritmo', 'valor_meta',)
list_filter = ('projeto',)
class PlanoDiretorAdmin(admin.ModelAdmin):
list_display = ('projeto', 'casa_legislativa', 'get_uf', 'status', 'data_entrega', 'data_implantacao',)
fields = ('projeto', 'casa_legislativa', 'status', 'data_entrega', 'data_implantacao',)
raw_id_fields = ('casa_legislativa',)
list_filter = ('projeto', 'status', 'casa_legislativa', )
def get_uf(self, obj):
return obj.casa_legislativa.municipio.uf.nome
get_uf.short_description = u"UF"
get_uf.admin_order_field = 'casa_legislativa__municipio__uf__nome'
def lookup_allowed(self, lookup, value):
return super(PlanoDiretorAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact']
def changelist_view(self, request, extra_context=None):
import re
request.GET._mutable=True
if 'data_entrega__gte' in request.GET:
value = request.GET.get('data_entrega__gte','')
if value == '':
del request.GET['data_entrega__gte']
elif re.match('^\d*$', value): # Year only
request.GET['data_entrega__gte'] = "%s-01-01" % value #Complete with january 1st
elif re.match('^\d*\D\d*$', value): # Year and month
request.GET['data_entrega__gte'] = '%s-01' % value #Complete with 1st day of month
if 'data_entrega__lte' in request.GET:
value = request.GET.get('data_entrega__lte','')
if value == '':
del request.GET['data_entrega__lte']
elif re.match('^\d*$', value): # Year only
request.GET['data_entrega__lte'] = "%s-01-01" % value #Complete with january 1st
elif re.match('^\d*\D\d*$', value): # Year and month
request.GET['data_entrega__lte'] = '%s-01' % value #Complete with 1st day of month
request.GET._mutable=False
return super(PlanoDiretorAdmin, self).changelist_view(request, extra_context)

3
sigi/apps/metas/forms.py

@ -0,0 +1,3 @@
from django import forms
# place form definition here

0
sigi/apps/metas/management/__init__.py

0
sigi/apps/metas/management/commands/__init__.py

31
sigi/apps/metas/management/commands/gera_map_data.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.servicos.management.commands.atualiza_uso_servico
#
# Copyright (c) 2012 by Interlegis
#
# GNU General Public License (GPL)
#
# 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.core.management.base import BaseCommand
from sigi.apps.metas.views import gera_map_data_file
class Command(BaseCommand):
help = u'Gera arquivo de dados de plotagem do mapa de atuação do Interlegis.'
def handle(self, *args, **options):
result = gera_map_data_file(cronjob=True)
self.stdout.write(result+"\n")

128
sigi/apps/metas/models.py

@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
from datetime import date, datetime
from django.db import models
from sigi.apps.convenios.models import Projeto, Convenio
from sigi.apps.diagnosticos.models import Diagnostico
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.financeiro.models import Desembolso
class Meta(models.Model):
ALGORITMO_CHOICES = (
('SUM_GASTOS', u'Soma dos desembolsos'),
('COUNT_EQUI', u'Quantidade de casas equipadas'),
('COUNT_ADER', u'Quantidade de casas aderidas'),
('COUNT_DIAG', u'Quantidade de casas diagnosticadas'),
('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')
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')
data_fim = models.DateField(u'Data final', help_text=u'Prazo final para cumprimento da meta')
algoritmo = models.CharField(u'Algoritmo de cálculo', max_length=10, choices=ALGORITMO_CHOICES)
valor_meta = models.FloatField(u'Valor da meta', help_text=u'Valor que deve ser atingido até o prazo final da meta')
class Meta:
verbose_name = 'Meta BID'
verbose_name_plural = 'Metas BID'
def __unicode__(self):
return self.titulo;
@property
def valor_executado(self):
"""
Calcula o valor executado da meta
"""
algoritmo = self.algoritmo.lower()
valor = getattr(self, algoritmo)()
try:
valor = float(valor)
except:
valor = 0.0
return valor
@property
def percentual_concluido(self):
return round(float(self.valor_executado) / float(self.valor_meta) * 100.0, 2)
@property
def valor_desejado(self):
total_dias = (self.data_fim - self.data_inicio).days + 1
dias_gastos = (date.today() - self.data_inicio).days + 1
meta_dia = self.valor_meta / total_dias
return meta_dia * dias_gastos
@property
def percentual_desejado_low(self):
return (self.valor_desejado / self.valor_meta) - 0.05 # 5% abaixo do desejado
@property
def percentual_desejado_high(self):
return (self.valor_desejado / self.valor_meta) + 0.05 # 5% acima do desejado
@property
def saude(self):
percentual_concluido = self.percentual_concluido / 100.0
if percentual_concluido >= 1:
return 'A2BBED' # Blue
if percentual_concluido > self.percentual_desejado_high:
return '89D7AF' # Green
if percentual_concluido > self.percentual_desejado_low:
return 'FFDB6E' # Orange
return 'E74A69' # Red
def sum_gastos(self):
valor = Desembolso.objects.filter(projeto=self.projeto, data__gte=self.data_inicio, data__lte=self.data_fim) \
.aggregate(total_dolar=models.Sum('valor_dolar'))
valor = valor['total_dolar']
return valor
def count_equi(self):
valor = Convenio.objects.filter(casa_legislativa__tipo__sigla='CM', equipada=True, projeto__pk=3, data_termo_aceite__gte=
self.data_inicio, data_termo_aceite__lte=self.data_fim).exclude(data_termo_aceite=None).count()
return valor
def count_ader(self):
valor = Convenio.objects.filter(casa_legislativa__tipo__sigla='CM', projeto=self.projeto, data_adesao__gte=self.data_inicio,
data_adesao__lte=self.data_fim).exclude(data_adesao=None).count()
return valor
def count_diag(self):
valor = Diagnostico.objects.filter(data_visita_inicio__gte=self.data_inicio, data_visita_inicio__lte=self.data_fim,
publicado=True).count()
return valor
def count_pdir(self):
valor = PlanoDiretor.objects.filter(projeto=self.projeto, data_entrega__gte=self.data_inicio,
data_entrega__lte=self.data_fim).count()
return valor
def count_conv(self):
valor = Convenio.objects.filter(casa_legislativa__tipo__sigla='CM', projeto=self.projeto, data_retorno_assinatura__gte=
self.data_inicio, data_retorno_assinatura__lte=self.data_fim).exclude(data_retorno_assinatura=None).count()
return valor
class PlanoDiretor(models.Model):
STATUS_CHOICE = (
('E', u'Entregue'),
('I', u'Implantado'),
)
projeto = models.ForeignKey(Projeto, verbose_name=u'Projeto')
casa_legislativa = models.ForeignKey(CasaLegislativa, 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)
data_implantacao = models.DateField(u'Data de implantação', blank=True, null=True)
class Meta:
verbose_name = 'Plano Diretor'
verbose_name_plural = 'Planos Diretores'
def __unicode__(self):
return self.casa_legislativa.nome ;

0
sigi/apps/metas/templatetags/__init__.py

35
sigi/apps/metas/templatetags/mapa_tags.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from django import template
from django.utils.safestring import mark_safe
from sigi.apps.casas.models import CasaLegislativa
register = template.Library()
@register.filter(name='map_desc_serv')
def descricao_servicos(value):
if not isinstance(value, CasaLegislativa):
return ""
result = ""
for sv in value.servico_set.all():
result += u'<li>%s ativado em %s</li>' % (sv.tipo_servico.nome, sv.data_ativacao.strftime('%d/%m/%Y'))
for cv in value.convenio_set.all():
if (cv.data_retorno_assinatura is None) and (cv.equipada and cv.data_termo_aceite is not None):
result += u"<li>Equipada em %s pelo %s</li>" % (cv.data_termo_aceite.strftime('%d/%m/%Y'), cv.projeto.sigla)
if (cv.data_retorno_assinatura is not None) and not (cv.equipada and cv.data_termo_aceite is not None):
result += u"<li>Conveniada ao %s em %s</li>" % (cv.projeto.sigla, cv.data_retorno_assinatura.strftime('%d/%m/%Y'))
if (cv.data_retorno_assinatura is not None) and (cv.equipada and cv.data_termo_aceite is not None):
result += u"<li>Conveniada ao %s em %s e equipada em %s</li>" % (cv.projeto.sigla, cv.data_retorno_assinatura.strftime('%d/%m/%Y'), cv.data_termo_aceite.strftime('%d/%m/%Y'))
for dg in value.diagnostico_set.all():
result += u'<li>Diagnosticada no período de %s a %s</li>' % (dg.data_visita_inicio.strftime('%d/%m/%Y') if dg.data_visita_inicio
else u"<< sem data inicial >>",
dg.data_visita_fim.strftime('%d/%m/%Y') if dg.data_visita_fim
else u"<< sem data final >>")
return mark_safe(result)
descricao_servicos.is_safe = True

3
sigi/apps/metas/urls.py

@ -0,0 +1,3 @@
from django.conf.urls.defaults import *
# place app url patterns here

345
sigi/apps/metas/views.py

@ -0,0 +1,345 @@
# -*- coding: utf-8 -*-
import csv
from django.http import HttpResponse
from django.core.exceptions import PermissionDenied
from django.utils import simplejson
from django.utils.datastructures import SortedDict
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.db.models import Q
from django.views.decorators.cache import cache_page
from django.db.models.aggregates import Sum
from django.contrib.auth.decorators import user_passes_test, login_required
from sigi.settings import MEDIA_ROOT
from sigi.shortcuts import render_to_pdf
from sigi.apps.servicos.models import TipoServico, Servico
from sigi.apps.convenios.models import Projeto, Convenio
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.utils import to_ascii
from sigi.apps.financeiro.models import Desembolso
from sigi.apps.metas.templatetags.mapa_tags import descricao_servicos
JSON_FILE_NAME = MEDIA_ROOT + 'apps/metas/map_data.json'
@login_required
def dashboard(request):
if request.user.groups.filter(name__in=['SPDT-Servidores', 'SSPLF']).count() <= 0:
raise PermissionDenied
desembolsos_max = 0
matriz = SortedDict()
dados = SortedDict()
projetos = Projeto.objects.all()
meses = Desembolso.objects.dates('data', 'month', 'DESC')[:6]
colors = ['ffff00', 'cc7900', 'ff0000', '92d050', '006600', '0097cc', '002776', 'ae78d6', 'ff00ff', '430080',
'28d75c', '0000ff', 'fff200']
for date in reversed(meses):
mes_ano = '%s/%s' % (date.month, date.year)
dados[mes_ano] = 0
for p in projetos:
matriz[p.id] = (p.sigla, dados.copy())
for date in meses:
mes_ano = '%s/%s' % (date.month, date.year)
for d in Desembolso.objects.filter(data__year=date.year, data__month=date.month).values('projeto').annotate(total_dolar=Sum('valor_dolar')):
if int(d['total_dolar']) > desembolsos_max:
desembolsos_max = int(d['total_dolar'])
matriz[d['projeto']][1][mes_ano] += int(d['total_dolar'])
meses = ["%s/%s" % (m.month, m.year) for m in reversed(meses)]
extra_context = {'desembolsos': matriz, 'desembolsos_max': desembolsos_max, 'meses': meses, 'colors': ','.join(colors[:len(matriz)])}
return render_to_response('metas/dashboard.html', extra_context, context_instance=RequestContext(request))
def mapa(request):
"""
Mostra o mapa com filtros carregados com valores default
"""
regiao_choices = UnidadeFederativa.REGIAO_CHOICES
estado_choices = UnidadeFederativa.objects.all()
servico_choices = TipoServico.objects.all()
projeto_choices = Projeto.objects.all()
seit = [ ts.sigla for ts in servico_choices]
convenios = ['PML'] # Apenas o ultimo #hardcoded #fixme
equipadas = [] #[p.sigla for p in projeto_choices]
diagnosticos = ['P'] # choices: ["A", "P"]
regioes = [r[0] for r in regiao_choices]
estados = []
extra_context = {
'seit': seit,
'convenios': convenios,
'equipadas': equipadas,
'diagnosticos': diagnosticos,
'regioes': regioes,
'estados': estados,
'regiao_choices': regiao_choices,
'estado_choices': estado_choices,
'servico_choices': servico_choices,
'projeto_choices': projeto_choices,
}
return render_to_response('metas/mapa.html', extra_context, context_instance=RequestContext(request))
@cache_page(1800) # Cache de 30min
def map_data(request):
"""
Retorna json com todos os dados dos municípios que têm relação com o Interlegis
Tenta ler esse json do arquivo JSON_FILE_NAME. Se não encontrar, chama a rotina
gera_map_data_file().
"""
try:
file = open(JSON_FILE_NAME, 'r')
json = file.read()
except:
json = gera_map_data_file()
return HttpResponse(json, mimetype="application/json")
def map_search(request):
response = {'result': 'NOT_FOUND'}
if 'q' in request.GET:
q = request.GET.get('q')
if len(q.split(',')) > 1:
municipio, uf = [s.strip() for s in q.split(',')]
casas = CasaLegislativa.objects.filter(search_text__icontains=to_ascii(municipio), municipio__uf__sigla__iexact=uf)
else:
casas = CasaLegislativa.objects.filter(search_text__icontains=to_ascii(q))
if casas.count() > 0:
response = {'result': 'FOUND', 'ids': [c.pk for c in casas]}
return HttpResponse(simplejson.dumps(response), mimetype="application/json")
@cache_page(86400) # Cache de um dia (24 horas = 86400 segundos)
def map_sum(request):
# Filtrar Casas de acordo com os parâmetros
param = get_params(request)
casas = filtrar_casas(**param)
# Montar registros de totalização
tot_servicos = SortedDict()
tot_projetos = SortedDict()
tot_diagnosticos = SortedDict()
for ts in TipoServico.objects.all():
tot_servicos[ts.sigla] = 0
for pr in Projeto.objects.all():
tot_projetos[pr.sigla] = 0
tot_convenios = tot_projetos.copy()
tot_equipadas = tot_projetos.copy()
tot_diagnosticos['A'] = 0
tot_diagnosticos['P'] = 0
# Montar as linhas do array de resultados com as regiões e os estados
result = {}
for uf in UnidadeFederativa.objects.filter(Q(regiao__in=param['regioes']) | Q(sigla__in=param['estados'])).order_by('regiao', 'nome'):
if not result.has_key(uf.regiao):
result[uf.regiao] = {'nome': uf.get_regiao_display(), 'ufs': {}, 'servicos': tot_servicos.copy(),
'convenios': tot_projetos.copy(), 'equipadas': tot_projetos.copy(),
'diagnosticos': tot_diagnosticos.copy()}
result[uf.regiao]['ufs'][uf.codigo_ibge] = {'nome': uf.nome, 'servicos': tot_servicos.copy(),
'convenios': tot_projetos.copy(), 'equipadas': tot_projetos.copy(),
'diagnosticos': tot_diagnosticos.copy()}
# Processar as casas filtradas
for casa in casas.distinct():
uf = casa.municipio.uf
for s in casa.servico_set.all():
tot_servicos[s.tipo_servico.sigla] += 1
result[uf.regiao]['servicos'][s.tipo_servico.sigla] += 1
result[uf.regiao]['ufs'][uf.codigo_ibge]['servicos'][s.tipo_servico.sigla] += 1
for c in casa.convenio_set.all():
tot_convenios[c.projeto.sigla] += 1
result[uf.regiao]['convenios'][c.projeto.sigla] += 1
result[uf.regiao]['ufs'][uf.codigo_ibge]['convenios'][c.projeto.sigla] += 1
if (c.equipada and c.data_termo_aceite is not None):
tot_equipadas[c.projeto.sigla] += 1
result[uf.regiao]['equipadas'][c.projeto.sigla] += 1
result[uf.regiao]['ufs'][uf.codigo_ibge]['equipadas'][c.projeto.sigla] += 1
for d in casa.diagnostico_set.all():
if d.publicado:
tot_diagnosticos['P'] += 1
result[uf.regiao]['diagnosticos']['P'] += 1
result[uf.regiao]['ufs'][uf.codigo_ibge]['diagnosticos']['P'] += 1
else:
tot_diagnosticos['A'] += 1
result[uf.regiao]['diagnosticos']['A'] += 1
result[uf.regiao]['ufs'][uf.codigo_ibge]['diagnosticos']['A'] += 1
extra_context = {
'pagesize': 'a4 landscape',
'servicos': TipoServico.objects.all(),
'projetos': Projeto.objects.all(),
'result': result,
'tot_servicos': tot_servicos,
'tot_convenios': tot_convenios,
'tot_equipadas': tot_equipadas,
'tot_diagnosticos': tot_diagnosticos,
}
return render_to_pdf('metas/map_sum.html', extra_context)
@cache_page(86400) # Cache de um dia (24 horas = 86400 segundos)
def map_list(request):
# Filtrar Casas de acordo com os parâmetros
param = get_params(request)
formato = request.GET.get('fmt', 'pdf')
casas = filtrar_casas(**param)
casas = casas.order_by('municipio__uf__regiao', 'municipio__uf__nome', 'nome').distinct()
if formato == 'csv':
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="maplist.csv"'
writer = csv.writer(response)
srv = {}
for ts in TipoServico.objects.all():
srv[ts.pk] = ts.nome
cnv = {}
for pr in Projeto.objects.all():
cnv[pr.id] = pr.sigla
writer.writerow([u'codigo_ibge', u'nome_casa', u'municipio', u'uf', u'regiao',] + [x for x in srv.values()] +
reduce(lambda x,y: x+y, [['conveniada ao %s' % x, 'equipada por %s' % x] for x in cnv.values()]))
for casa in casas:
row = [casa.municipio.codigo_ibge, casa.nome, casa.municipio.nome, casa.municipio.uf.sigla,
casa.municipio.uf.get_regiao_display(),]
for id in srv.keys():
try:
sv = casa.servico_set.get(tipo_servico__id=id)
row += [sv.data_ativacao,]
except:
row += [None,]
for id in cnv.keys():
try:
cv = casa.convenio_set.get(projeto__id=id)
row += [cv.data_retorno_assinatura, cv.data_termo_aceite if cv.equipada else None,]
except:
row += [None, None,]
writer.writerow(row)
return response
return render_to_pdf('metas/map_list.html', {'casas': casas})
#----------------------------------------------------------------------------------------------------
# Funções auxiliares - não são views
#----------------------------------------------------------------------------------------------------
def get_params(request):
''' Pegar parâmetros da pesquisa '''
return {
'seit' : request.GET.getlist('seit'),
'convenios' : request.GET.getlist('convenios'),
'equipadas' : request.GET.getlist('equipadas'),
'diagnosticos' : request.GET.getlist('diagnosticos'),
'regioes' : request.GET.getlist('regioes'),
'estados' : request.GET.getlist('estados'),
}
def filtrar_casas(seit, convenios, equipadas, regioes, estados, diagnosticos):
''' Filtrar Casas que atendem aos parâmetros de pesquisa '''
qServico = Q(servico__tipo_servico__sigla__in=seit)
qConvenio = Q(convenio__projeto__sigla__in=convenios)
qEquipada = Q(convenio__projeto__sigla__in=equipadas, convenio__equipada=True)
qRegiao = Q(municipio__uf__regiao__in=regioes)
qEstado = Q(municipio__uf__sigla__in=estados)
if diagnosticos:
qDiagnostico = Q(diagnostico__publicado__in=[p == 'P' for p in diagnosticos])
else:
qDiagnostico = Q()
casas = CasaLegislativa.objects.filter(qServico | qConvenio | qEquipada | qDiagnostico).filter(qRegiao | qEstado)
return casas
def gera_map_data_file(cronjob=False):
''' Criar um arquivo json em {settings.MEDIA_ROOT}/apps/metas/ com o nome de map_data.json
Este arquivo será consumido pela view de dados de mapa.
Retorna os dados json caso cronjob seja falso.
Caso cronjob seja True, retorna log de tempo gasto na geração ou a mensagem do erro
que impediu a gravação do arquivo.
'''
import time
start = time.time()
casas = {}
for c in CasaLegislativa.objects.select_related('servico', 'convenio', 'diagnostico').all().distinct():
if c.servico_set.count() == 0 and c.convenio_set.count() == 0 and c.diagnostico_set.count() == 0:
continue; # Salta essa casa, pois ela não tem nada com o Interlegis
if not casas.has_key(c.pk):
casa = {
'nome': c.nome + ', ' + c.municipio.uf.sigla,
'icone': 'mapmarker',
'lat': str(c.municipio.latitude),
'lng': str(c.municipio.longitude),
'estado': c.municipio.uf.sigla,
'regiao': c.municipio.uf.regiao,
'diagnosticos': [],
'seit': [],
'convenios': [],
'equipadas': [],
'info': []
}
for sv in c.servico_set.all():
casa['info'].append(u"%s ativado em %s <a href='%s' target='_blank'><img src='/sigi/media/images/link.gif' alt='link'></a>" % (
sv.tipo_servico.nome, sv.data_ativacao.strftime('%d/%m/%Y') if sv.data_ativacao else
u'<sem data de ativação>', sv.url))
casa['seit'].append(sv.tipo_servico.sigla)
for cv in c.convenio_set.all():
if (cv.data_retorno_assinatura is None) and (cv.equipada and cv.data_termo_aceite is not None):
casa['info'].append(u"Equipada em %s pelo %s" % (cv.data_termo_aceite.strftime('%d/%m/%Y'), cv.projeto.sigla))
casa['equipadas'].append(cv.projeto.sigla)
if (cv.data_retorno_assinatura is not None) and not (cv.equipada and cv.data_termo_aceite is not None):
casa['info'].append(u"Conveniada ao %s em %s" % (cv.projeto.sigla, cv.data_retorno_assinatura.strftime('%d/%m/%Y')))
casa['convenios'].append(cv.projeto.sigla)
if (cv.data_retorno_assinatura is not None) and (cv.equipada and cv.data_termo_aceite is not None):
casa['info'].append(u"Conveniada ao %s em %s e equipada em %s" % (cv.projeto.sigla, cv.data_retorno_assinatura.strftime('%d/%m/%Y'), cv.data_termo_aceite.strftime('%d/%m/%Y')))
casa['equipadas'].append(cv.projeto.sigla)
casa['convenios'].append(cv.projeto.sigla)
for dg in c.diagnostico_set.all():
casa['diagnosticos'].append('P' if dg.publicado else 'A')
casa['info'].append(u'Diagnosticada no período de %s a %s' % (dg.data_visita_inicio.strftime('%d/%m/%Y') if
dg.data_visita_inicio is not None else u"<sem data de início>",
dg.data_visita_fim.strftime('%d/%m/%Y') if dg.data_visita_fim else u"<sem data de término>"))
casa['info'] = "<br/>".join(casa['info'])
casas[c.pk] = casa
json_data = simplejson.dumps(casas)
try:
file = open(JSON_FILE_NAME, 'w')
file.write(json_data)
file.close()
except Exception as e: # A gravação não foi bem sucedida ...
if cronjob: # ... o chamador deseja a mensagem de erro
return str(e)
else:
pass # ... ou os dados poderão ser usados de qualquer forma
if cronjob:
return "Arquivo %s gerado em %d segundos" % (JSON_FILE_NAME, time.time() - start)
return json_data

0
sigi/apps/ocorrencias/__init__.py

105
sigi/apps/ocorrencias/admin.py

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.contrib import admin
from django.contrib.admin.views.main import ChangeList
from eav.admin import BaseEntityAdmin, BaseSchemaAdmin
from sigi.apps.servidores.models import Servidor
from sigi.apps.ocorrencias.models import Ocorrencia, Comentario, Anexo, Categoria
class ComentarioViewInline(admin.TabularInline):
model = Comentario
extra = 0
max_num=0
can_delete = False
verbose_name, verbose_name_plural = u"Comentário anterior", u"Comentários anteriores"
fields = ('usuario', 'data_criacao', 'novo_status', 'encaminhar_setor', 'descricao', )
readonly_fields = ('novo_status', 'encaminhar_setor', 'descricao', 'data_criacao', 'usuario',)
class ComentarioInline(admin.StackedInline):
model = Comentario
extra = 3
verbose_name, verbose_name_plural = u"Comentário novo", u"Comentários novos"
fieldsets = ((None, {'fields': (('novo_status', 'encaminhar_setor',), 'descricao', )}),)
def queryset(self, request):
return self.model.objects.get_empty_query_set()
class AnexosInline(admin.TabularInline):
model = Anexo
extra = 2
readonly_fields = ['data_pub',]
class OcorrenciaChangeList(ChangeList):
request = None
def __init__(self, request, model, list_display, list_display_links, list_filter, date_hierarchy, search_fields,
list_select_related, list_per_page, list_editable, model_admin):
self.request = request
super(OcorrenciaChangeList, self).__init__(request, model, list_display, list_display_links, list_filter,
date_hierarchy, search_fields, list_select_related, list_per_page,
list_editable, model_admin)
def get_query_set(self):
tmp_params = self.params.copy()
grupo = None
if 'grupo' in self.params:
grupo = self.params['grupo']
del self.params['grupo']
qs = super(OcorrenciaChangeList, self).get_query_set()
self.params = tmp_params.copy()
if grupo:
servidor = Servidor.objects.get(user=self.request.user)
if grupo == 'S': # Apenas do meu setor
qs = qs.filter(setor_responsavel=servidor.servico)
elif grupo == 'M': # Apenas criados por mim
qs = qs.filter(servidor_registro=servidor)
return qs
class OcorrenciaAdmin(admin.ModelAdmin):
list_display = ('data_criacao', 'casa_legislativa', 'assunto', 'prioridade', 'status', 'data_modificacao', 'setor_responsavel',)
list_filter = ('assunto', 'status', 'prioridade', 'categoria', 'setor_responsavel', )
search_fields = ('casa_legislativa__search_text', 'assunto', 'servidor_registro__nome', )
date_hierarchy = 'data_criacao'
fields = ('casa_legislativa', 'categoria', 'assunto', 'status', 'prioridade', 'descricao', 'servidor_registro',
'setor_responsavel', 'resolucao', )
readonly_fields = ('servidor_registro', 'setor_responsavel', )
inlines = (ComentarioViewInline, ComentarioInline, AnexosInline, )
raw_id_fields = ('casa_legislativa', )
def get_changelist(self, request, **kwargs):
return OcorrenciaChangeList
def get_readonly_fields(self, request, obj=None):
fields = list(self.readonly_fields)
if obj is not None:
fields.extend(['casa_legislativa', 'categoria', 'assunto', 'status', 'descricao', ])
if obj.status in [3, 4, 5]: #Fechados
fields.append('prioridade')
return fields
def get_fieldsets(self, request, obj=None):
if obj is None:
self.fields = ('casa_legislativa', 'categoria', 'assunto', 'prioridade', 'descricao', 'resolucao', )
return super(OcorrenciaAdmin, self).get_fieldsets(request, obj)
def save_model(self, request, obj, form, change):
if not change:
obj.servidor_registro = Servidor.objects.get(user=request.user)
obj.setor_responsavel = obj.categoria.setor_responsavel
obj.save()
def save_formset(self, request, form, formset, change):
servidor = Servidor.objects.get(user=request.user)
instances = formset.save(commit=False)
for instance in instances:
instance.usuario = servidor
instance.save()
if instance.encaminhar_setor and (instance.encaminhar_setor != instance.ocorrencia.setor_responsavel):
instance.ocorrencia.setor_responsavel = instance.encaminhar_setor
instance.ocorrencia.save()
if instance.novo_status and (instance.novo_status != instance.ocorrencia.status):
instance.ocorrencia.status = instance.novo_status
instance.ocorrencia.save()
formset.save_m2m()
admin.site.register(Ocorrencia, OcorrenciaAdmin)
admin.site.register(Categoria)

79
sigi/apps/ocorrencias/models.py

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
from django.db import models
from datetime import datetime
from django.db import models
from sigi.apps.utils import SearchField
#from eav.models import BaseChoice, BaseEntity, BaseSchema, BaseAttribute
class Categoria(models.Model):
nome= models.CharField(max_length=50)
descricao = models.TextField('descrição', blank=True, null=True)
setor_responsavel = models.ForeignKey('servidores.Servico', verbose_name=u"Setor responsável")
class Meta:
verbose_name, verbose_name_plural = u'Categoria', u'Categorias'
def __unicode__(self):
return self.nome
class Ocorrencia(models.Model):
STATUS_CHOICES = (
(1, u'Aberto'),
(2, u'Reaberto'),
(3, u'Resolvido'),
(4, u'Fechado'),
(5, u'Duplicado'),
)
PRIORITY_CHOICES = (
(1, u'Altíssimo'),
(2, u'Alto'),
(3, u'Normal'),
(4, u'Baixo'),
(5, u'Baixíssimo'),
)
casa_legislativa = models.ForeignKey('casas.CasaLegislativa', verbose_name=u'Casa Legislativa')
casa_legislativa.convenio_uf_filter = True
casa_legislativa.convenio_cl_tipo_filter = True
data_criacao = models.DateField(u'Data de criação', null=True, blank=True, auto_now_add=True)
data_modificacao = models.DateField(u'Data de modificação', null=True, blank=True, auto_now=True)
categoria = models.ForeignKey(Categoria, verbose_name=u'Categoria')
assunto = models.CharField(u'Assunto', max_length=200)
assunto.grupo_filter = True
status = models.IntegerField(u'Status', choices=STATUS_CHOICES, default=1,)
status.multichoice_filter = True
prioridade = models.IntegerField(u'Prioridade', choices=PRIORITY_CHOICES, default=3, )
descricao = models.TextField(u'descrição', blank=True,)
resolucao = models.TextField(u'resolução', blank=True,)
servidor_registro = models.ForeignKey('servidores.Servidor', verbose_name=u"Servidor que registrou a ocorrência")
setor_responsavel = models.ForeignKey('servidores.Servico', verbose_name=u"Setor responsável")
class Meta:
verbose_name, verbose_name_plural = u'ocorrência', u'ocorrências'
ordering = ['prioridade', 'data_modificacao', 'data_criacao', ]
def __unicode__(self):
return u"%(casa_legislativa)s: %(assunto)s" % {'assunto': self.assunto, 'casa_legislativa': self.casa_legislativa}
class Comentario(models.Model):
ocorrencia = models.ForeignKey(Ocorrencia, verbose_name=u'Ocorrência')
data_criacao = models.DateTimeField(u'Data de criação', null=True, blank=True, auto_now_add=True)
descricao = models.TextField(u'Descrição', blank=True, null=True)
usuario = models.ForeignKey('servidores.Servidor', verbose_name=u'Usuário')
novo_status = models.IntegerField(u'Novo status', choices=Ocorrencia.STATUS_CHOICES, blank=True, null=True)
encaminhar_setor = models.ForeignKey('servidores.Servico', verbose_name=u'Encaminhar para setor', blank=True, null=True)
class Anexo(models.Model):
ocorrencia = models.ForeignKey(Ocorrencia, verbose_name=u'ocorrência')
arquivo = models.FileField(u'Arquivo anexado', upload_to='apps/ocorrencia/anexo/arquivo',)
descricao = models.CharField(u'descrição do anexo', max_length='70')
data_pub = models.DateTimeField( u'data da publicação do anexo', null=True, blank=True, auto_now_add=True)
class Meta:
ordering = ('-data_pub',)
verbose_name, verbose_name_plural = u'Anexo', u'Anexos'
def __unicode__(self):
return u"%(arquivo_name)s: %(descricao)s" % {'arquivo_name': self.arquivo.name, 'descricao': self.descricao}

0
sigi/apps/parlamentares/__init__.py

75
sigi/apps/parlamentares/admin.py

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.contrib.contenttypes import generic
from django.http import HttpResponse, HttpResponseRedirect
from sigi.apps.contatos.models import Telefone
from sigi.apps.parlamentares.models import Partido, Parlamentar, Mandato
from sigi.apps.parlamentares.views import adicionar_parlamentar_carrinho
class MandatosInline(admin.TabularInline):
model = Mandato
extra = 1
raw_id_fields = ('legislatura', 'partido')
class TelefonesInline(generic.GenericTabularInline):
model = Telefone
extra = 2
class PartidoAdmin(admin.ModelAdmin):
list_display = ('nome', 'sigla')
list_display_links = ('nome', 'sigla')
search_fields = ('nome', 'sigla')
class ParlamentarAdmin(admin.ModelAdmin):
inlines = (TelefonesInline, MandatosInline)
list_display = ('nome_completo', 'nome_parlamentar', 'sexo')
list_display_links = ('nome_completo', 'nome_parlamentar')
list_filter = ('nome_completo', 'nome_parlamentar')
actions = ['adiciona_parlamentar',]
fieldsets = (
(None, {
'fields': ('nome_completo', 'nome_parlamentar', 'sexo'),
}),
# ('Endereço', {
# 'fields': ('logradouro', 'bairro', 'municipio', 'cep'),
# }),
('Outras informações', {
'fields': ('data_nascimento', 'email', 'pagina_web', 'foto'),
}),
)
radio_fields = {'sexo': admin.VERTICAL}
# raw_id_fields = ('municipio',)
search_fields = ('nome_completo', 'nome_parlamentar', 'email',
'pagina_web',)
def adiciona_parlamentar(self, request, queryset):
if request.session.has_key('carrinho_parlametar'):
q1 = len(request.session['carrinho_parlamentar'])
else:
q1 = 0
adicionar_parlamentar_carrinho(request,queryset=queryset)
q2 = len(request.session['carrinho_parlamentar'])
quant = q2 - q1
if quant:
self.message_user(request,"%s Parlamentares adicionados no carrinho" % (quant) )
else:
self.message_user(request,"Os parlamentares selecionadas já foram adicionadas anteriormente" )
return HttpResponseRedirect('.')
adiciona_parlamentar.short_description = u"Armazenar parlamentar no carrinho para exportar"
class MandatoAdmin(admin.ModelAdmin):
list_display = ('parlamentar', 'legislatura', 'partido',
'inicio_mandato', 'fim_mandato', 'is_afastado')
list_filter = ('is_afastado', 'partido')
search_fields = ('legislatura__numero', 'parlamentar__nome_completo',
'parlamentar__nome_parlamentar', 'partido__nome',
'partido__sigla')
raw_id_fields = ('parlamentar', 'legislatura', 'partido')
# radio_fields = {'suplencia': admin.VERTICAL}
admin.site.register(Partido, PartidoAdmin)
admin.site.register(Parlamentar, ParlamentarAdmin)
admin.site.register(Mandato, MandatoAdmin)

218
sigi/apps/parlamentares/fixtures/initial_data.json

@ -0,0 +1,218 @@
[
{
"pk": 5,
"model": "parlamentares.partido",
"fields": {
"sigla": "DEM",
"nome": "Democratas"
}
},
{
"pk": 19,
"model": "parlamentares.partido",
"fields": {
"sigla": "PCB",
"nome": "Partido Comunista Brasileiro"
}
},
{
"pk": 6,
"model": "parlamentares.partido",
"fields": {
"sigla": "PCdoB",
"nome": "Partido Comunista do Brasil"
}
},
{
"pk": 4,
"model": "parlamentares.partido",
"fields": {
"sigla": "PDT",
"nome": "Partido Democr\u00e1tico Trabalhista"
}
},
{
"pk": 20,
"model": "parlamentares.partido",
"fields": {
"sigla": "PHS",
"nome": "Partido Humanista da Solidariedade"
}
},
{
"pk": 13,
"model": "parlamentares.partido",
"fields": {
"sigla": "PPS",
"nome": "Partido Popular Socialista"
}
},
{
"pk": 17,
"model": "parlamentares.partido",
"fields": {
"sigla": "PP",
"nome": "Partido Progressista"
}
},
{
"pk": 16,
"model": "parlamentares.partido",
"fields": {
"sigla": "PRTB",
"nome": "Partido Renovador Trabalhista Brasileiro"
}
},
{
"pk": 25,
"model": "parlamentares.partido",
"fields": {
"sigla": "PRB",
"nome": "Partido Republicano Brasileiro"
}
},
{
"pk": 12,
"model": "parlamentares.partido",
"fields": {
"sigla": "PRP",
"nome": "Partido Republicano Progressista"
}
},
{
"pk": 10,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSC",
"nome": "Partido Social Crist\u00e3o"
}
},
{
"pk": 21,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSDC",
"nome": "Partido Social Democrata Crist\u00e3o"
}
},
{
"pk": 24,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSL",
"nome": "Partido Social Liberal"
}
},
{
"pk": 26,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSOL",
"nome": "Partido Socialismo e Liberdade"
}
},
{
"pk": 7,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSB",
"nome": "Partido Socialista Brasileiro"
}
},
{
"pk": 18,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSTU",
"nome": "Partido Socialista dos Trabalhadores Unificado"
}
},
{
"pk": 3,
"model": "parlamentares.partido",
"fields": {
"sigla": "PTB",
"nome": "Partido Trabalhista Brasileiro"
}
},
{
"pk": 9,
"model": "parlamentares.partido",
"fields": {
"sigla": "PTC",
"nome": "Partido Trabalhista Crist\u00e3o"
}
},
{
"pk": 23,
"model": "parlamentares.partido",
"fields": {
"sigla": "PTN",
"nome": "Partido Trabalhista Nacional"
}
},
{
"pk": 15,
"model": "parlamentares.partido",
"fields": {
"sigla": "PTdoB",
"nome": "Partido Trabalhista do Brasil"
}
},
{
"pk": 14,
"model": "parlamentares.partido",
"fields": {
"sigla": "PV",
"nome": "Partido Verde"
}
},
{
"pk": 22,
"model": "parlamentares.partido",
"fields": {
"sigla": "PCO",
"nome": "Partido da Causa Oper\u00e1ria"
}
},
{
"pk": 11,
"model": "parlamentares.partido",
"fields": {
"sigla": "PMN",
"nome": "Partido da Mobiliza\u00e7\u00e3o Nacional"
}
},
{
"pk": 27,
"model": "parlamentares.partido",
"fields": {
"sigla": "PR",
"nome": "Partido da Rep\u00fablica"
}
},
{
"pk": 8,
"model": "parlamentares.partido",
"fields": {
"sigla": "PSDB",
"nome": "Partido da Social Democracia Brasileira"
}
},
{
"pk": 2,
"model": "parlamentares.partido",
"fields": {
"sigla": "PMDB",
"nome": "Partido do Movimento Democr\u00e1tico Brasileiro"
}
},
{
"pk": 1,
"model": "parlamentares.partido",
"fields": {
"sigla": "PT",
"nome": "Partido dos Trabalhadores"
}
}
]

81
sigi/apps/parlamentares/models.py

@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.contenttypes import generic
class Partido(models.Model):
nome = models.CharField(max_length=50)
sigla = models.CharField(max_length=10)
class Meta:
ordering = ('nome',)
def __unicode__(self):
return '%s (%s)' % (unicode(self.nome), unicode(self.sigla))
class Parlamentar(models.Model):
SEXO_CHOICES = (
('M', 'Masculino'),
('F', 'Feminino'),
)
nome_completo = models.CharField(max_length=128)
nome_completo.alphabetic_filter = True
nome_parlamentar = models.CharField(max_length=35, blank=True)
foto = models.ImageField(
upload_to='fotos/parlamentares',
width_field='foto_largura',
height_field='foto_altura',
blank=True
)
foto_largura = models.SmallIntegerField(editable=False, null=True)
foto_altura = models.SmallIntegerField(editable=False, null=True)
sexo = models.CharField(
max_length=1,
choices=SEXO_CHOICES,
)
data_nascimento = models.DateField(
'data de nascimento',
blank=True,
null=True,
)
email = models.EmailField('e-mail', blank=True)
pagina_web = models.URLField(u'página web',
blank=True)
class Meta:
ordering = ('nome_completo',)
verbose_name_plural = 'parlamentares'
def __unicode__(self):
if self.nome_parlamentar:
return self.nome_parlamentar
return self.nome_completo
class Mandato(models.Model):
SUPLENCIA_CHOICES = (
('T', 'Titular'),
('S', 'Suplente'),
)
parlamentar = models.ForeignKey(Parlamentar)
legislatura = models.ForeignKey('mesas.Legislatura')
partido = models.ForeignKey(Partido)
cargo = models.ForeignKey('mesas.Cargo')
inicio_mandato = models.DateField(u'início de mandato')
fim_mandato = models.DateField('fim de mandato')
is_afastado = models.BooleanField(
'afastado',
default=False,
help_text=u'Marque caso parlamentar não esteja ativo.'
)
# suplencia = models.CharField(
# u'suplência',
# max_length=1,
# choices=SUPLENCIA_CHOICES,
# )
def __unicode__(self):
return str(self.id)

539
sigi/apps/parlamentares/reports.py

@ -0,0 +1,539 @@
# -*- coding: utf-8 -*-
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib.enums import TA_CENTER, TA_RIGHT
from geraldo import Report, DetailBand, Label, ObjectValue, ManyElements, \
ReportGroup, ReportBand, landscape, SubReport, BAND_WIDTH,SystemField
from sigi.apps.relatorios.reports import ReportDefault
from geraldo.graphics import Image
def string_to_cm(texto):
tamanho = 0
minEspeciais = {
'f':0.1,
'i':0.05,
'j':0.05,
'l':0.05,
'm':0.2,
'r':0.1,
't':0.15,
}
maiuEspeciais = {
'I':0.05,
'J':0.15,
'L':0.15,
'P':0.15,
}
for c in texto:
if c > 'a' and c<'z':
if c in minEspeciais:
tamanho += minEspeciais[c]
else:
tamanho += 0.17
else:
if c in maiuEspeciais:
tamanho += maiuEspeciais[c]
else:
tamanho += 0.2
return tamanho
class ParlamentaresLabels(Report):
"""
Usage example::
>>> from geraldo.generators import PDFGenerator
>>> queryset = CasaLegislativa.objects.filter(municipio__uf__sigla='MG')
>>> report = LabelsReport(queryset)
>>> report.generate_by(PDFGenerator, filename='./inline-detail-report.pdf')
"""
formato = ''
y = 2
largura_etiqueta = 7
altura_etiqueta = 3.3
tamanho_fonte = 6.4
altura_dados = 0.3 #logradouro, bairro, municipio, cep
delta = start = 0.5
def __init__(self, queryset, formato):
super(ParlamentaresLabels, self).__init__(queryset=queryset)
self.formato = formato
self.page_size = A4
if formato == '3x9_etiqueta':
self.margin_top = 0.0*cm
self.margin_bottom = 0.0*cm
self.margin_left = -1*cm
self.margin_right = 0.0*cm
self.delta = 0.4 # espaçamento entre as "strings/linhas" da etiqueta
self.start = 0.2 # valor entre a margin top e a etiqueta
else:
self.margin_top = 0.8*cm
self.margin_bottom = 0.8*cm
self.margin_left = 0.4*cm
self.margin_right = 0.4*cm
self.largura_etiqueta = 9.9
self.altura_etiqueta = 5.6
self.tamanho_fonte = 11
self.altura_dados = 0.5
self.y = 0.5
my_elements = [
Label(
text=u'A Sua Excelência o(a) Senhor(a)',
top=(self.start + self.delta)*cm, left=self.y*cm, width=(self.largura_etiqueta-self.y)*cm,
),
ObjectValue(
attribute_name='nome_completo',
top=(self.start + 2*self.delta)*cm, left=self.y*cm, width=(self.largura_etiqueta-self.y)*cm,
get_value=lambda instance:
instance.nome_completo or ""
),
ObjectValue(
attribute_name='logradouro',
top=(self.start + 3*self.delta)*cm, left=self.y*cm, width=(self.largura_etiqueta-self.y)*cm,
get_value=lambda instance:
logradouro_parlamentar(instance)
),
ObjectValue(
attribute_name='bairro',
top=(self.start + 4*self.delta)*cm, left=self.y*cm, width=(self.largura_etiqueta-self.y)*cm,
get_value=lambda instance:
bairro_parlamentar(instance)
),
ObjectValue(
attribute_name='municipio',
top=(self.start + 5*self.delta)*cm, left=self.y*cm, width=(self.largura_etiqueta-self.y)*cm,
get_value=lambda instance:
municipio_parlamentar(instance)
),
ObjectValue(
attribute_name='cep',
top=(self.start + 6*self.delta)*cm, left=self.y*cm, width=(self.largura_etiqueta-self.y)*cm,
get_value=lambda instance:
cep_parlamentar(instance)
),
]
self.band_detail = DetailBand(width=(self.largura_etiqueta)*cm, height=(self.altura_etiqueta)*cm, margin_left = 0, margin_top = 0, margin_bottom=0.0*cm, margin_right = 0, elements=my_elements,display_inline=True, default_style={'fontName': 'Helvetica', 'fontSize': self.tamanho_fonte})
def logradouro_parlamentar(instance):
try:
return instance.mandato_set.latest('inicio_mandato').legislatura.casa_legislativa.logradouro
except:
return u"<<PARLAMENTAR SEM MANDATO - impossivel definir endereço>>"
def bairro_parlamentar(instance):
try:
return instance.mandato_set.latest('inicio_mandato').legislatura.casa_legislativa.bairro
except:
return u"<<PARLAMENTAR SEM MANDATO - impossivel definir endereço>>"
def municipio_parlamentar(instance):
try:
return instance.mandato_set.latest('inicio_mandato').legislatura.casa_legislativa.municipio
except:
return u"<<PARLAMENTAR SEM MANDATO - impossivel definir endereço>>"
def cep_parlamentar(instance):
try:
return instance.mandato_set.latest('inicio_mandato').legislatura.casa_legislativa.cep
except:
return u"<<PARLAMENTAR SEM MANDATO - impossivel definir endereço>>"
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= ReportDefault.band_page_header.BASE_DIR + '/media/images/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= ReportDefault.band_page_header.BASE_DIR + '/media/images/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 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=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=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': 'Sul','SD': 'Sudeste','CO': 'Centro-Oeste','NE': 'Nordeste','NO': 'Norte',}
[instance.municipio.uf.regiao]
),
Label(
text=u"U.F.: ",
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=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=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=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=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=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=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=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':'Fixo','M':u'Móvel','X':'Fax','I':'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 != 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 != 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 != 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 != None else '-'
),
],
#borders = {'all':True},
),
)
]

78
sigi/apps/parlamentares/templates/parlamentares/carrinho.html

@ -0,0 +1,78 @@
{% extends "admin/carrinho.html" %}
{% load adminmedia admin_list i18n %}
{% block extrastyle %}
{{ block.super }}
{% include "admin/tabs_style.html" %}
{% endblock %}
{% block title %}Parlamentares no Carrinho | SIGI{% endblock %}
{% block content_title %}<h1>Parlamentares no Carrinho</h1>{% endblock %}
{% block mensagem%}
<ul class="messagelist">
{%if carIsEmpty%}
<li class="warning">O carrinho está vazio, sendo assim todas as casas entram na lista para exportação de acordo com os filtros aplicados.</li>
{%else%}
<li>{{paginas.paginator.count}}Parlamentares no carrinho.</li>
{%endif%}
</ul>
{% endblock %}
{% block action %}deleta_itens_carrinho{% endblock %}
{% block tabela %}
<table>
<thead>
<tr>
{%if not carIsEmpty%}
<th class="sorted ascending"><!-- <input type="checkbox" id="action-toggle" style="display: inline;">-->
</th>
{% endif %}
<th class="sorted ascending">Nome</th>
<th class="sorted ascending">Nome parlamentar</th>
<th class="sorted ascending">Sexo</th>
</tr>
</thead>
<tbody>
{% for parlamentar in paginas.object_list %}
<tr class="{% cycle 'row1' 'row2' %}">
{%if not carIsEmpty%}
<th><input type="checkbox" name="_selected_action"
value="{{parlamentar.id}}" class="action-select" /></th>
{% endif %}
<td style="text-align: left;">{{parlamentar.nome_completo}}</td>
<td>{{parlamentar.nome_parlamentar}}</td>
<td>{{parlamentar.get_sexo_display}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block botoes %}
<div id="tabs">
<ul>
<li><a href="#tabs-1">Etiqueta</a></li>
</ul>
<div id="tabs-1">
<form action="../labels/{{query_str}}" method="post">{% csrf_token %}
<fieldset><legend>Formato da Etiqueta</legend>
<ul class="formato_etiqueta">
<li><input type="radio" name="tamanho_etiqueta"
value="2x5_etiqueta"><label>2x5</label></li>
<li><input type="radio" name="tamanho_etiqueta"
value="3x9_etiqueta" checked="checked"><label>3x9</label></li>
</ul>
</fieldset>
<ul class="botoes">
<li><input type="submit" value="Gerar Etiqueta" /></li>
</ul>
</form>
</div>
{% endblock %}

14
sigi/apps/parlamentares/templates/parlamentares/change_form.html

@ -0,0 +1,14 @@
{% extends "admin/change_form.html" %}
{% load i18n reporting_tags %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
<li><a href="report_complete/">Relatório</a></li>
<li><a href="labels/">Etiqueta</a></li>
<li><a href="labels_sem_presidente/">Etiqueta sem presidente</a></li>
<li><a href="history/" class="historylink">{% trans "History" %}</a></li>
{% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
</ul>
{% endif %}{% endif %}
{% endblock %}

9
sigi/apps/parlamentares/templates/parlamentares/change_list.html

@ -0,0 +1,9 @@
{% extends "admin/change_list.html" %}
{% load adminmedia admin_list i18n reporting_tags %}
{% block object-tools %}
<ul class="object-tools">
<li><a href="#">Casas sem Processo de Convênio</a></li>
</ul>
{% endblock %}

149
sigi/apps/parlamentares/views.py

@ -0,0 +1,149 @@
# coding: utf-8
import datetime
import csv
import ho.pisa as pisa
from django.template import Context, loader
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.conf import settings
from django.shortcuts import render_to_response, get_list_or_404
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_protect
from django.template import RequestContext
from sigi.apps.casas.models import CasaLegislativa
from sigi.apps.parlamentares.models import Parlamentar
from sigi.apps.parlamentares.reports import ParlamentaresLabels
from geraldo.generators import PDFGenerator
def adicionar_parlamentar_carrinho(request,queryset=None,id=None):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if not request.session.has_key('carrinho_parlametar'):
request.session['carrinho_parlamentar'] = ids_selecionados
else:
lista = request.session['carrinho_parlamentar']
# Verifica se id já não está adicionado
for id in ids_selecionados:
if not id in lista:
lista.append(id)
request.session['carrinho_parlamentar'] = lista
@csrf_protect
def visualizar_carrinho(request):
qs = carrinhoOrGet_for_qs(request)
paginator = Paginator(qs, 100)
# Make sure page request is an int. If not, deliver first page.
# Esteja certo de que o `page request` é um inteiro. Se não, mostre a primeira página.
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
# Se o page request (9999) está fora da lista, mostre a última página.
try:
paginas = paginator.page(page)
except (EmptyPage, InvalidPage):
paginas = paginator.page(paginator.num_pages)
carrinhoIsEmpty = not(request.session.has_key('carrinho_parlamentares'))
return render_to_response('parlamentares/carrinho.html',
{"ADMIN_MEDIA_PREFIX":settings.ADMIN_MEDIA_PREFIX,
'MEDIA_URL':settings.MEDIA_URL,
'carIsEmpty':carrinhoIsEmpty,
'paginas':paginas,
'query_str':'?'+request.META['QUERY_STRING']},
context_instance=RequestContext(request))
def carrinhoOrGet_for_qs(request):
"""
Verifica se existe parlamentares na sessão se não verifica get e retorna qs correspondente.
"""
if request.session.has_key('carrinho_parlamentar'):
ids = request.session['carrinho_parlamentar']
qs = Parlamentar.objects.filter(pk__in=ids)
else:
qs = Parlamentar.objects.all()
if request.GET:
qs = get_for_qs(request.GET,qs)
return qs
def query_ordena(qs,o,ot):
list_display = ('nome_completo',)
aux = list_display[(int(o)-1)]
if ot =='asc':
qs = qs.order_by(aux)
else:
qs = qs.order_by("-"+aux)
return qs
def get_for_qs(get,qs):
"""
Verifica atributos do GET e retorna queryset correspondente
"""
kwargs = {}
for k,v in get.iteritems():
if not (k == 'page' or k == 'pop' or k == 'q'):
if not k == 'o':
if k == "ot":
qs = query_ordena(qs,get["o"],get["ot"])
else:
kwargs[str(k)] = v
qs = qs.filter(**kwargs)
return qs
def deleta_itens_carrinho(request):
"""
Deleta itens selecionados do carrinho
"""
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if request.session.has_key('carrinho_parlamentar'):
lista = request.session['carrinho_parlamentar']
for item in ids_selecionados:
lista.remove(item)
if lista:
request.session['carrinho_parlamentar'] = lista
else:
del lista;
del request.session['carrinho_parlamentar']
return HttpResponseRedirect('.')
def labels_report(request, id=None, formato='3x9_etiqueta'):
""" TODO: adicionar suporte para resultado de pesquisa do admin.
"""
if request.POST:
if request.POST.has_key('tipo_etiqueta'):
tipo = request.POST['tipo_etiqueta']
if id:
qs = Parlamentar.objects.filter(pk=id)
else:
qs = carrinhoOrGet_for_qs(request)
if not qs:
return HttpResponseRedirect('../')
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=casas.pdf'
report = ParlamentaresLabels(queryset=qs, formato=formato)
report.generate_by(PDFGenerator, filename=response)
return response

0
sigi/apps/relatorios/__init__.py

3
sigi/apps/relatorios/models.py

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

76
sigi/apps/relatorios/reports.py

@ -0,0 +1,76 @@
#-*- coding:utf-8 -*-
import os
from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label, \
landscape,SystemField, BAND_WIDTH,ReportGroup, \
FIELD_ACTION_SUM, FIELD_ACTION_COUNT, Line
from geraldo.graphics import Image
from reportlab.lib.units import cm
from reportlab.lib.pagesizes import A4
from reportlab.lib.enums import TA_CENTER, TA_RIGHT
from reportlab.lib.colors import navy, red
class ReportDefault(Report):
#__metaclass__ = ABCMeta
title = u'Relatório'
author = u'Interlegis'
print_if_empty = True
page_size = A4
class band_page_header(ReportBand):
height = 4.2*cm
label_top = 3.7*cm
default_style = {'fontName': 'Helvetica', 'fontSize':9}
BASE_DIR = os.path.abspath(os.path.dirname(__file__) + '../../../../')
#BASE_DIR = os.path.abspath(os.getcwd() + '../..')
elements = [
Image(filename= BASE_DIR + '/media/images/logo-interlegis.jpg',
left=15.5*cm,right=1*cm,top=0.1*cm,bottom=1*cm,
width=4.2*cm,height=3*cm,
),
Image(filename= BASE_DIR + '/media/images/logo-senado.png',
left=1*cm,right=1*cm,top=0.1*cm,bottom=1*cm,
width=3*cm,height=3*cm,
),
Label(text="SENADO FEDERAL",top=1*cm,left=0,width=BAND_WIDTH,
style={'fontName': 'Helvetica-Bold','fontSize':14, 'alignment': TA_CENTER}
),
Label(text="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}
),
]
borders = {'bottom': True}
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),
SystemField(expression=u'Página %(page_number)d de %(page_count)d', top=0.3*cm,
width=BAND_WIDTH, style={'alignment': TA_RIGHT}
),
]
#borders = {'top': True}
class band_detail(DetailBand):
height = 0.5*cm
default_style = {'fontName': 'Helvetica', 'fontSize': 8}
auto_expand_height = True
class band_summary(ReportBand):
height = 0.8*cm
elements = [
Label(text="Total:", top=0.1*cm, left=0),
ObjectValue(attribute_name='id', top=0.1*cm, left=1*cm,\
action=FIELD_ACTION_COUNT, display_format='%s'),
]
borders = {'top': Line(stroke_color=navy, stroke_width=2)}

23
sigi/apps/relatorios/tests.py

@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

1
sigi/apps/relatorios/views.py

@ -0,0 +1 @@
# Create your views here.

0
sigi/apps/servicos/__init__.py

214
sigi/apps/servicos/admin.py

@ -0,0 +1,214 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from sigi.apps.servicos.models import Servico, LogServico, CasaAtendida, TipoServico
#from sigi.apps.casas.models import Funcionario
from sigi.apps.casas.admin import FuncionariosInline
from django.http import Http404, HttpResponseRedirect
from django.forms.models import ModelForm
from django.utils.encoding import force_unicode
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from apps.casas.models import CasaLegislativa
#---------------- inlines ---------------------
class LogServicoInline(admin.StackedInline):
model = LogServico
Fieldset = ((None, {'fields': (('data', 'descricao'), 'log')}))
extra = 1
# --------------- forms -----------------------
class ServicoFormAdmin(ModelForm):
class Meta:
model = Servico
def __init__(self, *args, **kwargs):
super(ServicoFormAdmin, self).__init__(*args, **kwargs)
self.fields['contato_tecnico'].choices = ()
self.fields['contato_administrativo'].choices = ()
if self.instance.casa_legislativa_id:
id_casa = self.instance.casa_legislativa_id
elif kwargs.has_key('initial') and kwargs['initial'].has_key('id_casa'):
id_casa = kwargs['initial']['id_casa']
self.instance.casa_legislativa_id = id_casa
else:
id_casa = None
if id_casa:
casa = CasaAtendida.objects.get(pk=id_casa)
contatos = [(f.id, unicode(f)) for f in casa.funcionario_set.all()]
self.fields['contato_tecnico'].choices = contatos
self.fields['contato_administrativo'].choices = contatos
#---------------- admins ----------------------
class TipoServicoAdmin(admin.ModelAdmin):
list_display = ('id', 'sigla', 'nome', 'qtde_casas_atendidas', )
ordering = ['id']
class ServicoAdmin(admin.ModelAdmin):
form = ServicoFormAdmin
actions = ['calcular_data_uso',]
list_display = ('casa_legislativa', 'get_codigo_interlegis', 'get_uf', 'tipo_servico', 'hospedagem_interlegis',
'data_ativacao', 'data_desativacao', 'getUrl', 'data_ultimo_uso', 'get_link_erro')
fieldsets = (( None, {
'fields': ('casa_legislativa', 'data_ativacao',)
}),
( 'Serviço', {
'fields': ('tipo_servico', ('url', 'hospedagem_interlegis'), ('nome_servidor', 'porta_servico', 'senha_inicial'),)
}),
( 'Contatos', {
'fields': ('contato_tecnico', 'contato_administrativo',)
}),
( 'Alterações', {
'fields': ('data_alteracao', 'data_desativacao', 'motivo_desativacao',)
}))
readonly_fields = ('casa_legislativa', 'data_ativacao', 'data_alteracao')
list_filter = ('tipo_servico', 'hospedagem_interlegis', 'data_ultimo_uso', 'casa_legislativa', )
list_display_links = []
ordering = ('casa_legislativa__municipio__uf', 'casa_legislativa', 'tipo_servico',)
inlines = (LogServicoInline,)
search_fields = ('casa_legislativa__search_text',)
def get_codigo_interlegis(self, obj):
return obj.casa_legislativa.codigo_interlegis
get_codigo_interlegis.short_description = u'Código Interlegis'
get_codigo_interlegis.admin_order_field = 'casa_legislativa__codigo_interlegis'
def get_uf(self, obj):
return u'%s' % (obj.casa_legislativa.municipio.uf)
get_uf.short_description = 'UF'
get_uf.admin_order_field = 'casa_legislativa__municipio__uf'
def getUrl(self, obj):
return u'<a href="%s" target="_blank">%s</a>' % (obj.url, obj.url)
getUrl.short_description = 'Url'
getUrl.allow_tags = True
def get_link_erro(self, obj):
if not obj.erro_atualizacao:
return u""
url = obj.url
if url[-1] != '/':
url += '/'
url += obj.tipo_servico.string_pesquisa
return u'<a href="%s" target="_blank">%s</a>' % (url, obj.erro_atualizacao)
get_link_erro.allow_tags = True
get_link_erro.short_description = u"Erro na atualização"
get_link_erro.admin_order_field = 'erro_atualizacao'
def calcular_data_uso(self, request, queryset):
for servico in queryset:
servico.atualiza_data_uso()
self.message_user(request, "Atualização concluída. Os sites que não responderam foram deixados com a data em branco" )
return HttpResponseRedirect('.')
calcular_data_uso.short_description = u"Atualizar a data do último uso do(s) serviço(s)"
def get_actions(self, request):
from django.utils.datastructures import SortedDict
actions = [self.get_action(action) for action in self.actions]
actions = filter(None, actions)
actions.sort(lambda a,b: cmp(a[2].lower(), b[2].lower()))
actions = SortedDict([ (name, (func, name, desc)) for func, name, desc in actions ])
return actions
def lookup_allowed(self, lookup, value):
return super(ServicoAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact']
def add_view(self, request, form_url='', extra_context=None):
id_casa = request.GET.get('id_casa', None)
if not id_casa:
raise Http404
return super(ServicoAdmin, self).add_view(request, form_url, extra_context=extra_context)
def response_add(self, request, obj):
opts = obj._meta
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
if request.POST.has_key("_addanother"):
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect(request.path + '?id_casa=%s' % (obj.casa_legislativa.id,))
elif request.POST.has_key("_save"):
self.message_user(request, msg)
return HttpResponseRedirect(reverse('admin:servicos_casaatendida_change', args=[obj.casa_legislativa.id]))
return super(ServicoAdmin, self).response_add(request, obj)
def response_change(self, request, obj):
opts = obj._meta
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
if request.POST.has_key("_addanother"):
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect("../add/?id_casa=%s" % (obj.casa_legislativa.id,))
elif request.POST.has_key("_save"):
self.message_user(request, msg)
return HttpResponseRedirect(reverse('admin:servicos_casaatendida_change', args=[obj.casa_legislativa.id]))
return super(ServicoAdmin, self).response_change(request, obj)
def save_form(self, request, form, change):
obj = super( ServicoAdmin, self).save_form(request, form, change)
if not change:
id_casa = request.GET.get('id_casa', None)
if not id_casa:
raise Http404
obj.casa_legislativa = CasaAtendida.objects.get(pk=id_casa)
return obj
class ContatosInline(FuncionariosInline):
can_delete = False # Equipe do SEIT não pode excluir pessoas de contato
class CasaAtendidaAdmin(admin.ModelAdmin):
actions = None
list_display = ('codigo_interlegis', 'nome', 'get_servicos',)
ordering = ['nome']
fieldsets = (
('Casa legislativa', {
'fields': (('codigo_interlegis', 'nome'), ('logradouro', 'bairro', 'municipio', 'cep'), ('email', 'pagina_web'))
})
,)
readonly_fields = ('nome', 'logradouro', 'bairro', 'municipio', 'cep')
inlines = (ContatosInline,)
list_filter = ('tipo', 'codigo_interlegis', 'municipio', )
search_fields = ('search_text','cnpj', 'bairro', 'logradouro',
'cep', 'municipio__nome', 'municipio__uf__nome',
'municipio__codigo_ibge', 'pagina_web', 'observacoes')
def get_servicos(self, obj):
result = []
for servico in obj.servico_set.all():
result.append(u"%s (%s). Contato: %s" % (servico.tipo_servico.nome, 'ativo' if servico.data_desativacao is None
else 'Desativado', servico.contato_administrativo.nome))
return "<ul><li>" + "</li><li>".join(result) + "</li></ul>"
get_servicos.allow_tags = True
get_servicos.short_description = u"Serviços"
def lookup_allowed(self, lookup, value):
return super(CasaAtendidaAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['municipio__uf__codigo_ibge__exact', 'servico__tipo_servico__id__exact', ]
def change_view(self, request, object_id, extra_context=None):
# Se a Casa ainda não é atendida, gerar o código interlegis para ela
# Assim ela passa a ser uma casa atendida
casa = CasaLegislativa.objects.get(id=object_id)
if casa.codigo_interlegis == '':
casa.gerarCodigoInterlegis()
return super(CasaAtendidaAdmin, self).change_view(request, object_id, extra_context=extra_context)
def has_add_permission(self, request):
return False # Nunca é permitido inserir uma nova Casa Legislativa por aqui
def has_delete_permission(self, request, obj=None):
return False # Nunca deletar casas por aqui

1
sigi/apps/servicos/fixtures/initial_data.json

@ -0,0 +1 @@
[{"pk": 1, "model": "servicos.tiposervico", "fields": {"template_email_altera": "Seu Portal Modelo foi alterado com sucesso. O endere\u00e7o de acesso \u00e9 {url} e a senha \u00e9 {senha}. Altere sua senha no primeiro acesso.", "sigla": "PM", "template_email_ativa": "Seu Portal Modelo foi ativado com sucesso. O endere\u00e7o de acesso \u00e9 {url} e a senha inicial \u00e9 {senha}. Altere sua senha no primeiro acesso.", "template_email_desativa": "Seu Portal Modelo foi desativado com sucesso. O endere\u00e7o de acesso era {url}.\r\nO motivo do cancelamento foi: {motivo}", "nome": "Portal Modelo"}}, {"pk": 2, "model": "servicos.tiposervico", "fields": {"template_email_altera": "Seu SAPL foi alterado com sucesso. O endere\u00e7o de acesso \u00e9 {url} e a senha \u00e9 {senha}. Altere sua senha no primeiro acesso.", "sigla": "SAPL", "template_email_ativa": "Seu SAPL foi ativado com sucesso. O endere\u00e7o de acesso \u00e9 {url} e a senha inicial \u00e9 {senha}. Altere sua senha no primeiro acesso.", "template_email_desativa": "Seu SAPL foi desativado com sucesso. O endere\u00e7o de acesso era {url}.\r\nO motivo do cancelamento foi: {motivo}", "nome": "Hospedagem SAPL"}}, {"pk": 3, "model": "servicos.tiposervico", "fields": {"template_email_altera": "Seu SAAP foi alterado com sucesso. O endere\u00e7o de acesso \u00e9 {url} e a senha \u00e9 {senha}. Altere sua senha no primeiro acesso.", "sigla": "SAAP", "template_email_ativa": "Seu SAAP foi ativado com sucesso. O endere\u00e7o de acesso \u00e9 {url} e a senha inicial \u00e9 {senha}. Altere sua senha no primeiro acesso.", "template_email_desativa": "Seu SAAP foi desativado com sucesso. O endere\u00e7o de acesso era {url}.\r\nO motivo do cancelamento foi: {motivo}", "nome": "Hospedagem SAAP"}}]

0
sigi/apps/servicos/management/__init__.py

0
sigi/apps/servicos/management/commands/__init__.py

35
sigi/apps/servicos/management/commands/atualiza_uso_servico.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
#
# sigi.apps.servicos.management.commands.atualiza_uso_servico
#
# Copyright (c) 2012 by Interlegis
#
# GNU General Public License (GPL)
#
# 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.core.management.base import BaseCommand
from sigi.apps.servicos.models import Servico
class Command(BaseCommand):
help = u'Atualiza a informação de data de último serviço dos serviços SEIT hospedados no Interlegis.'
def handle(self, *args, **options):
verbosity = int(options['verbosity'])
queryset = Servico.objects.exclude(url="").exclude(tipo_servico__string_pesquisa="")
for obj in queryset:
obj.atualiza_data_uso()
if ((verbosity == 1) and (obj.data_ultimo_uso is None)) or (verbosity > 1):
self.stdout.write(u"%s \t %s \t %s\n" % (obj.url, obj.data_ultimo_uso, obj.erro_atualizacao))

196
sigi/apps/servicos/models.py

@ -0,0 +1,196 @@
# -*- coding: utf-8 -*-
from django.db import models
from sigi.apps.casas.models import CasaLegislativa, Funcionario
from datetime import date
from django.core.mail import send_mail
from sigi.settings import DEFAULT_FROM_EMAIL
class TipoServico(models.Model):
email_help = u'''Use:<br/>
{url} para incluir a URL do serviço,<br/>
{senha} para incluir a senha inicial do serviço'''
nome = models.CharField(u'Nome', max_length=60)
sigla = models.CharField(u'Sigla', max_length='12')
string_pesquisa = models.CharField(u'String de pesquisa', blank=True, max_length=200,
help_text=u'Sufixo para pesquisa RSS para averiguar a data da última atualização do serviço')
template_email_ativa = models.TextField(u'Template de email de ativação', help_text = email_help, blank=True)
template_email_altera = models.TextField(u'Template de email de alteração', help_text = email_help, blank=True)
template_email_desativa = models.TextField(u'Template de email de desativação', help_text = email_help + u'<br/>{motivo} para incluir o motivo da desativação do serviço', blank=True)
@property
def qtde_casas_atendidas(self):
u"""Quantidade de casas atendidas"""
return self.servico_set.filter(data_desativacao=None).count()
class Meta:
verbose_name = u'Tipo de serviço'
verbose_name_plural = u'Tipos de serviço'
def __unicode__(self):
return self.nome;
class Servico(models.Model):
casa_legislativa = models.ForeignKey(CasaLegislativa, verbose_name=u'Casa legislativa')
tipo_servico = models.ForeignKey(TipoServico, verbose_name=u'Tipo de serviço')
contato_tecnico = models.ForeignKey(Funcionario, verbose_name=u'Contato técnico', related_name='contato_tecnico')
contato_administrativo = models.ForeignKey(Funcionario, verbose_name=u'Contato administrativo', related_name='contato_administrativo')
url = models.URLField(u'URL do serviço', blank=True)
hospedagem_interlegis = models.BooleanField(u'Hospedagem no Interlegis?')
nome_servidor = models.CharField(u'Hospedado em', max_length=60, blank=True,
help_text=u'Se hospedado no Interlegis, informe o nome do servidor.<br/>Senão, informe o nome do provedor de serviços.')
porta_servico = models.PositiveSmallIntegerField(u'Porta de serviço (instância)', blank=True, null=True)
senha_inicial = models.CharField(u'Senha inicial', max_length=33, blank=True)
data_ativacao = models.DateField(u'Data de ativação', default=date.today)
data_alteracao = models.DateField(u'Data da última alteração', blank=True, null=True, auto_now=True)
data_desativacao = models.DateField(u'Data de desativação', blank=True, null=True)
motivo_desativacao = models.TextField(u'Motivo da desativação', blank=True)
data_ultimo_uso = models.DateField(u'Data da última utilização', blank=True, null=True,
help_text=u'Data em que o serviço foi utilizado pela Casa Legislativa pela última vez<br/><strong>NÃO É ATUALIZADO AUTOMATICAMENTE!</strong>')
erro_atualizacao = models.CharField(u"Erro na atualização", blank=True, max_length=200,
help_text=u"Erro ocorrido na última tentativa de atualizar a data de último acesso")
casa_legislativa.casa_uf_filter = True
def atualiza_data_uso(self):
def reset(erro=u"", comment=u""):
if self.data_ultimo_uso is None and not erro:
return
self.data_ultimo_uso = None
self.erro_atualizacao = comment + '<br/>' + erro
self.save()
return
if self.tipo_servico.string_pesquisa == "":
reset()
return
url = self.url
if not url:
reset()
return
if url[-1] != '/':
url += '/'
url += self.tipo_servico.string_pesquisa
import urllib2
from xml.dom.minidom import parseString
try: # Captura erros de conexão
try: # Tentar conxão sem proxy
req = urllib2.urlopen(url=url, timeout=5)
except: # Tentar com proxy
proxy = urllib2.ProxyHandler()
opener = urllib2.build_opener(proxy)
req = opener.open(fullurl=url, timeout=5)
except Exception as e:
reset(erro=str(e), comment=u'Não foi possível conectar com o servidor. Pode estar fora do ar ou não ser um ' +
self.tipo_servico.nome)
return
try:
rss = req.read()
except Exception as e:
reset(erro=str(e), comment=u'Não foi possível receber os dados do servidor. O acesso pode ter sido negado.')
return
try:
xml = parseString(rss)
items = xml.getElementsByTagName('item')
first_item = items[0]
date_list = first_item.getElementsByTagName('dc:date')
date_item = date_list[0]
date_text = date_item.firstChild.nodeValue
self.data_ultimo_uso = date_text[:10] # Apenas YYYY-MM-DD
self.erro_atualizacao = ""
self.save()
except Exception as e:
reset(erro=str(e), comment=u'A resposta do servidor não é compatível com %s. Pode ser outro software que está sendo usado' %
self.tipo_servico.nome)
return
def __unicode__(self):
return "%s (%s)" % (self.tipo_servico.nome, 'ativo' if self.data_desativacao is None else 'Desativado')
def save(self, *args, **kwargs):
# Reter o objeto original para verificar mudanças
if self.id is not None:
original = Servico.objects.get(id=self.id)
if self.id is None:
# Novo serviço, email de ativação
subject = u'INTERLEGIS - Ativação de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_ativa
elif self.data_desativacao is not None and original.data_desativacao is None:
# Serviço foi desativado. Email de desativação
subject = u'INTERLEGIS - Desativação de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_desativa
elif (self.tipo_servico != original.tipo_servico or
self.contato_tecnico != original.contato_tecnico or
self.url != original.url or
self.nome_servidor != original.nome_servidor or
self.senha_inicial != original.senha_inicial):
# Serviço foi alterado
subject = u'INTERLEGIS - Alteração de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_altera
else:
# Salvar o Servico
super(Servico, self).save(*args, **kwargs)
return # sem enviar email
# Prepara e envia o email
body = body.replace('{url}', self.url) \
.replace('{senha}', self.senha_inicial) \
.replace('{motivo}', self.motivo_desativacao)
# send_mail(subject, body, DEFAULT_FROM_EMAIL, \
# (self.contato_tecnico.email,), fail_silently=False)
# Salvar o Servico
super(Servico, self).save(*args, **kwargs)
return
class LogServico(models.Model):
servico = models.ForeignKey(Servico, verbose_name='Serviço')
descricao = models.CharField('Breve descrição da ação', max_length=60)
data = models.DateField('Data da ação', default=date.today)
log = models.TextField('Log da ação')
def __unicode__(self):
return "%s (%s)" % (self.descricao, self.data)
class Meta:
verbose_name = 'Log do serviço'
verbose_name_plural = 'Logs do serviço'
class CasaAtendidaManager(models.Manager):
def get_query_set(self):
qs = super(CasaAtendidaManager, self).get_query_set()
qs = qs.exclude(codigo_interlegis='')
return qs
class CasaAtendida(CasaLegislativa):
class Meta:
proxy = True
verbose_name_plural = 'Casas atendidas'
objects = CasaAtendidaManager()
class CasaManifesta(models.Model):
casa_legislativa = models.OneToOneField(CasaLegislativa)
data_manifestacao = models.DateTimeField(auto_now_add=True)
data_atualizacao = models.DateTimeField(auto_now=True)
informante = models.CharField(u'Nome do informante', max_length=100)
cargo = models.CharField(u'Cargo do informante', max_length=100)
class ServicoManifesto(models.Model):
casa_manifesta = models.ForeignKey(CasaManifesta)
servico = models.ForeignKey(TipoServico)
url = models.URLField(blank=True)
hospedagem_interlegis = models.BooleanField(u'Hospedagem no Interlegis?')
class Meta:
unique_together = ('casa_manifesta', 'servico')

122
sigi/apps/servicos/models.py~

@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
from django.db import models
from sigi.apps.casas.models import CasaLegislativa, Funcionario
from datetime import date
from django.core.mail import send_mail
from sigi.settings import DEFAULT_FROM_EMAIL
class TipoServico(models.Model):
email_help = '''Use:<br/>
{url} para incluir a URL do serviço,<br/>
{senha} para incluir a senha inicial do serviço'''
nome = models.CharField('Nome', max_length=60)
sigla = models.CharField('Sigla', max_length='12')
template_email_ativa = models.TextField('Template de email de ativação', help_text = email_help, blank=True)
template_email_altera = models.TextField('Template de email de alteração', help_text = email_help, blank=True)
template_email_desativa = models.TextField('Template de email de desativação', help_text = email_help + '<br/>{motivo} para incluir o motivo da desativação do serviço', blank=True)
@property
def qtde_casas_atendidas(self):
u"""Quantidade de casas atendidas"""
return self.servico_set.filter(data_desativacao=None).count()
class Meta:
verbose_name = 'Tipo de serviço'
verbose_name_plural = 'Tipos de serviço'
def __unicode__(self):
return self.nome;
class Servico(models.Model):
casa_legislativa = models.ForeignKey(CasaLegislativa, verbose_name='Casa legislativa')
tipo_servico = models.ForeignKey(TipoServico, verbose_name='Tipo de serviço')
contato_tecnico = models.ForeignKey(Funcionario, verbose_name='Contato técnico', related_name='contato_tecnico')
contato_administrativo = models.ForeignKey(Funcionario, verbose_name='Contato administrativo', related_name='contato_administrativo')
url = models.URLField('URL do serviço', verify_exists=False, blank=True)
hospedagem_interlegis = models.BooleanField('Hospedagem no Interlegis?')
nome_servidor = models.CharField('Hospedado em', max_length=60, blank=True, help_text='Se hospedado no Interlegis, informe o nome do servidor.<br/>Senão, informe o nome do provedor de serviços.')
porta_servico = models.PositiveSmallIntegerField('Porta de serviço (instância)', blank=True, null=True)
senha_inicial = models.CharField('Senha inicial', max_length=33, blank=True)
data_ativacao = models.DateField('Data de ativação', default=date.today)
data_alteracao = models.DateField('Data da última alteração', blank=True, null=True, auto_now=True)
data_desativacao = models.DateField('Data de desativação', blank=True, null=True)
motivo_desativacao = models.TextField('Motivo da desativação', blank=True)
casa_legislativa.casa_uf_filter = True
def __unicode__(self):
return "%s (%s)" % (self.tipo_servico.nome, 'ativo' if self.data_desativacao is None else 'Desativado')
def save(self, *args, **kwargs):
# Reter o objeto original para verificar mudanças
if self.id is not None:
original = Servico.objects.get(id=self.id)
if self.id is None:
# Novo serviço, email de ativação
subject = u'INTERLEGIS - Ativação de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_ativa
elif self.data_desativacao is not None and original.data_desativacao is None:
# Serviço foi desativado. Email de desativação
subject = u'INTERLEGIS - Desativação de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_desativa
elif (self.tipo_servico != original.tipo_servico or
self.contato_tecnico != original.contato_tecnico or
self.url != original.url or
self.nome_servidor != original.nome_servidor or
self.senha_inicial != original.senha_inicial):
# Serviço foi alterado
subject = u'INTERLEGIS - Alteração de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_altera
else:
# Salvar o Servico
super(Servico, self).save(*args, **kwargs)
return # sem enviar email
# Prepara e envia o email
body = body.replace('{url}', self.url) \
.replace('{senha}', self.senha_inicial) \
.replace('{motivo}', self.motivo_desativacao)
# send_mail(subject, body, DEFAULT_FROM_EMAIL, \
# (self.contato_tecnico.email,), fail_silently=False)
# Salvar o Servico
super(Servico, self).save(*args, **kwargs)
return
class LogServico(models.Model):
servico = models.ForeignKey(Servico, verbose_name='Serviço')
descricao = models.CharField('Breve descrição da ação', max_length=60)
data = models.DateField('Data da ação', default=date.today)
log = models.TextField('Log da ação')
def __unicode__(self):
return "%s (%s)" % (self.descricao, self.data)
class Meta:
verbose_name = 'Log do serviço'
verbose_name_plural = 'Logs do serviço'
class CasaAtendidaManager(models.Manager):
def get_query_set(self):
qs = super(CasaAtendidaManager, self).get_query_set()
qs = qs.exclude(codigo_interlegis='')
return qs
class CasaAtendida(CasaLegislativa):
class Meta:
proxy = True
verbose_name_plural = 'Casas atendidas'
objects = CasaAtendidaManager()
@property
def servicos(self):
result = []
for servico in self.servico_set.all():
result.append(unicode(servico))
return ", ".join(result)

127
sigi/apps/servicos/views.py

@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
from django import forms
from django.http import HttpResponse
from django.utils import simplejson
from django.shortcuts import render_to_response, get_object_or_404
from django.db.models import Q
from sigi.apps.servicos.models import TipoServico, CasaAtendida, CasaManifesta, ServicoManifesto
from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.casas.models import CasaLegislativa
from django.template.context import RequestContext
from django.utils.encoding import force_unicode
from django.forms.forms import BoundField
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
from django.contrib.admin.helpers import AdminForm
def municipios_atendidos(self, servico):
municipios = []
servico = servico.upper()
query = Q()
if servico != 'ALL':
for sigla in servico.split('_'):
query = query | Q(tipo_servico__sigla=sigla)
query = Q(data_desativacao=None) & query
for casa in CasaAtendida.objects.all():
if casa.servico_set.filter(query).exists():
m = casa.municipio
municipio = {'nome': casa.nome + ', ' + m.uf.sigla,
'lat': str(m.latitude),
'lng': str(m.longitude),
'servicos': "<ul><li>" + "</li><li>".join([s.tipo_servico.nome for s in casa.servico_set.filter(query)]) + "</li></ul>",}
municipios.append(municipio)
return HttpResponse(simplejson.dumps(municipios), mimetype="application/json")
class CasaManifestaProtoForm(forms.Form):
fieldsets = None
informante = forms.CharField(max_length=100, required=False)
cargo = forms.CharField(max_length=100, required=False)
def set_fieldsets(self, fieldsets):
result = []
for name, lines in fieldsets:
field_lines = []
for line in lines:
if isinstance(line, str):
line = (line,)
field_line = []
for field_name in line:
field = self.fields[field_name]
bf = BoundField(self, field, field_name)
field_line.append(bf)
field_lines.append(field_line)
result.append({'name': name, 'lines': field_lines},)
self.fieldsets = result
def casa_manifesta_view(request):
if 'casa_id' in request.GET:
casa_id = request.GET.get('casa_id')
casa = get_object_or_404(CasaLegislativa, pk=casa_id)
# Criar um formulário dinâmico
campos = {}
fieldsets = ((None, ('informante', 'cargo'),),)
for ts in TipoServico.objects.all():
campos['possui_%s' % ts.pk] = forms.BooleanField(label=u'Possui o serviço de %s' % ts.nome, required=False)
campos['url_%s' % ts.pk] = forms.URLField(label=u'Informe a URL', required=False)
campos['hospedagem_interlegis_%s' % ts.pk] = forms.BooleanField(label=u'Serviço está hospedado no Interlegis', required=False)
fieldsets += ((ts.nome, ('possui_%s' % ts.pk, 'url_%s' % ts.pk, 'hospedagem_interlegis_%s' % ts.pk )),)
CasaManifestaForm = type('', (CasaManifestaProtoForm,), campos)
if request.method == 'POST':
cmf = CasaManifestaForm(request.POST)
if cmf.is_valid():
thanks = []
cm, created = CasaManifesta.objects.get_or_create(casa_legislativa=casa)
cm.informante = cmf.cleaned_data['informante']
cm.cargo = cmf.cleaned_data['cargo']
cm.save()
thanks.append((u'Informante', cmf.cleaned_data['informante']))
thanks.append((u'Cargo', cmf.cleaned_data['cargo']))
for ts in TipoServico.objects.all():
if cmf.cleaned_data['possui_%s' % ts.pk]:
sm, created = ServicoManifesto.objects.get_or_create(casa_manifesta=cm, servico=ts)
sm.url = cmf.cleaned_data['url_%s' % ts.pk]
sm.hospedagem_interlegis = cmf.cleaned_data['hospedagem_interlegis_%s' % ts.pk]
sm.save()
thanks.append((ts.nome, u'Possui o serviço acessível em %s %s' % (sm.url, u'hospedado no Interlegis' if
sm.hospedagem_interlegis else '')))
else:
ServicoManifesto.objects.filter(casa_manifesta=cm, servico=ts).delete()
thanks.append((ts.nome, u'Não possui'))
extra_context = {'casa': casa, 'thanks': thanks}
else:
extra_context = {'casa': casa, 'cmf': cmf}
else:
try:
cm = casa.casamanifesta
values = {
'informante': cm.informante,
'cargo': cm.cargo,
}
for sm in cm.servicomanifesto_set.all():
values['possui_%s' % sm.servico.pk] = True
values['url_%s' % sm.servico.pk] = sm.url
values['hospedagem_interlegis_%s' % sm.servico.pk] = sm.hospedagem_interlegis
cmf = CasaManifestaForm(values)
except:
cmf = CasaManifestaForm()
cmf.set_fieldsets(fieldsets)
extra_context = {'casa': casa, 'cmf': cmf}
elif 'uf' in request.GET:
uf = request.GET.get('uf')
extra_context = {'casa_list': CasaLegislativa.objects.filter(municipio__uf__sigla=uf)}
else:
extra_context = {'uf_list': UnidadeFederativa.objects.all()}
return render_to_response('servicos/casa_manifesta.html', extra_context, context_instance=RequestContext(request))

11
sigi/settings.py

@ -40,6 +40,15 @@ INSTALLED_APPS = (
# Local apps
'sigi.apps.contatos',
'sigi.apps.servidores',
'sigi.apps.parlamentares',
'sigi.apps.mesas',
'sigi.apps.casas',
'sigi.apps.convenios',
'sigi.apps.inventario',
# Third-party apps
'localflavor',
'reporting',
)
MIDDLEWARE_CLASSES = (
@ -84,3 +93,5 @@ USE_TZ = True
# https://docs.djangoproject.com/en/dev/howto/static-files/
STATIC_URL = '/static/'
DEFAULT_FROM_EMAIL = 'sesostris@interlegis.leg.br'

Loading…
Cancel
Save