+
+
+
+
+{% endblock %}
diff --git a/sigi/apps/parlamentares/templates/parlamentares/change_form.html b/sigi/apps/parlamentares/templates/parlamentares/change_form.html
new file mode 100644
index 0000000..b59cb99
--- /dev/null
+++ b/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 %}
+
+{% endif %}{% endif %}
+{% endblock %}
diff --git a/sigi/apps/parlamentares/templates/parlamentares/change_list.html b/sigi/apps/parlamentares/templates/parlamentares/change_list.html
new file mode 100644
index 0000000..05501cd
--- /dev/null
+++ b/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 %}
+
+
+{% endblock %}
diff --git a/sigi/apps/parlamentares/views.py b/sigi/apps/parlamentares/views.py
new file mode 100644
index 0000000..67042a7
--- /dev/null
+++ b/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
\ No newline at end of file
diff --git a/sigi/apps/relatorios/__init__.py b/sigi/apps/relatorios/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sigi/apps/relatorios/models.py b/sigi/apps/relatorios/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/sigi/apps/relatorios/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/sigi/apps/relatorios/reports.py b/sigi/apps/relatorios/reports.py
new file mode 100644
index 0000000..a22bf7c
--- /dev/null
+++ b/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)}
+
+
diff --git a/sigi/apps/relatorios/tests.py b/sigi/apps/relatorios/tests.py
new file mode 100644
index 0000000..2247054
--- /dev/null
+++ b/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
+"""}
+
diff --git a/sigi/apps/relatorios/views.py b/sigi/apps/relatorios/views.py
new file mode 100644
index 0000000..60f00ef
--- /dev/null
+++ b/sigi/apps/relatorios/views.py
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/sigi/apps/servicos/__init__.py b/sigi/apps/servicos/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sigi/apps/servicos/admin.py b/sigi/apps/servicos/admin.py
new file mode 100644
index 0000000..665ddf4
--- /dev/null
+++ b/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'
%s' % (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'
%s' % (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 "
"
+ 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
\ No newline at end of file
diff --git a/sigi/apps/servicos/fixtures/initial_data.json b/sigi/apps/servicos/fixtures/initial_data.json
new file mode 100644
index 0000000..4671d13
--- /dev/null
+++ b/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"}}]
\ No newline at end of file
diff --git a/sigi/apps/servicos/management/__init__.py b/sigi/apps/servicos/management/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sigi/apps/servicos/management/commands/__init__.py b/sigi/apps/servicos/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sigi/apps/servicos/management/commands/atualiza_uso_servico.py b/sigi/apps/servicos/management/commands/atualiza_uso_servico.py
new file mode 100644
index 0000000..17e84da
--- /dev/null
+++ b/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))
\ No newline at end of file
diff --git a/sigi/apps/servicos/models.py b/sigi/apps/servicos/models.py
new file mode 100644
index 0000000..6ab2444
--- /dev/null
+++ b/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:
+ {url} para incluir a URL do serviço,
+ {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'
{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.
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
NÃO É ATUALIZADO AUTOMATICAMENTE!')
+ 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 + '
' + 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')
\ No newline at end of file
diff --git a/sigi/apps/servicos/models.py~ b/sigi/apps/servicos/models.py~
new file mode 100644
index 0000000..a4d7ba0
--- /dev/null
+++ b/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:
+ {url} para incluir a URL do serviço,
+ {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 + '
{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.
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)
\ No newline at end of file
diff --git a/sigi/apps/servicos/views.py b/sigi/apps/servicos/views.py
new file mode 100644
index 0000000..0e61541
--- /dev/null
+++ b/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': "
- " + "
- ".join([s.tipo_servico.nome for s in casa.servico_set.filter(query)]) + "
",}
+ 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))
\ No newline at end of file
diff --git a/sigi/settings.py b/sigi/settings.py
index eac5743..4a2c837 100644
--- a/sigi/settings.py
+++ b/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'