From 83674af34c3f551fffc1c3cd7ae6b072ce6bcc37 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Fri, 7 May 2010 15:50:57 +0000 Subject: [PATCH 01/28] =?UTF-8?q?Altera=C3=A7=C3=A3o=20de=20alguns=20model?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/casas/admin.py | 7 ++++++- sigi/apps/convenios/admin.py | 2 +- sigi/apps/convenios/models.py | 11 +++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sigi/apps/casas/admin.py b/sigi/apps/casas/admin.py index 6d73979..8e90087 100644 --- a/sigi/apps/casas/admin.py +++ b/sigi/apps/casas/admin.py @@ -4,6 +4,7 @@ from django.contrib.contenttypes import generic from sigi.apps.casas.forms import CasaLegislativaForm from sigi.apps.casas.models import CasaLegislativa from sigi.apps.contatos.models import Contato, Telefone +from sigi.apps.convenios.models import Convenio, EquipamentoPrevisto, Anexo class ContatosInline(generic.GenericTabularInline): model = Contato @@ -14,11 +15,15 @@ class TelefonesInline(generic.GenericTabularInline): model = Telefone extra = 2 +class ConveniosInline(admin.TabularInline): + model = Convenio + extra =0 + class CasaLegislativaAdmin(admin.ModelAdmin): form = CasaLegislativaForm change_form_template = 'casas/change_form.html' change_list_template = 'casas/change_list.html' - inlines = (TelefonesInline, ContatosInline) + inlines = (TelefonesInline, ContatosInline, ConveniosInline) list_display = ('nome', 'email', 'pagina_web', 'municipio') list_display_links = ('nome',) list_filter = ('tipo', 'municipio') diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index a4fe994..c832fa3 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -25,7 +25,7 @@ class ConvenioAdmin(admin.ModelAdmin): change_list_template = 'convenios/change_list.html' fieldsets = ( (None, - {'fields': ('casa_legislativa', 'num_processo_sf')} + {'fields': ('casa_legislativa', 'num_processo_sf','tipo_convenio')} ), ('Datas', {'fields': ('data_adesao', 'data_retorno_assinatura', diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index dc928c6..ce886ee 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -1,9 +1,15 @@ # -*- coding: utf-8 -*- from datetime import datetime from django.db import models +#from django.contrib.contenttypes import ContentType from django.contrib.contenttypes import generic class Convenio(models.Model): + CONVENIO_TIPO = ( + ('PI', 'Programa Interlegis'), + ('PPL', 'Projeto Piloto de Modernização'), + ('PML', 'Projeto Modernização Legislaivo') + ) casa_legislativa = models.ForeignKey( 'casas.CasaLegislativa', verbose_name='Casa Legislativa' @@ -19,6 +25,10 @@ class Convenio(models.Model): null=True, blank=True, ) + tipo_convenio = models.CharField( + max_length=10, + choices=CONVENIO_TIPO + ) data_retorno_assinatura = models.DateField( 'data do retorno e assinatura', null=True, @@ -47,6 +57,7 @@ class Convenio(models.Model): null=True, blank=True, ) + #content_type = models.ForeignKey(ContentType) class Meta: get_latest_by = 'id' From f4d8cbd227fab608d6b9f3d427f978703cf84016 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Sat, 8 May 2010 15:45:21 +0000 Subject: [PATCH 02/28] =?UTF-8?q?Consertando=20erro=20de=20codifica=C3=A7?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/casas/admin.py | 2 +- sigi/apps/convenios/models.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sigi/apps/casas/admin.py b/sigi/apps/casas/admin.py index 8e90087..1f44664 100644 --- a/sigi/apps/casas/admin.py +++ b/sigi/apps/casas/admin.py @@ -17,7 +17,7 @@ class TelefonesInline(generic.GenericTabularInline): class ConveniosInline(admin.TabularInline): model = Convenio - extra =0 + extra =1 class CasaLegislativaAdmin(admin.ModelAdmin): form = CasaLegislativaForm diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index ce886ee..dfac186 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -8,7 +8,7 @@ class Convenio(models.Model): CONVENIO_TIPO = ( ('PI', 'Programa Interlegis'), ('PPL', 'Projeto Piloto de Modernização'), - ('PML', 'Projeto Modernização Legislaivo') + ('PML', 'Projeto Modernização Legislativo') ) casa_legislativa = models.ForeignKey( 'casas.CasaLegislativa', @@ -50,7 +50,7 @@ class Convenio(models.Model): 'data de devolução da via', null=True, blank=True, - help_text='Data de devolução da via do convênio à Câmara Municipal.' + help_text=u'Data de devolução da via do convênio à Câmara Municipal.' ) data_postagem_correio = models.DateField( 'data postagem correio', @@ -62,13 +62,13 @@ class Convenio(models.Model): class Meta: get_latest_by = 'id' ordering = ('id',) - verbose_name = 'convênio' + verbose_name = u'convênio' def __unicode__(self): return str(self.id) class EquipamentoPrevisto(models.Model): - convenio = models.ForeignKey(Convenio, verbose_name='convênio') + convenio = models.ForeignKey(Convenio, verbose_name=u'convênio') equipamento = models.ForeignKey('inventario.Equipamento') quantidade = models.PositiveSmallIntegerField(default=1) @@ -80,7 +80,7 @@ class EquipamentoPrevisto(models.Model): return '%s %s(s)' % (self.quantidade, self.equipamento) class Anexo(models.Model): - convenio = models.ForeignKey(Convenio, verbose_name='convênio') + convenio = models.ForeignKey(Convenio, verbose_name=u'convênio') arquivo = models.FileField(upload_to='apps/convenios/anexo/arquivo',) descricao = models.CharField('descrição', max_length='70') data_pub = models.DateTimeField( From 8d4696ac728c4794bd4ab01d5cd5b804ad447dc7 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Wed, 12 May 2010 18:51:05 +0000 Subject: [PATCH 03/28] Acrescentando entidade Projeto na app convenios --- sigi/apps/casas/admin.py | 4 ++-- sigi/apps/convenios/admin.py | 5 +++-- sigi/apps/convenios/models.py | 18 +++++++++--------- sigi/sites.py | 3 ++- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/sigi/apps/casas/admin.py b/sigi/apps/casas/admin.py index 1f44664..d10972c 100644 --- a/sigi/apps/casas/admin.py +++ b/sigi/apps/casas/admin.py @@ -4,7 +4,7 @@ from django.contrib.contenttypes import generic from sigi.apps.casas.forms import CasaLegislativaForm from sigi.apps.casas.models import CasaLegislativa from sigi.apps.contatos.models import Contato, Telefone -from sigi.apps.convenios.models import Convenio, EquipamentoPrevisto, Anexo +from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo class ContatosInline(generic.GenericTabularInline): model = Contato @@ -17,7 +17,7 @@ class TelefonesInline(generic.GenericTabularInline): class ConveniosInline(admin.TabularInline): model = Convenio - extra =1 + extra = 1 class CasaLegislativaAdmin(admin.ModelAdmin): form = CasaLegislativaForm diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index c832fa3..5942e06 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- from django.contrib import admin -from sigi.apps.convenios.models import Convenio, EquipamentoPrevisto, Anexo +from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo from sigi.apps.servicos.models import Servico class AnexosInline(admin.TabularInline): @@ -25,7 +25,7 @@ class ConvenioAdmin(admin.ModelAdmin): change_list_template = 'convenios/change_list.html' fieldsets = ( (None, - {'fields': ('casa_legislativa', 'num_processo_sf','tipo_convenio')} + {'fields': ('casa_legislativa', 'num_processo_sf','projeto')} ), ('Datas', {'fields': ('data_adesao', 'data_retorno_assinatura', @@ -53,6 +53,7 @@ class EquipamentoPrevistoAdmin(admin.ModelAdmin): 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(EquipamentoPrevisto, EquipamentoPrevistoAdmin) admin.site.register(Anexo, AnexoAdmin) diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index dfac186..a7e051b 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -4,12 +4,13 @@ from django.db import models #from django.contrib.contenttypes import ContentType from django.contrib.contenttypes import generic -class Convenio(models.Model): - CONVENIO_TIPO = ( - ('PI', 'Programa Interlegis'), - ('PPL', 'Projeto Piloto de Modernização'), - ('PML', 'Projeto Modernização Legislativo') - ) +class Projeto(models.Model): + nome = models.CharField(max_length=50) + + def __unicode__(self): + return self.nome + +class Convenio(models.Model): casa_legislativa = models.ForeignKey( 'casas.CasaLegislativa', verbose_name='Casa Legislativa' @@ -25,9 +26,8 @@ class Convenio(models.Model): null=True, blank=True, ) - tipo_convenio = models.CharField( - max_length=10, - choices=CONVENIO_TIPO + projeto = models.ForeignKey( + Projeto ) data_retorno_assinatura = models.DateField( 'data do retorno e assinatura', diff --git a/sigi/sites.py b/sigi/sites.py index febd61f..c52d476 100644 --- a/sigi/sites.py +++ b/sigi/sites.py @@ -6,7 +6,7 @@ from sigi.apps.casas.admin import CasaLegislativa, CasaLegislativaAdmin from sigi.apps.contatos.admin import (UnidadeFederativa, UnidadeFederativaAdmin, Municipio, MunicipioAdmin, Telefone, TelefoneAdmin, Contato, ContatoAdmin) -from sigi.apps.convenios.admin import (Convenio, ConvenioAdmin, EquipamentoPrevisto, +from sigi.apps.convenios.admin import (Projeto, Convenio, ConvenioAdmin, EquipamentoPrevisto, EquipamentoPrevistoAdmin, Anexo, AnexoAdmin) from sigi.apps.inventario.admin import (Fornecedor, FornecedorAdmin, Fabricante, FabricanteAdmin, Equipamento, @@ -50,6 +50,7 @@ default.register(Telefone, TelefoneAdmin) default.register(Contato, ContatoAdmin) # sigi.apps.convenios +default.register(Projeto) default.register(Convenio, ConvenioAdmin) default.register(EquipamentoPrevisto, EquipamentoPrevistoAdmin) default.register(Anexo, AnexoAdmin) From 9aee20172fea5393c8cb35ea71e4d8649330c130 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Thu, 13 May 2010 18:16:25 +0000 Subject: [PATCH 04/28] =?UTF-8?q?Adicionando=20primeiros=20relat=C3=B3rios?= =?UTF-8?q?=20de=20conv=C3=AAnios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/convenios/admin.py | 18 +++++++++++++++--- sigi/apps/convenios/reports.py | 31 +++++++++++++++++++++++++++++++ sigi/apps/convenios/views.py | 25 +++++++++++++++++++++++++ sigi/urls.py | 5 ++++- 4 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 sigi/apps/convenios/views.py diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index 5942e06..1299ab3 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -2,6 +2,7 @@ from django.contrib import admin from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo from sigi.apps.servicos.models import Servico +from django.http import HttpResponseRedirect class AnexosInline(admin.TabularInline): model = Anexo @@ -33,17 +34,29 @@ class ConvenioAdmin(admin.ModelAdmin): 'data_devolucao_via', 'data_postagem_correio')} ), ) + actions = ['delete_selected', 'relatorio'] inlines = (AnexosInline, EquipamentoPrevistoInline) list_display = ('id', 'casa_legislativa', - 'num_processo_sf', 'data_adesao') + 'num_processo_sf', 'data_adesao', 'projeto') list_filter = ('data_adesao', 'data_retorno_assinatura', 'data_termo_aceite', 'data_devolucao_via', - 'data_postagem_correio') + 'data_postagem_correio', 'projeto') ordering = ('-id',) raw_id_fields = ('casa_legislativa',) search_fields = ('id', 'casa_legislativa__nome', 'num_processo_sf', 'casa_legislativa__municipio__nome', 'casa_legislativa__municipio__uf__nome') + def changelist_view(self, request, extra_context=None): + return super(ConvenioAdmin, self).changelist_view( + request, + extra_context={'query_str': '?' + request.META['QUERY_STRING']} + ) + def relatorio(modeladmin, request, queryset): + selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) + print selected + return HttpResponseRedirect("reports/?ids=%s"%(",".join(selected))) + relatorio.short_description = 'Selecione para gerar relatorio' + class EquipamentoPrevistoAdmin(admin.ModelAdmin): list_display = ('convenio', 'equipamento', 'quantidade') @@ -56,4 +69,3 @@ class EquipamentoPrevistoAdmin(admin.ModelAdmin): admin.site.register(Projeto) admin.site.register(Convenio, ConvenioAdmin) admin.site.register(EquipamentoPrevisto, EquipamentoPrevistoAdmin) -admin.site.register(Anexo, AnexoAdmin) diff --git a/sigi/apps/convenios/reports.py b/sigi/apps/convenios/reports.py index 86eca5d..40cb180 100644 --- a/sigi/apps/convenios/reports.py +++ b/sigi/apps/convenios/reports.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label +from reportlab.lib.units import cm class CasasAderidasReport(object): pass @@ -9,3 +12,31 @@ class CasasComEquipamentosReport(object): class SemEquipamentosReport(object): pass +class ConvenioReport(Report): + title = u'Relatórios dos Convênios' + author = u'Interlegis' + class band_page_header(ReportBand): + elements = [ + Label( + text="ID", left=0.5*cm + ), + Label( + text="Nº Processo", left=3*cm + ), + Label( + text="Nome", left=5*cm + ), + Label( + text="Data Adesão", left=10*cm + ), + ] + #borders = {'bottom': True} + class band_detail(DetailBand): +# height = 0.5*cm + elements=[ + ObjectValue(attribute_name='id', left=0.5*cm), + ObjectValue(attribute_name='num_processo_sf', left=3*cm), + ObjectValue(attribute_name='casa_legislativa', left=5*cm), + ObjectValue(attribute_name='data_adesao', left=10*cm) + ] + border = {'bottom': True} diff --git a/sigi/apps/convenios/views.py b/sigi/apps/convenios/views.py new file mode 100644 index 0000000..50d88b6 --- /dev/null +++ b/sigi/apps/convenios/views.py @@ -0,0 +1,25 @@ +from django.http import HttpResponse, HttpResponseRedirect +from geraldo.generators import PDFGenerator +from sigi.apps.convenios.models import Convenio +from sigi.apps.convenios.reports import ConvenioReport + +def report(request, id=None): + qs = Convenio.objects.all() + if id: + qs = qs.filter(pk=id) + elif request.GET: #Se tiver algum parametro de pesquisa + kwargs = {} + for k, v in request.GET.iteritems(): + kwargs[str(k)] = v + if(str(k)=='ids'): + break + qs = qs.filter(**kwargs) + if kwargs['ids']: + query = 'id IN ('+ kwargs['ids'].__str__()+')' + qs = Convenio.objects.extra(where=[query]) + if not qs: + return HttpResponseRedirect('../') + response = HttpResponse(mimetype='application/pdf') + report = ConvenioReport(queryset=qs) + report.generate_by(PDFGenerator, filename=response) + return response diff --git a/sigi/urls.py b/sigi/urls.py index 6eb1965..a4a82d0 100644 --- a/sigi/urls.py +++ b/sigi/urls.py @@ -8,11 +8,14 @@ import sigi.admin.filterspecs urlpatterns = patterns( '', - # reports + # reports labels (r'^casas/casalegislativa/labels/', 'sigi.apps.casas.views.labels_report'), (r'^casas/casalegislativa/(?P\w+)/labels/', 'sigi.apps.casas.views.labels_report'), + # reports + (r'^convenios/convenio/reports/', + 'sigi.apps.convenios.views.report'), # automatic interface based on admin (r'^(.*)', sites.default.root), From 10a179f7e17a614f145afb579b6268057040fc51 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Fri, 14 May 2010 17:20:12 +0000 Subject: [PATCH 05/28] =?UTF-8?q?Corrigindo=20script=20de=20migra=C3=A7?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/migracao/migra.py | 145 +++++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 43 deletions(-) diff --git a/etc/migracao/migra.py b/etc/migracao/migra.py index 6e4fed3..b0284fc 100755 --- a/etc/migracao/migra.py +++ b/etc/migracao/migra.py @@ -1,6 +1,5 @@ - #!/usr/bin/env python -# coding: utf-8 +# -*- coding: utf-8 -*- """ Script para fazer a migração dos dados do SIGI antigo (Access), exportados para @@ -43,24 +42,25 @@ def migra_assembleias(filename): # identificação das colunas nos arquivo CSV UF_COL = 5 NOME_COL = 8 - ENDERECO_COL = 39 - CEP_COL = 40 - EMAIL_COL = 41 - PAGINA_COL = 43 - OBS_COL = 37 FONE_1_COL = 32 FONE_2_COL = 33 FAX_COL = 34 FONE_PREFEITURA = 35 + OBS_COL = 37 PRESIDENTE_COL = 38 + ENDERECO_COL = 39 + CEP_COL = 40 + EMAIL_COL = 41 EMAIL_PRESIDENTE_COL = 42 - REPRESENTANTE_COL = 86 + PAGINA_COL = 43 + #REPRESENTANTE_COL = 86 reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True) header = reader.next() for line in reader: - municipio = Municipio.objects.get(uf__sigla=line[UF_COL], is_capital=True) + UF = UnidadeFederativa.objects.get(sigla=line[UF_COL]) + municipio = Municipio.objects.get(municipio__codigo_ibge=line[UF_COL], is_capital=True) casa = CasaLegislativa( municipio=municipio, nome=line[NOME_COL], @@ -93,9 +93,9 @@ def migra_assembleias(filename): ) fone_prefeitura.save() - if line[REPRESENTANTE_COL]: - representante = Contato(nome=line[REPRESENTANTE_COL], content_object=casa) - representante.save() +# if line[REPRESENTANTE_COL]: +# representante = Contato(nome=line[REPRESENTANTE_COL], content_object=casa) +# representante.save() if line[PRESIDENTE_COL]: mesa = MesaDiretora(casa_legislativa=casa) @@ -134,13 +134,19 @@ def migra_casas(filename): linenum = 1 for line in reader: linenum += 1 - try: municipio = Municipio.objects.get(codigo_ibge=line[COD_IBGE_COL]) + #print line[COD_IBGE_COL] + #var = raw_input() + print municipio.codigo_ibge except Municipio.DoesNotExist: + print "Municipio não existe" + #var = raw_input() + #print line[COD_IBDE_COL] print ERROR_MSG_1 % (filename, linenum) continue except ValueError: + var = raw_input() print ERROR_MSG_1 % (filename, linenum) continue casa = CasaLegislativa( @@ -153,9 +159,12 @@ def migra_casas(filename): pagina_web=line[PAGINA_COL], observacoes=line[OBS_COL], ) + #print casa.nome try: casa.save() except: + print "Erro ao inserir casa" + #var = raw_input("teste") print ERROR_MSG_0 % (filename, linenum) continue @@ -217,10 +226,16 @@ def migra_cnpj(filename): except ValueError: print ERROR_MSG_1 % (filename, linenum) continue - casa.cnpj = line[COD_CNPJ1_COL] if not 'BRANCO' in line[COD_CNPJ1_COL] else line[COD_CNPJ2_COL] + casa.cnpj = line[COD_CNPJ1_COL] if not 'EM BRANCO' in line[COD_CNPJ1_COL] else line[COD_CNPJ2_COL] casa.save() def migra_convenios_casas(filename): + """ + Será preciso cadastrar no banco os seguintes Projeto: + 1 - Sem Projeto + 2 - Projeto Interlegis + 3 - Programa Piloto de Modernização + """ def get_datetime_obj(data): ldata = data.split('-') if len(ldata) != 3: @@ -228,14 +243,26 @@ def migra_convenios_casas(filename): return datetime(int(ldata[0]), int(ldata[1]), int(ldata[2])) # identificação das colunas no arquivo CSV + # No arquivo CSV colunas que contém _100 são do Programa Interlegis COD_IBGE_COL = 1 - NUM_PROCESSO_SF_COL = 25 + DATA_ADESAO_COL = 10 DATA_TERMO_ACEITE_COL = 21 + NUM_CONVENIO_COL = 23 + DATA_POSTAGEM_CORREIO = 26 + NUM_PROCESSO_SF_COL = 27 DATA_RETORNO_ASSINATURA = 28 DATA_PUB_DIARIO = 30 DATA_DEV_VIA_CONV_CM = 32 - DATA_POSTAGEM_CORREIO = 26 + + DATA_ADESAO_100_COL = 11 + DATA_TERMO_ACEITE_100_COL = 22 + NUM_CONVENIO_100_COL = 24 + NUM_PROCESSO_SF_100_COL = 25 + DATA_RETORNO_ASSINATURA_100_COL = 29 + DATA_PUB_DIARIO_100_COL = 31 + #DATA_DEV_VIA_CONV_CM_100 = 32 Não foi registrado para as 100 + #DATA_POSTAGEM_CORREIO_100 = 26 reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True) header = reader.next() @@ -254,19 +281,49 @@ def migra_convenios_casas(filename): except ValueError: print ERROR_MSG_1 % (filename, linenum) continue - - convenio = Convenio( + if line[DATA_ADESAO_COL]=='1001-01-01':#Sem Projeto + line[DATA_ADESAO_COL]='' + projeto = Projeto.objects.get(id=1) + else: + projeto = Projeto.objects.get(id=2) + + if(projeto.id!=1 or line[NUM_PROCESSO_SF_COL].__len__()!=0 or + line[NUM_CONVENIO_COL].__len__()!=0): + convenio1 = Convenio( + casa_legislativa=casa, + projeto=projeto, + num_processo_sf=line[NUM_PROCESSO_SF_COL], + num_convenio=line[NUM_CONVENIO_COL], + data_adesao=get_datetime_obj(line[DATA_ADESAO_COL]), + data_retorno_assinatura=get_datetime_obj(line[DATA_TERMO_ACEITE_COL]), + data_pub_diario=get_datetime_obj(line[DATA_RETORNO_ASSINATURA]), + data_termo_aceite=get_datetime_obj(line[DATA_PUB_DIARIO]), + data_devolucao_via=get_datetime_obj(line[DATA_DEV_VIA_CONV_CM]), + data_postagem_correio=get_datetime_obj(line[DATA_POSTAGEM_CORREIO]), + ) + if line[DATA_ADESAO_100_COL]=='1001-01-01':#Sem Projeto + line[DATA_ADESAO_100_COL]='' + projeto = Projeto.objects.get(id=1) + else: + projeto = Projeto.objects.get(id=3) + if(projeto.id!=1 or line[NUM_PROCESSO_SF_100_COL].__len__()!=0 or + line[NUM_CONVENIO_100_COL].__len__()!=0): + convenio2 = Convenio( casa_legislativa=casa, - num_processo_sf=line[NUM_PROCESSO_SF_COL], - data_adesao=get_datetime_obj(line[DATA_ADESAO_COL]), - data_retorno_assinatura=get_datetime_obj(line[DATA_TERMO_ACEITE_COL]), - data_pub_diario=get_datetime_obj(line[DATA_RETORNO_ASSINATURA]), - data_termo_aceite=get_datetime_obj(line[DATA_PUB_DIARIO]), - data_devolucao_via=get_datetime_obj(line[DATA_DEV_VIA_CONV_CM]), - data_postagem_correio=get_datetime_obj(line[DATA_POSTAGEM_CORREIO]), - ) + projeto=projeto, + num_processo_sf=line[NUM_PROCESSO_SF_100_COL], + num_convenio=line[NUM_CONVENIO_100_COL], + data_adesao=get_datetime_obj(line[DATA_ADESAO_100_COL]), + data_retorno_assinatura=get_datetime_obj(line[DATA_TERMO_ACEITE_100_COL]), + data_pub_diario=get_datetime_obj(line[DATA_RETORNO_ASSINATURA_100_COL]), + data_termo_aceite=get_datetime_obj(line[DATA_PUB_DIARIO_100_COL]), + # data_devolucao_via=get_datetime_obj(line[DATA_DEV_VIA_CONV_CM]), + # data_postagem_correio=get_datetime_obj(line[DATA_POSTAGEM_CORREIO]), + ) + try: - convenio.save() + if convenio1: convenio1.save() + if convenio2: convenio2.save() except: print ERROR_MSG_0 % (filename, linenum) continue @@ -279,14 +336,14 @@ def migra_convenios_assembleias(filename): return datetime(int(ldata[0]), int(ldata[1]), int(ldata[2])) # identificação das colunas no arquivo CSV - COD_IBGE_COL = 1 - NUM_PROCESSO_SF_COL = 25 + SIGLA_COL = 5 DATA_ADESAO_COL = 10 DATA_TERMO_ACEITE_COL = 21 - DATA_RETORNO_ASSINATURA = 28 - DATA_PUB_DIARIO = 30 - DATA_DEV_VIA_CONV_CM = 32 - DATA_POSTAGEM_CORREIO = 26 + NUM_CONVENIO_COL = 23 + NUM_PROCESSO_SF_COL = 26 + DATA_RETORNO_ASSINATURA = 27 + DATA_PUB_DIARIO = 39 + DATA_DEV_VIA_CONV_CM = 31 reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True) header = reader.next() @@ -295,7 +352,7 @@ def migra_convenios_assembleias(filename): linenum += 1 try: - assembleia = CasaLegislativa.objects.get(municipio__codigo_ibge=line[COD_IBGE_COL]) + assembleia = CasaLegislativa.objects.get(municipio__uf__sigla=line[COD_IBGE_COL]) except CasaLegislativa.DoesNotExist: print ERROR_MSG_1 % (filename, linenum) continue @@ -304,10 +361,12 @@ def migra_convenios_assembleias(filename): except ValueError: print ERROR_MSG_1 % (filename, linenum) continue - + projeto = Projeto.object.get(id=2) convenio = Convenio( casa_legislativa=assembleia, num_processo_sf=line[NUM_PROCESSO_SF_COL], + num_convenio=line[NUM_CONVENIO_COL], + projeto=projeto, data_adesao=get_datetime_obj(line[DATA_ADESAO_COL]), data_retorno_assinatura=get_datetime_obj(line[DATA_TERMO_ACEITE_COL]), data_pub_diario=get_datetime_obj(line[DATA_RETORNO_ASSINATURA]), @@ -323,13 +382,13 @@ def migra_convenios_assembleias(filename): if __name__ == '__main__': - print "" - migra_assembleias('assembleias.csv') - print "" - migra_casas('casas.csv') - print "" - migra_cnpj('cnpj.csv') +# print "" +# migra_assembleias('assembleias.csv') +# print "" +# migra_casas('casas.csv') +# print "" +# migra_cnpj('cnpj.csv') print "" migra_convenios_casas('casas.csv') - print "" - migra_convenios_casas('assembleias.csv') +# print "" +# migra_convenios_assembleias('assembleias.csv') From f05f4f64548c2da53847e59ae3f788da405bad69 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Fri, 14 May 2010 17:20:51 +0000 Subject: [PATCH 06/28] =?UTF-8?q?Adicionando=20campo=20n=C3=BAmero=20de=20?= =?UTF-8?q?conv=C3=AAnio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/convenios/admin.py | 9 +++++---- sigi/apps/convenios/models.py | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index 1299ab3..227aa80 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -26,7 +26,7 @@ class ConvenioAdmin(admin.ModelAdmin): change_list_template = 'convenios/change_list.html' fieldsets = ( (None, - {'fields': ('casa_legislativa', 'num_processo_sf','projeto')} + {'fields': ('casa_legislativa', 'num_processo_sf','num_convenio','projeto')} ), ('Datas', {'fields': ('data_adesao', 'data_retorno_assinatura', @@ -41,11 +41,12 @@ class ConvenioAdmin(admin.ModelAdmin): list_filter = ('data_adesao', 'data_retorno_assinatura', 'data_termo_aceite', 'data_devolucao_via', 'data_postagem_correio', 'projeto') + #, 'casa_legislativa__nome') ordering = ('-id',) raw_id_fields = ('casa_legislativa',) search_fields = ('id', 'casa_legislativa__nome', - 'num_processo_sf', 'casa_legislativa__municipio__nome', - 'casa_legislativa__municipio__uf__nome') + 'num_processo_sf') + def changelist_view(self, request, extra_context=None): return super(ConvenioAdmin, self).changelist_view( request, @@ -66,6 +67,6 @@ class EquipamentoPrevistoAdmin(admin.ModelAdmin): search_fields = ('convenio__id', 'equipamento__fabricante__nome', 'equipamento__modelo__modelo', 'equipamento__modelo__tipo__tipo') -admin.site.register(Projeto) +#admin.site.register(Projeto) admin.site.register(Convenio, ConvenioAdmin) admin.site.register(EquipamentoPrevisto, EquipamentoPrevistoAdmin) diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index a7e051b..a7d254c 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -21,6 +21,11 @@ class Convenio(models.Model): blank=True, help_text='Formato: XXXXXX/XX-X.' ) + num_convenio = models.CharField( + 'número do convênio', + max_length=10, + blank=True + ) data_adesao = models.DateField( 'data de adesão', null=True, From 668fb39e48386e1ca8d4f44341faa0d8219639ad Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Fri, 14 May 2010 20:51:37 +0000 Subject: [PATCH 07/28] Filtro de convenio apenas por projeto e acrescentando date_hierarchy --- sigi/apps/convenios/admin.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index 227aa80..0ab96c1 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -38,10 +38,8 @@ class ConvenioAdmin(admin.ModelAdmin): inlines = (AnexosInline, EquipamentoPrevistoInline) list_display = ('id', 'casa_legislativa', 'num_processo_sf', 'data_adesao', 'projeto') - list_filter = ('data_adesao', 'data_retorno_assinatura', - 'data_termo_aceite', 'data_devolucao_via', - 'data_postagem_correio', 'projeto') - #, 'casa_legislativa__nome') + list_filter = ('projeto',) + date_hierarchy = 'data_adesao' ordering = ('-id',) raw_id_fields = ('casa_legislativa',) search_fields = ('id', 'casa_legislativa__nome', From 3cd0e067a60e45bddb5be95c927eb2513aa67ad9 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Mon, 17 May 2010 19:15:43 +0000 Subject: [PATCH 08/28] Acrescentando legendas aos graficos do Dashboard --- sigi/templates/snippets/modules/charts-convenios.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sigi/templates/snippets/modules/charts-convenios.html b/sigi/templates/snippets/modules/charts-convenios.html index 78042b2..458d040 100644 --- a/sigi/templates/snippets/modules/charts-convenios.html +++ b/sigi/templates/snippets/modules/charts-convenios.html @@ -3,7 +3,8 @@ {% chart as convenios %} {% chart-size 340 160 %} {% chart-type "pie" %} - {% chart-labels "Conveniadas" "Não conveniadas" "Não aderidas" %} + {% chart-labels convenios_chart_data %} + {% chart-legend "Conveniadas" "Não conveniadas" "Não aderidas" %} {% chart-data convenios_chart_data %} {% endchart %} @@ -18,10 +19,11 @@ {% endchart %} {% chart as equipamentos %} - {% chart-size 340 160 %} - {% chart-type "pie" %} - {% chart-labels "Recebidos" "Não recebidos" %} + {% chart-size 340 160 %} + {% chart-type "pie" %} + {% chart-labels equipamentos_chart_data %} {% chart-data equipamentos_chart_data %} + {% chart-legend "Recebidos" "Não recebidos" %} {% endchart %}
From 8e35dd91da08df8b45d1d2c720c787ebe739852f Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Mon, 17 May 2010 20:11:20 +0000 Subject: [PATCH 09/28] =?UTF-8?q?Corrigindo=20falha=20na=20gera=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20relat=C3=B3rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/convenios/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sigi/apps/convenios/views.py b/sigi/apps/convenios/views.py index 50d88b6..352315b 100644 --- a/sigi/apps/convenios/views.py +++ b/sigi/apps/convenios/views.py @@ -9,12 +9,14 @@ def report(request, id=None): qs = qs.filter(pk=id) elif request.GET: #Se tiver algum parametro de pesquisa kwargs = {} + ids = 0 for k, v in request.GET.iteritems(): kwargs[str(k)] = v if(str(k)=='ids'): + ids = 1 break qs = qs.filter(**kwargs) - if kwargs['ids']: + if ids: query = 'id IN ('+ kwargs['ids'].__str__()+')' qs = Convenio.objects.extra(where=[query]) if not qs: From 1f3d79b89b8eeba541628835358c433b26cc8a96 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Tue, 18 May 2010 20:07:46 +0000 Subject: [PATCH 10/28] =?UTF-8?q?Corrigindo=20scrpit=20de=20migra=C3=A7?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/migracao/migra.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/etc/migracao/migra.py b/etc/migracao/migra.py index b0284fc..15c4e43 100755 --- a/etc/migracao/migra.py +++ b/etc/migracao/migra.py @@ -136,17 +136,11 @@ def migra_casas(filename): linenum += 1 try: municipio = Municipio.objects.get(codigo_ibge=line[COD_IBGE_COL]) - #print line[COD_IBGE_COL] - #var = raw_input() - print municipio.codigo_ibge except Municipio.DoesNotExist: print "Municipio não existe" - #var = raw_input() - #print line[COD_IBDE_COL] print ERROR_MSG_1 % (filename, linenum) continue except ValueError: - var = raw_input() print ERROR_MSG_1 % (filename, linenum) continue casa = CasaLegislativa( @@ -159,12 +153,10 @@ def migra_casas(filename): pagina_web=line[PAGINA_COL], observacoes=line[OBS_COL], ) - #print casa.nome try: casa.save() except: print "Erro ao inserir casa" - #var = raw_input("teste") print ERROR_MSG_0 % (filename, linenum) continue @@ -382,13 +374,13 @@ def migra_convenios_assembleias(filename): if __name__ == '__main__': -# print "" -# migra_assembleias('assembleias.csv') -# print "" -# migra_casas('casas.csv') -# print "" -# migra_cnpj('cnpj.csv') + print "" + migra_assembleias('assembleias.csv') + print "" + migra_casas('casas.csv') + print "" + migra_cnpj('cnpj.csv') print "" migra_convenios_casas('casas.csv') -# print "" -# migra_convenios_assembleias('assembleias.csv') + print "" + migra_convenios_assembleias('assembleias.csv') From d7002e3f93291f4a2039c57dc5fcb96c5a0e04f7 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Tue, 25 May 2010 20:29:48 +0000 Subject: [PATCH 11/28] =?UTF-8?q?Adicionando=20campo=20observa=C3=A7=C3=A3?= =?UTF-8?q?o=20em=20conv=C3=AAnio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/convenios/admin.py | 4 +++- sigi/apps/convenios/models.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index 0ab96c1..120ce98 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from django.contrib import admin from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo +from sigi.apps.casas.models import CasaLegislativa from sigi.apps.servicos.models import Servico from django.http import HttpResponseRedirect @@ -26,7 +27,7 @@ class ConvenioAdmin(admin.ModelAdmin): change_list_template = 'convenios/change_list.html' fieldsets = ( (None, - {'fields': ('casa_legislativa', 'num_processo_sf','num_convenio','projeto')} + {'fields': ('casa_legislativa', 'num_processo_sf','num_convenio','projeto','observacao')} ), ('Datas', {'fields': ('data_adesao', 'data_retorno_assinatura', @@ -67,4 +68,5 @@ class EquipamentoPrevistoAdmin(admin.ModelAdmin): #admin.site.register(Projeto) admin.site.register(Convenio, ConvenioAdmin) +#admin.site.register(CasaLegislativa) admin.site.register(EquipamentoPrevisto, EquipamentoPrevistoAdmin) diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index a7d254c..2512dff 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -62,7 +62,7 @@ class Convenio(models.Model): null=True, blank=True, ) - #content_type = models.ForeignKey(ContentType) + observacao = models.TextField() class Meta: get_latest_by = 'id' From 09534f26cce5156f57fdbd72363f3e67d0ebb89f Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Thu, 27 May 2010 20:18:08 +0000 Subject: [PATCH 12/28] =?UTF-8?q?Adicionando=20filtro=20em=20conv=C3=AAnio?= =?UTF-8?q?s=20por=20UF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/admin/filterspecs.py | 38 ++++++++++++++++++++++++++++++++++- sigi/apps/convenios/admin.py | 2 +- sigi/apps/convenios/models.py | 1 + 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/sigi/admin/filterspecs.py b/sigi/admin/filterspecs.py index d926dab..74a67d7 100644 --- a/sigi/admin/filterspecs.py +++ b/sigi/admin/filterspecs.py @@ -45,7 +45,7 @@ class MunicipioUFFilterSpec(ChoicesFilterSpec): my_municipio_field.uf_filter = True - On Django 1.2 you will can specify a lookup on admin filters. Example: + On Django 1.3 you will can specify a lookup on admin filters. Example: list_filter = ('municipio__uf',) @@ -74,6 +74,42 @@ class MunicipioUFFilterSpec(ChoicesFilterSpec): FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'uf_filter', False), MunicipioUFFilterSpec)) +class ConvenioUFFilterSpec(ChoicesFilterSpec): + """ + Usage: + + municipio.uf_filter = True + + On Django 1.3 you will can specify a lookup on admin filters. Example: + + list_filter = ('municipio__uf',) + + """ + + def __init__(self, f, request, params, model, model_admin): + super(ConvenioUFFilterSpec, self).__init__(f, request, params, model, + model_admin) + self.lookup_kwarg = '%s__municipio__uf__codigo_ibge__exact' % f.name + self.lookup_val = request.GET.get(self.lookup_kwarg, None) + self.lookup_choices = UnidadeFederativa.objects.all().order_by('nome') + + def choices(self, cl): + yield {'selected': self.lookup_val is None, + 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), + 'display': _('All')} + for val in self.lookup_choices: + yield {'selected': smart_unicode(val.codigo_ibge) == self.lookup_val, + 'query_string': cl.get_query_string({self.lookup_kwarg: val.codigo_ibge}), + 'display': val.nome} + def title(self): + return _('UF') % \ + {'field_name': self.field.verbose_name} + +# registering the filter +FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'uf_filter', False), + ConvenioUFFilterSpec)) + + class RangeValuesFilterSpec(FilterSpec): """ Author: Willie Gollino (wgollino@yahoo.com) diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index 120ce98..75af0e5 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -39,7 +39,7 @@ class ConvenioAdmin(admin.ModelAdmin): inlines = (AnexosInline, EquipamentoPrevistoInline) list_display = ('id', 'casa_legislativa', 'num_processo_sf', 'data_adesao', 'projeto') - list_filter = ('projeto',) + list_filter = ('projeto','casa_legislativa') date_hierarchy = 'data_adesao' ordering = ('-id',) raw_id_fields = ('casa_legislativa',) diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index 2512dff..60d64ef 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -15,6 +15,7 @@ class Convenio(models.Model): 'casas.CasaLegislativa', verbose_name='Casa Legislativa' ) + casa_legislativa.uf_filter = True num_processo_sf = models.CharField( 'número do processo SF', max_length=11, From e7f11272cfe7470b99386c034042e35674aae802 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Tue, 1 Jun 2010 20:36:45 +0000 Subject: [PATCH 13/28] Acrescentando imagens e alterando css --- media/css/base_site.css | 12 ++++++++---- media/images/default-bg2.jpg | Bin 0 -> 358 bytes media/images/logo-interlegis.jpg | Bin 0 -> 2667 bytes 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 media/images/default-bg2.jpg create mode 100644 media/images/logo-interlegis.jpg diff --git a/media/css/base_site.css b/media/css/base_site.css index 9d55a24..4159131 100644 --- a/media/css/base_site.css +++ b/media/css/base_site.css @@ -4,7 +4,7 @@ a:hover { color:#11488d; } /* HEADER */ -#header { background:#003351; } +#header { background:#003351 url(../images/default-bg3.jpg);} #site-name a:hover { text-decoration: none; } #nav-global { @@ -16,7 +16,8 @@ a:hover { color:#11488d; } font-weight:bold; } #nav-global ul { - background:#222; + /*background:#222;*/ + background:#efefef url("../../admin_media/img/admin/nav-bg.gif");/*#9C9C9C;*/ height:25px; margin:0; padding:0; @@ -27,7 +28,7 @@ a:hover { color:#11488d; } padding:0px; } #nav-global li a { - background:#222 url("../images/menu/seperator.gif") bottom right no-repeat; + /*background: url("../images/menu/seperator.gif") bottom right no-repeat;*/ color:#cccccc; display:block; font-weight:normal; @@ -36,7 +37,10 @@ a:hover { color:#11488d; } padding:0px 15px; text-align:center; text-decoration:none; + /*font-size: medium;*/ } +#nav-global li a:link,#nav-global li a:visited{ color: black;} + #nav-global li a:hover, #nav-global ul li:hover a { background-color:#333; color:#FFFFFF; @@ -52,7 +56,7 @@ a:hover { color:#11488d; } position:absolute; width:200px; z-index:200; - /*top:1em; + /*top:1em;*/ /*left:0;*/ } #nav-global li:hover ul { display:block; } diff --git a/media/images/default-bg2.jpg b/media/images/default-bg2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..075aec30777951adb64fa7d188208d5b8a3a6716 GIT binary patch literal 358 zcmex=|Jt7~Xz zC@5=Vw9yzfvi*yDVQ{L(|;R4Ub@4>?-!!D=g zD{b9oOg@#++)qs}c%-bOi?^eAoM%-&lQ6dbLzn1ZzNEsWpb)skGC~4iFbE8VNWuSg zC43|lhLUgyS@QEA0!*Z+`u0V-%2uNVY{nkbn(P7kX6_s)Ya{`pw<%W`#9l z-l+yv5>}0=i@jHUDFziX34Xjk4HC=v3?20fz@fwp{hr9WHS?1_&oETKV_2SJk)ud! zihk4e?AbtF*Xb13d>j21+1iZmhl^a@fbnqhI|44vU;9c##oZ4o>!BK}tqsh%!z#Ff zM4yYvLo}NL)A#3uyuDG;78S+81%06}^S8J0>6Lm(p&oAo*@Q! zvKX4d5ON#*Y?e}kYipDWGB+L_!w%gUzsyY%_zaJ@dsv~Si>5|1bgjT@G^M+oX1 zLBZ(B7H3YR7Q!B%cU24c-&J5|7b=^#c=vnG-pu@*^5x~FdL^oS(zSMb@|-~L`sQ$v@x$ymHzS!B88t#mZrF|$sQME%hb%r+6C7?URt_o2 zXv-q8WGsW1nIhBc0Q?>uo>;ZGRK(OTdL$ZNoGzh!{Iz9b@@3E7B`w5!#9|-+t#XF- zNQv&j&KjGt2-)i@8a^%akjYT1Q!nT8m9gRW{DVD2gKWdy_)V@JUFdwq%WCqv|8KQA zou5*b#yFTib9(F6JwZQQGGuP(5K5|5*sPPX#+RqkljTCVX9#lCi;qV4CYCDBfW(@xPTMp#79?S{G?m@kR5u0I{a~&KEX*p`BlY z6Wf+VYmdX11eyE;&LLqpqXlqPL*2N^QI@phxZ`SXMAXrv>=&9Vs?@AH0>js!~f)@@?mrpRo zS53Q*Z2%^vUpu{ngi5DoORETZ{crhhjiJ}QNsbzHhdL}8vx913Hc~Zq;0^Z*Gc@?5usNQnoSfs}?t+{%lM!@<^%=Dg9As&l$ay)$4lbjSU zqc-5nEr`g^Kf-${g1fCGJ-~$s*9BhC+78;1AKw7DfM!A+te-?=7Ka`>WnJupPOylJ z{$3e(^-z6Xd1i19b$h<6HnS@9acU8ne(taPKypHP6v<(aWrsNV{B0&{?Q%^>mxy+? z8{8E1=9~Y}%p$opOkT>V&~QxP0tifAxL6%MUaeVbrG$`jc1tDgec*-rt7e zF_bIs%sFu9f^GYhaQnOt|hjjPJP-bcmk|v3t zW`9m?k;4x_b6!W0c$Nbm9J9v!r56qTWP<`ph5b& zb7hgNRM&^m{OPgrLhgypjRmLK{n>%EY+9=GdC~!D^F2yR#%`@cwng6}@Ay&~0n3Hq z!}v~tkzmz~tB|dljrBTi?bW?_Lvi5&fOliqOXZuxS5KAuSu!+i=IzAiE?p+H@Dao(zs6EgBOE125rRh z64?`}Pf%ZV#` zD$l`3cM`kmZ^rc0>6q{p6pXM%y%wnIyrT5?R(%O`@>nwV`Jn$J20sR literal 0 HcmV?d00001 From 2b48ec734a4219a7cf4f947b165b1701538a8a45 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Tue, 1 Jun 2010 20:39:02 +0000 Subject: [PATCH 14/28] Alterando logo do interlegis e alterando graficos do dashbord --- sigi/context_processors.py | 20 +++++++++- sigi/templates/admin/base_site.html | 2 +- .../snippets/modules/charts-convenios.html | 38 +++++++++++++++---- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/sigi/context_processors.py b/sigi/context_processors.py index 9e06722..82b5e46 100644 --- a/sigi/context_processors.py +++ b/sigi/context_processors.py @@ -1,15 +1,22 @@ from sigi.apps.casas.models import CasaLegislativa -from sigi.apps.convenios.models import Convenio +from sigi.apps.convenios.models import Convenio, Projeto def charts_data(request): casas = CasaLegislativa.objects.all() convenios = Convenio.objects.all() + projetos = Projeto.objects.all() + convenios_firmados = convenios.exclude(data_retorno_assinatura=None) num_convenios_firmados = convenios_firmados.count() num_convenios_nao_firmados = convenios.filter(data_retorno_assinatura=None).count() num_casas_nao_aderidas = casas.count() - convenios.exclude(data_adesao=None).count() + # Verifica quantidade de convenios por projeto + convenios_por_projeto = [] + for p in projetos: + convenios_por_projeto.append(convenios_firmados.filter(projeto=p).count()) + num_casas_regiao = [ casas.filter(municipio__uf__regiao='CO').count(), casas.filter(municipio__uf__regiao='NO').count(), @@ -24,6 +31,12 @@ def charts_data(request): convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SD').count(), convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SL').count() ] + + # Verifica qual regiao tem mais convenios e guarda valor para "axis" do grafico de regioes + num_regiao_maior = 0 + for i in num_casas_regiao: + if num_regiao_maior - +

Copyright © 2008–2010 Interlegis. Todos os Direitos Reservados.
É proibido o uso das informações aqui fornecidas fora do âmbito do Interlegis. diff --git a/sigi/templates/snippets/modules/charts-convenios.html b/sigi/templates/snippets/modules/charts-convenios.html index 458d040..0e293ad 100644 --- a/sigi/templates/snippets/modules/charts-convenios.html +++ b/sigi/templates/snippets/modules/charts-convenios.html @@ -1,31 +1,46 @@ {% load charts %} {% chart as convenios %} - {% chart-size 340 160 %} - {% chart-type "pie" %} + {% chart-size 440 160 %} + {% chart-type "pie-3d" %} {% chart-labels convenios_chart_data %} {% chart-legend "Conveniadas" "Não conveniadas" "Não aderidas" %} {% chart-data convenios_chart_data %} + {% chart-colors "A2CD5A,FFB90F,6CA6CD" %} {% endchart %} {% chart as regioes %} - {% chart-size 320 160 %} + {% chart-size 440 160 %} {% chart-type "column-stacked" %} {% chart-bar-width "40" %} {% chart-labels "Centro-O" "Norte" "Nordeste" "Sudeste" "Sul" %} {% chart-data regioes_chart_data.0 regioes_chart_data.1 %} - {% chart-legend "Conveniadas" "Total" %} - {% chart-colors "ff9900,ffc266" %} + {% chart-legend "Conveniadas" "Total" %} + {% axis "left" %} + {% axis-range 0 num_regiao_maior_chart_data%} + {% endaxis %} + {% chart-colors "A2CD5A,FFB90F,6CA6CD" %} {% endchart %} {% chart as equipamentos %} - {% chart-size 340 160 %} - {% chart-type "pie" %} + {% chart-size 440 160 %} + {% chart-type "pie-3d" %} {% chart-labels equipamentos_chart_data %} {% chart-data equipamentos_chart_data %} {% chart-legend "Recebidos" "Não recebidos" %} + {% chart-colors "A2CD5A,FFB90F,6CA6CD" %} {% endchart %} +{% chart as projetos %} + {% chart-size 440 160 %} + {% chart-type "pie-3d" %} + {% chart-labels convenios_por_projeto_chart_data %} + {% chart-data convenios_por_projeto_chart_data %} + {% chart-legend projetos_chart_data %} + {% chart-colors "A2CD5A,FFB90F,6CA6CD" %} +{% endchart %} + +

Convênios

Convênios com as Casas Legislativas

@@ -49,3 +64,12 @@

+ +
+

Convênios

+

Convênios por projeto

+

+ +

+
+ From 62d006603d5554ef1931f458eeddfac184eda821 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Tue, 1 Jun 2010 20:45:27 +0000 Subject: [PATCH 15/28] Corrigindo css --- media/css/base_site.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/css/base_site.css b/media/css/base_site.css index 4159131..800207a 100644 --- a/media/css/base_site.css +++ b/media/css/base_site.css @@ -4,7 +4,7 @@ a:hover { color:#11488d; } /* HEADER */ -#header { background:#003351 url(../images/default-bg3.jpg);} +#header { background:#003351 url(../images/default-bg2.jpg);} #site-name a:hover { text-decoration: none; } #nav-global { From d9c45ca354acb5f4b85897256fc4f5648de881ea Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Tue, 1 Jun 2010 21:15:32 +0000 Subject: [PATCH 16/28] =?UTF-8?q?Removendo=20alguns=20campos=20desnecess?= =?UTF-8?q?=C3=A1rios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sigi/apps/parlamentares/admin.py | 14 ++++++------ sigi/apps/parlamentares/models.py | 38 ++++++++++++++++++------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/sigi/apps/parlamentares/admin.py b/sigi/apps/parlamentares/admin.py index b57b61d..a485074 100644 --- a/sigi/apps/parlamentares/admin.py +++ b/sigi/apps/parlamentares/admin.py @@ -27,27 +27,27 @@ class ParlamentarAdmin(admin.ModelAdmin): (None, { 'fields': ('nome_completo', 'nome_parlamentar', 'sexo'), }), - ('Endereço', { - 'fields': ('logradouro', 'bairro', 'municipio', 'cep'), - }), +# ('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',) +# raw_id_fields = ('municipio',) search_fields = ('nome_completo', 'nome_parlamentar', 'email', - 'pagina_web', 'municipio__nome') + 'pagina_web',) class MandatoAdmin(admin.ModelAdmin): list_display = ('parlamentar', 'legislatura', 'partido', 'inicio_mandato', 'fim_mandato', 'is_afastado') - list_filter = ('is_afastado', 'partido', 'suplencia') + 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} +# radio_fields = {'suplencia': admin.VERTICAL} admin.site.register(Partido, PartidoAdmin) admin.site.register(Parlamentar, ParlamentarAdmin) diff --git a/sigi/apps/parlamentares/models.py b/sigi/apps/parlamentares/models.py index 53eae15..a65de4a 100644 --- a/sigi/apps/parlamentares/models.py +++ b/sigi/apps/parlamentares/models.py @@ -37,21 +37,11 @@ class Parlamentar(models.Model): blank=True, null=True, ) - logradouro = models.CharField(max_length=100, blank=True) - bairro = models.CharField(max_length=40, blank=True) - municipio = models.ForeignKey('contatos.Municipio', blank=True, null=True) - cep = models.CharField( - 'CEP', - max_length=9, - blank=True, - help_text="Formato: XXXXX-XXX." - ) - telefones = generic.GenericRelation('contatos.Telefone') + email = models.EmailField('e-mail', blank=True) pagina_web = models.URLField( u'página web', blank=True, verify_exists=False ) - email = models.EmailField('e-mail', blank=True) class Meta: ordering = ('nome_completo',) @@ -62,6 +52,20 @@ class Parlamentar(models.Model): return self.nome_parlamentar return self.nome_completo + +# logradouro = models.CharField(max_length=100, blank=True) +# bairro = models.CharField(max_length=40, blank=True) +# municipio = models.ForeignKey('contatos.Municipio', blank=True, null=True) +# cep = models.CharField( +# 'CEP', +# max_length=9, +# blank=True, +# help_text="Formato: XXXXX-XXX." +# ) +# telefones = generic.GenericRelation('contatos.Telefone') + + + class Mandato(models.Model): SUPLENCIA_CHOICES = ( ('T', 'Titular'), @@ -77,11 +81,13 @@ class Mandato(models.Model): default=False, help_text=u'Marque caso parlamentar não esteja ativo.' ) - suplencia = models.CharField( - u'suplência', - max_length=1, - choices=SUPLENCIA_CHOICES, - ) + +# suplencia = models.CharField( +# u'suplência', +# max_length=1, +# choices=SUPLENCIA_CHOICES, +# ) + def __unicode__(self): return str(self.id) From 1ce8169b1e7b35715325f267c553b21aaecc7c3f Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Tue, 1 Jun 2010 21:16:27 +0000 Subject: [PATCH 17/28] Adicionando campo parlamentar em casa --- sigi/apps/casas/admin.py | 5 +++-- sigi/apps/casas/models.py | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sigi/apps/casas/admin.py b/sigi/apps/casas/admin.py index d10972c..7fa715f 100644 --- a/sigi/apps/casas/admin.py +++ b/sigi/apps/casas/admin.py @@ -29,7 +29,8 @@ class CasaLegislativaAdmin(admin.ModelAdmin): list_filter = ('tipo', 'municipio') fieldsets = ( (None, { - 'fields': ('nome', 'sigla', 'tipo', 'cnpj', 'observacoes'), + 'fields': ('nome', 'sigla', 'tipo', 'cnpj', 'observacoes', + 'parlamentar'), }), ('Endereço', { 'fields': ('logradouro', 'bairro', 'municipio', 'cep'), @@ -39,7 +40,7 @@ class CasaLegislativaAdmin(admin.ModelAdmin): 'fields': ('email', 'pagina_web', 'foto', 'historico'), }), ) - raw_id_fields = ('municipio',) + raw_id_fields = ('municipio','parlamentar') search_fields = ('nome', 'sigla', 'cnpj', 'logradouro', 'bairro', 'cep', 'municipio__nome', 'municipio__uf__nome', 'municipio__codigo_ibge', 'pagina_web', 'observacoes') diff --git a/sigi/apps/casas/models.py b/sigi/apps/casas/models.py index bd84bd7..35d4a13 100644 --- a/sigi/apps/casas/models.py +++ b/sigi/apps/casas/models.py @@ -2,6 +2,7 @@ from django.db import models from django.contrib.contenttypes import generic from sigi.apps.mesas.models import MesaDiretora, MembroMesaDiretora +from sigi.apps.parlamentares.models import Parlamentar class CasaLegislativa(models.Model): CASA_CHOICES = ( @@ -24,6 +25,7 @@ class CasaLegislativa(models.Model): tipo = models.CharField(max_length=2, choices=CASA_CHOICES, default='CM') cnpj = models.CharField('CNPJ', max_length=32, blank=True) observacoes = models.TextField(u'observações', blank=True) + parlamentar = models.ForeignKey(Parlamentar, null=True, blank=True) logradouro = models.CharField( max_length=100, From 71238edc389aec8cbf969f0f76dd19053994cc49 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Tue, 1 Jun 2010 21:17:44 +0000 Subject: [PATCH 18/28] Adicinando filtros para casas conveniadas e equipadas --- sigi/apps/convenios/admin.py | 5 +++-- sigi/apps/convenios/models.py | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index 75af0e5..f4aac23 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -38,8 +38,9 @@ class ConvenioAdmin(admin.ModelAdmin): actions = ['delete_selected', 'relatorio'] inlines = (AnexosInline, EquipamentoPrevistoInline) list_display = ('id', 'casa_legislativa', - 'num_processo_sf', 'data_adesao', 'projeto') - list_filter = ('projeto','casa_legislativa') + 'num_processo_sf', 'data_adesao', 'projeto', + ) + list_filter = ('projeto','casa_legislativa','conveniada', 'equipada') date_hierarchy = 'data_adesao' ordering = ('-id',) raw_id_fields = ('casa_legislativa',) diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index 60d64ef..54a46fb 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -63,7 +63,15 @@ class Convenio(models.Model): null=True, blank=True, ) - observacao = models.TextField() + observacao = models.TextField(null=True, blank=True) + 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' From 2c775107122c6eca901237fabb7ff0d52afad4b1 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Tue, 1 Jun 2010 21:18:40 +0000 Subject: [PATCH 19/28] =?UTF-8?q?Corrigindo=20script=20de=20migra=C3=A7?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/migracao/migra.py | 105 ++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/etc/migracao/migra.py b/etc/migracao/migra.py index 15c4e43..aa6a23c 100755 --- a/etc/migracao/migra.py +++ b/etc/migracao/migra.py @@ -37,6 +37,7 @@ ERROR_MSG_0 = (' %s[%s]: erro desconhecido! Possível erro de integridade 'necessário.') ERROR_MSG_1 = (' %s[%s]: erro ao inserir item, será necessário inserção ' 'manual.') +OBS_CONVENIO = ('Convênio sem termo de adesão') def migra_assembleias(filename): # identificação das colunas nos arquivo CSV @@ -59,8 +60,8 @@ def migra_assembleias(filename): header = reader.next() for line in reader: - UF = UnidadeFederativa.objects.get(sigla=line[UF_COL]) - municipio = Municipio.objects.get(municipio__codigo_ibge=line[UF_COL], is_capital=True) + uf = UnidadeFederativa.objects.get(sigla=line[UF_COL]) + municipio = Municipio.objects.get(uf=uf, is_capital=True) casa = CasaLegislativa( municipio=municipio, nome=line[NOME_COL], @@ -143,6 +144,10 @@ def migra_casas(filename): except ValueError: print ERROR_MSG_1 % (filename, linenum) continue + parlamentar=None + if(line[PRESIDENTE_COL]): + parlamentar = Parlamentar(nome_completo=line[PRESIDENTE_COL], email=line[EMAIL_PRESIDENTE_COL]) + parlamentar.save() casa = CasaLegislativa( municipio=municipio, nome='Câmara Municipal de ' + line[NOME_COL], @@ -152,11 +157,13 @@ def migra_casas(filename): email=line[EMAIL_COL], pagina_web=line[PAGINA_COL], observacoes=line[OBS_COL], + parlamentar=parlamentar, ) + try: casa.save() except: - print "Erro ao inserir casa" + print "Erro ao inserir casa..." print ERROR_MSG_0 % (filename, linenum) continue @@ -224,9 +231,8 @@ def migra_cnpj(filename): def migra_convenios_casas(filename): """ Será preciso cadastrar no banco os seguintes Projeto: - 1 - Sem Projeto - 2 - Projeto Interlegis - 3 - Programa Piloto de Modernização + 1 - Projeto Interlegis + 2 - Programa Piloto de Modernização """ def get_datetime_obj(data): ldata = data.split('-') @@ -234,6 +240,12 @@ def migra_convenios_casas(filename): return None return datetime(int(ldata[0]), int(ldata[1]), int(ldata[2])) + projeto1 = Projeto(nome="Projeto Interlegis") + projeto1.save() + projeto2 = Projeto(nome="Projeto Piloto de Modernização") + projeto2.save() + + # identificação das colunas no arquivo CSV # No arquivo CSV colunas que contém _100 são do Programa Interlegis COD_IBGE_COL = 1 @@ -247,6 +259,7 @@ def migra_convenios_casas(filename): DATA_PUB_DIARIO = 30 DATA_DEV_VIA_CONV_CM = 32 + DATA_ADESAO_100_COL = 11 DATA_TERMO_ACEITE_100_COL = 22 NUM_CONVENIO_100_COL = 24 @@ -259,12 +272,20 @@ def migra_convenios_casas(filename): reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True) header = reader.next() linenum = 1 + ###Geração de arquivos para análise### + import codecs + f1 = codecs.open('file1.txt','w' , encoding="utf-8") + f1.write(u'Casas que não tem Número Processo Senado Federal\n') + f2 = codecs.open('file2.txt','w', encoding="utf-8") + f2.write(u'Casas que não tem data de adesão e não tem convênio mas recebeu equipamentos\n') + ###### for line in reader: linenum += 1 try: casa = CasaLegislativa.objects.get(municipio__codigo_ibge=line[COD_IBGE_COL]) except CasaLegislativa.DoesNotExist: + print "Erro ao inserir convênio. Casa não existe" print ERROR_MSG_1 % (filename, linenum) continue except CasaLegislativa.MultipleObjectsReturned: @@ -273,14 +294,20 @@ def migra_convenios_casas(filename): except ValueError: print ERROR_MSG_1 % (filename, linenum) continue - if line[DATA_ADESAO_COL]=='1001-01-01':#Sem Projeto - line[DATA_ADESAO_COL]='' + + # Se o convênio não tiver data de adesão mas tiver data retorno assinatura copiar essa data para a data de adesão. + obs = '' + projeto = None + convenio1=None + convenio2=None + if line[DATA_ADESAO_COL]=='1001-01-01' and line[DATA_RETORNO_ASSINATURA].__len__()!=0: + line[DATA_ADESAO_COL] = line[DATA_RETORNO_ASSINATURA] + obs = OBS_CONVENIO + + if line[DATA_ADESAO_COL]!='1001-01-01': projeto = Projeto.objects.get(id=1) - else: - projeto = Projeto.objects.get(id=2) - if(projeto.id!=1 or line[NUM_PROCESSO_SF_COL].__len__()!=0 or - line[NUM_CONVENIO_COL].__len__()!=0): + if projeto: convenio1 = Convenio( casa_legislativa=casa, projeto=projeto, @@ -292,14 +319,23 @@ def migra_convenios_casas(filename): data_termo_aceite=get_datetime_obj(line[DATA_PUB_DIARIO]), data_devolucao_via=get_datetime_obj(line[DATA_DEV_VIA_CONV_CM]), data_postagem_correio=get_datetime_obj(line[DATA_POSTAGEM_CORREIO]), - ) - if line[DATA_ADESAO_100_COL]=='1001-01-01':#Sem Projeto - line[DATA_ADESAO_100_COL]='' - projeto = Projeto.objects.get(id=1) - else: - projeto = Projeto.objects.get(id=3) - if(projeto.id!=1 or line[NUM_PROCESSO_SF_100_COL].__len__()!=0 or - line[NUM_CONVENIO_100_COL].__len__()!=0): + observacao=obs,) + + ###Relatório### + if( (projeto or line[DATA_TERMO_ACEITE_COL]) and line[NUM_PROCESSO_SF_COL].__len__()==0): + f1.write(casa.nome+","+casa.municipio.uf.sigla+"\n") + if(projeto==None and line[DATA_TERMO_ACEITE_COL].__len__()!=0): + f2.write(casa.nome+","+casa.municipio.uf.sigla+"\n") + ###### + projeto=None + obs = '' + if line[DATA_ADESAO_100_COL]=='1001-01-01' and line[DATA_RETORNO_ASSINATURA_100_COL].__len__()!=0: + line[DATA_ADESAO_100_COL] = line[DATA_RETORNO_ASSINATURA_100_COL] + obs = OBS_CONVENIO + if line[DATA_ADESAO_100_COL]!='1001-01-01': + projeto = Projeto.objects.get(id=2) + + if projeto: convenio2 = Convenio( casa_legislativa=casa, projeto=projeto, @@ -309,16 +345,18 @@ def migra_convenios_casas(filename): data_retorno_assinatura=get_datetime_obj(line[DATA_TERMO_ACEITE_100_COL]), data_pub_diario=get_datetime_obj(line[DATA_RETORNO_ASSINATURA_100_COL]), data_termo_aceite=get_datetime_obj(line[DATA_PUB_DIARIO_100_COL]), - # data_devolucao_via=get_datetime_obj(line[DATA_DEV_VIA_CONV_CM]), - # data_postagem_correio=get_datetime_obj(line[DATA_POSTAGEM_CORREIO]), + observacao=obs, ) try: if convenio1: convenio1.save() if convenio2: convenio2.save() except: + print "Erro ao inserir convênio" print ERROR_MSG_0 % (filename, linenum) continue + f1.close() + f2.close() def migra_convenios_assembleias(filename): def get_datetime_obj(data): @@ -334,9 +372,8 @@ def migra_convenios_assembleias(filename): NUM_CONVENIO_COL = 23 NUM_PROCESSO_SF_COL = 26 DATA_RETORNO_ASSINATURA = 27 - DATA_PUB_DIARIO = 39 - DATA_DEV_VIA_CONV_CM = 31 - + DATA_PUB_DIARIO = 29 + reader = csv.reader(open(filename, 'r'), delimiter='|', skipinitialspace=True) header = reader.next() linenum = 1 @@ -344,7 +381,7 @@ def migra_convenios_assembleias(filename): linenum += 1 try: - assembleia = CasaLegislativa.objects.get(municipio__uf__sigla=line[COD_IBGE_COL]) + assembleia = CasaLegislativa.objects.get(municipio__uf__sigla=line[SIGLA_COL], tipo='AL') except CasaLegislativa.DoesNotExist: print ERROR_MSG_1 % (filename, linenum) continue @@ -353,7 +390,7 @@ def migra_convenios_assembleias(filename): except ValueError: print ERROR_MSG_1 % (filename, linenum) continue - projeto = Projeto.object.get(id=2) + projeto = Projeto.objects.get(id=2) convenio = Convenio( casa_legislativa=assembleia, num_processo_sf=line[NUM_PROCESSO_SF_COL], @@ -363,8 +400,6 @@ def migra_convenios_assembleias(filename): data_retorno_assinatura=get_datetime_obj(line[DATA_TERMO_ACEITE_COL]), data_pub_diario=get_datetime_obj(line[DATA_RETORNO_ASSINATURA]), data_termo_aceite=get_datetime_obj(line[DATA_PUB_DIARIO]), - data_devolucao_via=get_datetime_obj(line[DATA_DEV_VIA_CONV_CM]), - data_postagem_correio=get_datetime_obj(line[DATA_POSTAGEM_CORREIO]), ) try: convenio.save() @@ -374,12 +409,12 @@ def migra_convenios_assembleias(filename): if __name__ == '__main__': - print "" - migra_assembleias('assembleias.csv') - print "" - migra_casas('casas.csv') - print "" - migra_cnpj('cnpj.csv') +# print "" +# migra_assembleias('assembleias.csv') +# print "" +# migra_casas('casas.csv') +# print "" +# migra_cnpj('cnpj.csv') print "" migra_convenios_casas('casas.csv') print "" From c848819083d6d5dbd21664da010ff55580e6d9d9 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Mon, 7 Jun 2010 17:35:52 +0000 Subject: [PATCH 20/28] Alterando atributo observacao do convenio de TextField para CharField --- sigi/apps/convenios/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sigi/apps/convenios/models.py b/sigi/apps/convenios/models.py index 54a46fb..3488973 100644 --- a/sigi/apps/convenios/models.py +++ b/sigi/apps/convenios/models.py @@ -63,7 +63,11 @@ class Convenio(models.Model): null=True, blank=True, ) - observacao = models.TextField(null=True, blank=True) + observacao = models.CharField( + null=True, + blank=True, + max_length=100, + ) conveniada = models.BooleanField() equipada = models.BooleanField() From 89199229bd54960add1b449a4b2c31c382425fed Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Mon, 7 Jun 2010 18:08:04 +0000 Subject: [PATCH 21/28] Adicionando verbose_name parlamentar --- sigi/apps/casas/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sigi/apps/casas/models.py b/sigi/apps/casas/models.py index 35d4a13..84f70b9 100644 --- a/sigi/apps/casas/models.py +++ b/sigi/apps/casas/models.py @@ -25,7 +25,7 @@ class CasaLegislativa(models.Model): tipo = models.CharField(max_length=2, choices=CASA_CHOICES, default='CM') cnpj = models.CharField('CNPJ', max_length=32, blank=True) observacoes = models.TextField(u'observações', blank=True) - parlamentar = models.ForeignKey(Parlamentar, null=True, blank=True) + parlamentar = models.ForeignKey(Parlamentar, null=True, blank=True, verbose_name="Presidente") logradouro = models.CharField( max_length=100, From 1bfec4470f9f90bbc09cb8002b11d2e7ae0ecbe4 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Mon, 7 Jun 2010 20:16:43 +0000 Subject: [PATCH 22/28] Alterando grafico de convenios com as casas --- sigi/context_processors.py | 5 +++-- sigi/templates/snippets/modules/charts-convenios.html | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sigi/context_processors.py b/sigi/context_processors.py index 82b5e46..6deb478 100644 --- a/sigi/context_processors.py +++ b/sigi/context_processors.py @@ -10,7 +10,8 @@ def charts_data(request): num_convenios_firmados = convenios_firmados.count() num_convenios_nao_firmados = convenios.filter(data_retorno_assinatura=None).count() - num_casas_nao_aderidas = casas.count() - convenios.exclude(data_adesao=None).count() + num_casas_nao_aderidas = CasaLegislativa.objects.filter(convenio=None).count() + #num_casas_nao_aderidas = casas.count() - convenios.exclude(data_adesao=None).count() # Verifica quantidade de convenios por projeto convenios_por_projeto = [] @@ -32,7 +33,7 @@ def charts_data(request): convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SL').count() ] - # Verifica qual regiao tem mais convenios e guarda valor para "axis" do grafico de regioes + # Verifica qual regiao tem mais convenios e guarda valor para "axis left" do grafico de regioes num_regiao_maior = 0 for i in num_casas_regiao: if num_regiao_maior Date: Wed, 9 Jun 2010 20:59:10 +0000 Subject: [PATCH 23/28] Alterando grafico de regioes do dashboard e grafico de convenios. --- sigi/context_processors.py | 45 +++++++++++++------ .../snippets/modules/charts-convenios.html | 4 +- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/sigi/context_processors.py b/sigi/context_processors.py index 6deb478..fa454f7 100644 --- a/sigi/context_processors.py +++ b/sigi/context_processors.py @@ -1,5 +1,6 @@ from sigi.apps.casas.models import CasaLegislativa from sigi.apps.convenios.models import Convenio, Projeto +from sigi.apps.contatos.models import UnidadeFederativa def charts_data(request): casas = CasaLegislativa.objects.all() @@ -10,7 +11,7 @@ def charts_data(request): num_convenios_firmados = convenios_firmados.count() num_convenios_nao_firmados = convenios.filter(data_retorno_assinatura=None).count() - num_casas_nao_aderidas = CasaLegislativa.objects.filter(convenio=None).count() + #num_casas_nao_aderidas = CasaLegislativa.objects.filter(convenio=None).count() #num_casas_nao_aderidas = casas.count() - convenios.exclude(data_adesao=None).count() # Verifica quantidade de convenios por projeto @@ -25,13 +26,33 @@ def charts_data(request): casas.filter(municipio__uf__regiao='SD').count(), casas.filter(municipio__uf__regiao='SL').count() ] - num_convenios_firmados_regiao = [ - convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='CO').count(), - convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='NO').count(), - convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='NE').count(), - convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SD').count(), - convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SL').count() - ] + #num_convenios_firmados_regiao = [ + # convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='CO').count(), + # convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='NO').count(), + # convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='NE').count(), + # convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SD').count(), + # convenios_firmados.filter(casa_legislativa__municipio__uf__regiao='SL').count() + #] + + REGIAO_CHOICES = ('CO','NO','NE','SD','SL') + + # Busca numero de casas conveniadas por regiao + num_casas_conveniadas_regiao = [] + for regiao in REGIAO_CHOICES: + num_casas_conveniadas_regiao.append( + CasaLegislativa.objects.filter( + convenio__casa_legislativa__municipio__uf__regiao=regiao + ).exclude( + convenio__data_retorno_assinatura=None + ).distinct().count() + ) + + # Busca numero de casas sem convenio por regiao + num_casas_sem_convenio_regiao = [] + for i in range(len(num_casas_regiao)): + num_casas_sem_convenio_regiao.append( + num_casas_regiao[i] - num_casas_conveniadas_regiao[i] + ) # Verifica qual regiao tem mais convenios e guarda valor para "axis left" do grafico de regioes num_regiao_maior = 0 @@ -43,11 +64,9 @@ def charts_data(request): equip_recebidos = convenios.exclude(data_termo_aceite=None).count() return { - 'regioes_chart_data': [num_convenios_firmados_regiao, num_casas_regiao], - 'convenios_chart_data': [num_convenios_firmados, num_convenios_nao_firmados, - num_casas_nao_aderidas], + 'regioes_chart_data': [num_casas_conveniadas_regiao, num_casas_sem_convenio_regiao, num_regiao_maior], + 'convenios_chart_data': [num_convenios_firmados, num_convenios_nao_firmados,], 'equipamentos_chart_data': [equip_recebidos, equip_n_recebidos], 'projetos_chart_data': projetos, - 'convenios_por_projeto_chart_data': convenios_por_projeto, - 'num_regiao_maior_chart_data': num_regiao_maior, + 'convenios_por_projeto_chart_data': convenios_por_projeto, } diff --git a/sigi/templates/snippets/modules/charts-convenios.html b/sigi/templates/snippets/modules/charts-convenios.html index 9e6e707..e5f8ca2 100644 --- a/sigi/templates/snippets/modules/charts-convenios.html +++ b/sigi/templates/snippets/modules/charts-convenios.html @@ -4,7 +4,7 @@ {% chart-size 440 160 %} {% chart-type "pie-3d" %} {% chart-labels convenios_chart_data %} - {% chart-legend "Convênios firmados" "Convênios pendentes" "Casas sem convênio" %} + {% chart-legend "Convênios firmados" "Convênios pendentes" %} {% chart-data convenios_chart_data %} {% chart-colors "A2CD5A,FFB90F,6CA6CD" %} {% endchart %} @@ -17,7 +17,7 @@ {% chart-data regioes_chart_data.0 regioes_chart_data.1 %} {% chart-legend "Conveniadas" "Total" %} {% axis "left" %} - {% axis-range 0 num_regiao_maior_chart_data%} + {% axis-range 0 regioes_chart_data.2 %} {% endaxis %} {% chart-colors "A2CD5A,FFB90F,6CA6CD" %} {% endchart %} From ff92f58b74dec2a6343dbc931b93af30b712bb74 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Wed, 9 Jun 2010 21:01:14 +0000 Subject: [PATCH 24/28] Acrescentando geracao de etiquetas ao action de casas e alterando action de convenio --- sigi/apps/casas/admin.py | 11 +++++++++++ sigi/apps/convenios/admin.py | 17 ++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/sigi/apps/casas/admin.py b/sigi/apps/casas/admin.py index 7fa715f..f46e7b7 100644 --- a/sigi/apps/casas/admin.py +++ b/sigi/apps/casas/admin.py @@ -5,6 +5,9 @@ from sigi.apps.casas.forms import CasaLegislativaForm from sigi.apps.casas.models import CasaLegislativa from sigi.apps.contatos.models import Contato, Telefone from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo +from django.http import HttpResponse, HttpResponseRedirect +from sigi.apps.casas.reports import CasasLegislativasLabels +from geraldo.generators import PDFGenerator class ContatosInline(generic.GenericTabularInline): model = Contato @@ -23,6 +26,7 @@ class CasaLegislativaAdmin(admin.ModelAdmin): form = CasaLegislativaForm change_form_template = 'casas/change_form.html' change_list_template = 'casas/change_list.html' + actions = ['delete_selected','etiqueta'] inlines = (TelefonesInline, ContatosInline, ConveniosInline) list_display = ('nome', 'email', 'pagina_web', 'municipio') list_display_links = ('nome',) @@ -51,4 +55,11 @@ class CasaLegislativaAdmin(admin.ModelAdmin): extra_context={'query_str': '?' + request.META['QUERY_STRING']} ) + def etiqueta(modelAdmin,request,queryset): + response = HttpResponse(mimetype='application/pdf') + report = CasasLegislativasLabels(queryset=queryset) + report.generate_by(PDFGenerator, filename=response) + return response + etiqueta.short_description = "Gerar etiqueta(s) da(s) casa(s) selecionada(s)" + admin.site.register(CasaLegislativa, CasaLegislativaAdmin) diff --git a/sigi/apps/convenios/admin.py b/sigi/apps/convenios/admin.py index f4aac23..1ded868 100644 --- a/sigi/apps/convenios/admin.py +++ b/sigi/apps/convenios/admin.py @@ -3,7 +3,9 @@ from django.contrib import admin from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo from sigi.apps.casas.models import CasaLegislativa from sigi.apps.servicos.models import Servico -from django.http import HttpResponseRedirect +from django.http import HttpResponse, HttpResponseRedirect +from sigi.apps.convenios.reports import ConvenioReport +from geraldo.generators import PDFGenerator class AnexosInline(admin.TabularInline): model = Anexo @@ -53,10 +55,15 @@ class ConvenioAdmin(admin.ModelAdmin): extra_context={'query_str': '?' + request.META['QUERY_STRING']} ) def relatorio(modeladmin, request, queryset): - selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) - print selected - return HttpResponseRedirect("reports/?ids=%s"%(",".join(selected))) - relatorio.short_description = 'Selecione para gerar relatorio' + response = HttpResponse(mimetype='application/pdf') + report = ConvenioReport(queryset=queryset) + report.generate_by(PDFGenerator, filename=response) + return response + #selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) + #print selected + #return HttpResponseRedirect("reports/?ids=%s"%(",".join(selected))) + #relatorio.short_description = 'Selecione para gerar relatorio' + relatorio.short_description = 'Gerar relatorio dos convenios selecionados' class EquipamentoPrevistoAdmin(admin.ModelAdmin): From 086547e4fa46da21dbdb61c77c5453ca8107fcb3 Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Fri, 11 Jun 2010 15:35:52 +0000 Subject: [PATCH 25/28] Reorganizando e corrigindo filtros personalizados --- sigi/admin/filterspecs.py | 65 ++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/sigi/admin/filterspecs.py b/sigi/admin/filterspecs.py index 74a67d7..57608ae 100644 --- a/sigi/admin/filterspecs.py +++ b/sigi/admin/filterspecs.py @@ -3,6 +3,7 @@ from django.utils.encoding import smart_unicode from django.utils.safestring import mark_safe from django.utils.translation import ugettext as _ from sigi.apps.contatos.models import UnidadeFederativa +from abc import ABCMeta class AlphabeticFilterSpec(ChoicesFilterSpec): """ @@ -39,7 +40,28 @@ class AlphabeticFilterSpec(ChoicesFilterSpec): FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'alphabetic_filter', False), AlphabeticFilterSpec)) -class MunicipioUFFilterSpec(ChoicesFilterSpec): +class UFFilterSpec(ChoicesFilterSpec): + """ + This is an abstract class and customs filters by 'Uf' have to extend this class. + """ + __metaclass__ = ABCMeta + def __init__(self, f, request, params, model, model_admin): + super(UFFilterSpec, self).__init__(f, request, params, model, + model_admin) + + def choices(self, cl): + yield {'selected': self.lookup_val is None, + 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), + 'display': _('All')} + for val in self.lookup_choices: + yield {'selected': smart_unicode(val.codigo_ibge) == self.lookup_val, + 'query_string': cl.get_query_string({self.lookup_kwarg: val.codigo_ibge}), + 'display': val.nome} + def title(self): + return _('UF') % \ + {'field_name': self.field.verbose_name} + +class MunicipioUFFilterSpec(UFFilterSpec): """ Usage: @@ -58,57 +80,30 @@ class MunicipioUFFilterSpec(ChoicesFilterSpec): self.lookup_val = request.GET.get(self.lookup_kwarg, None) self.lookup_choices = UnidadeFederativa.objects.all().order_by('nome') - def choices(self, cl): - yield {'selected': self.lookup_val is None, - 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), - 'display': _('All')} - for val in self.lookup_choices: - yield {'selected': smart_unicode(val.codigo_ibge) == self.lookup_val, - 'query_string': cl.get_query_string({self.lookup_kwarg: val.codigo_ibge}), - 'display': val.nome} - def title(self): - return _('UF') % \ - {'field_name': self.field.verbose_name} # registering the filter FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'uf_filter', False), - MunicipioUFFilterSpec)) + MunicipioUFFilterSpec)) -class ConvenioUFFilterSpec(ChoicesFilterSpec): +class ConvenioUFFilterSpec(UFFilterSpec): """ Usage: - municipio.uf_filter = True + my_casa_legislativa_field.convenio_uf_filter = True On Django 1.3 you will can specify a lookup on admin filters. Example: - list_filter = ('municipio__uf',) + list_filter = ('casa_legislativa__municipio__uf',) """ - def __init__(self, f, request, params, model, model_admin): - super(ConvenioUFFilterSpec, self).__init__(f, request, params, model, - model_admin) + super(ConvenioUFFilterSpec, self).__init__(f, request, params, model, model_admin) self.lookup_kwarg = '%s__municipio__uf__codigo_ibge__exact' % f.name self.lookup_val = request.GET.get(self.lookup_kwarg, None) self.lookup_choices = UnidadeFederativa.objects.all().order_by('nome') - def choices(self, cl): - yield {'selected': self.lookup_val is None, - 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), - 'display': _('All')} - for val in self.lookup_choices: - yield {'selected': smart_unicode(val.codigo_ibge) == self.lookup_val, - 'query_string': cl.get_query_string({self.lookup_kwarg: val.codigo_ibge}), - 'display': val.nome} - def title(self): - return _('UF') % \ - {'field_name': self.field.verbose_name} - -# registering the filter -FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'uf_filter', False), - ConvenioUFFilterSpec)) - +FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'convenio_uf_filter', False), +ConvenioUFFilterSpec)) class RangeValuesFilterSpec(FilterSpec): """ From 5d7d0f5b525e14665c6f2d3187987cd183fa2a3c Mon Sep 17 00:00:00 2001 From: "Camilo Carlos (Estagiario)" Date: Fri, 18 Jun 2010 13:08:59 +0000 Subject: [PATCH 26/28] Adicionando relatorio sobre dados estatisticos por regiao --- sigi/apps/convenios/reports.py | 46 +++++++++++++++++++++++++++++++++- sigi/apps/convenios/views.py | 36 +++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/sigi/apps/convenios/reports.py b/sigi/apps/convenios/reports.py index 40cb180..b2625a1 100644 --- a/sigi/apps/convenios/reports.py +++ b/sigi/apps/convenios/reports.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label +from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label, FIELD_ACTION_SUM, FIELD_ACTION_COUNT from reportlab.lib.units import cm class CasasAderidasReport(object): pass @@ -40,3 +40,47 @@ class ConvenioReport(Report): ObjectValue(attribute_name='data_adesao', left=10*cm) ] border = {'bottom': True} + +class ConvenioReportRegiao(Report): + title = u'Relatório dos Convênios por Região' + author = u'Interlegis' + class band_page_header(ReportBand): + elements = [ + Label( + text="Região", left=0*cm + ), + Label( + text="Quantidade Casas", left=3*cm, + ), + Label( + text="Quantidade Casas Conveniadas", left=6*cm + ), + Label( + text="Porcentagem Casas Conveniadas", left=15*cm + ), + ] + class band_detail(DetailBand): + height = 0.5*cm + elements=[ + ObjectValue(attribute_name='regiao', left=0*cm, ), + ObjectValue(attribute_name='casas', left=3*cm,), + ObjectValue(attribute_name='casas_conveniadas', left=6*cm), + ObjectValue(attribute_name='porc_casas_conveniadas', left=15*cm), + ] + border = {'bottom': True} + class band_summary(ReportBand): + elements = [ + Label(text="Total", top=0.1*cm, left=0), + ObjectValue(attribute_name='casas', action=FIELD_ACTION_SUM, left=3*cm, top=0.1*cm), + ObjectValue(attribute_name='casas_conveniadas', left=6*cm, action=FIELD_ACTION_SUM), + ] + borders = {'top':True} + child_bands = [ + ReportBand( + height = 0.6*cm, + elements = [ + Label(text="Total",), + ObjectValue(attribute_name='casas', action=FIELD_ACTION_COUNT,) + ] + ), + ] diff --git a/sigi/apps/convenios/views.py b/sigi/apps/convenios/views.py index 352315b..42c936e 100644 --- a/sigi/apps/convenios/views.py +++ b/sigi/apps/convenios/views.py @@ -1,7 +1,9 @@ from django.http import HttpResponse, HttpResponseRedirect from geraldo.generators import PDFGenerator from sigi.apps.convenios.models import Convenio -from sigi.apps.convenios.reports import ConvenioReport +from sigi.apps.convenios.reports import ConvenioReport, ConvenioReportRegiao +from sigi.apps.casas.models import CasaLegislativa + def report(request, id=None): qs = Convenio.objects.all() @@ -25,3 +27,35 @@ def report(request, id=None): report = ConvenioReport(queryset=qs) report.generate_by(PDFGenerator, filename=response) return response + +class Relatorios(object): + def __init__(self, regiao, casas, casas_conveniadas): + self.regiao = regiao + self.casas = casas + self.casas_conveniadas = casas_conveniadas + if(casas_conveniadas!=0): + self.porc_casas_conveniadas = float(casas_conveniadas)/float(casas)*100 + else: + self.porc_casas_conveniadas = 0 + +def reportRegiao(request): + REGIAO_CHOICES = ( + ('SL', 'Sul'), + ('SD', 'Sudeste'), + ('CO', 'Centro-Oeste'), + ('NE', 'Nordeste'), + ('NO', 'Norte'), + ) + relatorio = [] + for casa in REGIAO_CHOICES: + casasSD = CasaLegislativa.objects.filter(municipio__uf__regiao=casa[0]) + casasConvSD = CasaLegislativa.objects.filter(convenio__casa_legislativa__municipio__uf__regiao=casa[0]).distinct() + + relatorio.append(Relatorios(casa[1], casasSD.count(), + casasConvSD.count())) + + response = HttpResponse(mimetype='application/pdf') + relatorio = ConvenioReportRegiao(queryset=relatorio) + relatorio.generate_by(PDFGenerator, filename=response) + return response + From 2d3943414c9690ca2974da9084814e001f484545 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Fri, 18 Jun 2010 20:45:11 +0000 Subject: [PATCH 27/28] Alterando layout do Relatorio --- sigi/apps/convenios/reports.py | 73 ++++++++++++++++++++++++++++------ sigi/apps/convenios/views.py | 2 +- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/sigi/apps/convenios/reports.py b/sigi/apps/convenios/reports.py index b2625a1..6b3f4ea 100644 --- a/sigi/apps/convenios/reports.py +++ b/sigi/apps/convenios/reports.py @@ -1,6 +1,14 @@ # -*- coding: utf-8 -*- -from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label, FIELD_ACTION_SUM, FIELD_ACTION_COUNT +from operator import attrgetter +from geraldo import Report, ReportBand, ObjectValue, DetailBand, Label, \ + landscape,SystemField, BAND_WIDTH,ReportGroup, \ + FIELD_ACTION_SUM, FIELD_ACTION_COUNT + + from reportlab.lib.units import cm +from reportlab.lib.pagesizes import A4 +from reportlab.lib.enums import TA_CENTER, TA_RIGHT + class CasasAderidasReport(object): pass @@ -14,32 +22,70 @@ class SemEquipamentosReport(object): pass class ConvenioReport(Report): title = u'Relatórios dos Convênios' - author = u'Interlegis' + #author = u'Interlegis' + print_if_empty = True + page_size = A4#landscape(A4) + class band_page_header(ReportBand): + height = 1.3*cm + elements = [ + SystemField( + expression='%(report_title)s',top=0.1*cm,left=0,width=BAND_WIDTH, + style={'fontName': 'Helvetica-Bold','fontSize':14, 'alignment': TA_CENTER} + ), + SystemField(expression=u'Página %(page_number)d de %(page_count)d', top=0.1*cm, + width=BAND_WIDTH, style={'alignment': TA_RIGHT} + ), Label( - text="ID", left=0.5*cm + text="Nº Processo", left=0.5*cm, top=0.8*cm ), Label( - text="Nº Processo", left=3*cm + text="Nome", left=3*cm, top=0.8*cm ), Label( - text="Nome", left=5*cm + text="Data Adesão", left=7*cm, top=0.8*cm ), Label( - text="Data Adesão", left=10*cm + text="Projeto", left=10*cm, top=0.8*cm ), ] - #borders = {'bottom': True} + borders = {'bottom': True} + + class band_page_footer(ReportBand): + height = 0.5*cm + + elements = [ + Label(text='Interlegis', top=0.1*cm), + SystemField(expression=u'Impresso em %(now:%d/%m/%Y)s às %(now:%H:%M)s', top=0.1*cm, + width=BAND_WIDTH, style={'alignment': TA_RIGHT}), + ] + borders = {'top': True} + class band_detail(DetailBand): -# height = 0.5*cm + height = 0.5*cm elements=[ - ObjectValue(attribute_name='id', left=0.5*cm), - ObjectValue(attribute_name='num_processo_sf', left=3*cm), - ObjectValue(attribute_name='casa_legislativa', left=5*cm), - ObjectValue(attribute_name='data_adesao', left=10*cm) + ObjectValue(attribute_name='num_processo_sf', left=0.5*cm), + ObjectValue(attribute_name='casa_legislativa', left=3*cm), + ObjectValue(attribute_name='data_adesao', left=7*cm), + ObjectValue(attribute_name='projeto', left=10*cm) ] - border = {'bottom': True} + #border = {'bottom': True} + + 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.regiao) + ) + ], + borders={'bottom': True}, + ) + ) + ] + class ConvenioReportRegiao(Report): title = u'Relatório dos Convênios por Região' @@ -68,6 +114,7 @@ class ConvenioReportRegiao(Report): ObjectValue(attribute_name='porc_casas_conveniadas', left=15*cm), ] border = {'bottom': True} + class band_summary(ReportBand): elements = [ Label(text="Total", top=0.1*cm, left=0), diff --git a/sigi/apps/convenios/views.py b/sigi/apps/convenios/views.py index 42c936e..5bb0bbc 100644 --- a/sigi/apps/convenios/views.py +++ b/sigi/apps/convenios/views.py @@ -24,7 +24,7 @@ def report(request, id=None): if not qs: return HttpResponseRedirect('../') response = HttpResponse(mimetype='application/pdf') - report = ConvenioReport(queryset=qs) + report = ConvenioReport(queryset=qs.order_by('casa_legislativa')) report.generate_by(PDFGenerator, filename=response) return response From e1e4153b5350feeb3b02abf72d0660c0b929ad89 Mon Sep 17 00:00:00 2001 From: "Starlone (Estagiario)" Date: Tue, 29 Jun 2010 18:16:43 +0000 Subject: [PATCH 28/28] Adicionando logo do senado --- media/images/logo-senado.png | Bin 0 -> 30326 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 media/images/logo-senado.png diff --git a/media/images/logo-senado.png b/media/images/logo-senado.png new file mode 100644 index 0000000000000000000000000000000000000000..bee0adad6e79af9ce0e3c5b960fed10388b91c6e GIT binary patch literal 30326 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

D+_{Kn5N<|%;UYQ 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 bk{Y(76euZoqGRFbF>GYS4bqmc76 literal 0 HcmV?d00001