Browse Source

Merge branch 'stable/2.2' of https://github.com/interlegis/sigi into new_sigi

new_sigi^2
Lude Ribeiro 3 years ago
parent
commit
2e7851b317
  1. 19
      sigi/apps/casas/admin.py
  2. 13
      sigi/apps/casas/models.py
  3. 18
      sigi/apps/convenios/admin.py
  4. 20
      sigi/apps/convenios/migrations/0017_convenio_id_contrato_gescon.py
  5. 21
      sigi/apps/convenios/migrations/0018_auto_20211208_1256.py
  6. 18
      sigi/apps/convenios/models.py
  7. 20
      sigi/apps/convenios/reports.py
  8. 9
      sigi/apps/eventos/admin.py
  9. 21
      sigi/apps/eventos/migrations/0014_auto_20211124_0736.py
  10. 29
      sigi/apps/eventos/migrations/0015_anexo.py
  11. 26
      sigi/apps/eventos/models.py
  12. 2
      sigi/apps/eventos/templates/eventos/declaracao_pdf.html
  13. 2
      sigi/apps/metas/templates/metas/openmap.html
  14. 4
      sigi/apps/metas/templatetags/mapa_tags.py
  15. 2
      sigi/apps/metas/views.py
  16. 49
      sigi/apps/servicos/admin.py
  17. 4
      sigi/apps/servicos/templates/admin/servicos/servico/change_list.html
  18. 33
      sigi/apps/servicos/templates/servico/change_list.html
  19. 100
      sigi/apps/servicos/templates/servicos/carrinho.html
  20. 4
      sigi/apps/servicos/urls.py
  21. 194
      sigi/apps/servicos/views.py
  22. 14
      sigi/apps/servidores/models.py
  23. 1
      sigi/settings/base.py
  24. 8
      templates/base_report.html

19
sigi/apps/casas/admin.py

@ -374,6 +374,23 @@ class ServicoFilter(admin.SimpleListFilter):
return queryset.distinct('municipio__uf__nome', 'nome') return queryset.distinct('municipio__uf__nome', 'nome')
class ServicoAtivoFilter(admin.SimpleListFilter):
title = _(u"Serviço ativo")
parameter_name = 'ativo'
def lookups(self, request, model_admin):
return (
('ativo', _(u"Ativo")),
('desativado', _(u"Desativado")),
)
def queryset(self, request, queryset):
if self.value() is not None:
if self.value() == 'ativo':
queryset = queryset.filter(servico__data_desativacao__isnull=True)
else:
queryset = queryset.filter(servico__data_desativacao__isnull=False)
return queryset
@admin.register(Orgao) @admin.register(Orgao)
class OrgaoAdmin(ImageCroppingMixin, BaseModelAdmin): class OrgaoAdmin(ImageCroppingMixin, BaseModelAdmin):
form = OrgaoForm form = OrgaoForm
@ -384,7 +401,7 @@ class OrgaoAdmin(ImageCroppingMixin, BaseModelAdmin):
'get_servicos') 'get_servicos')
list_display_links = ('sigla', 'nome',) list_display_links = ('sigla', 'nome',)
list_filter = ('tipo', ('gerentes_interlegis', GerentesInterlegisFilter), list_filter = ('tipo', ('gerentes_interlegis', GerentesInterlegisFilter),
'municipio__uf__nome', ConvenioFilter, ExcluirConvenioFilter, ServicoFilter, 'municipio__uf__nome', ConvenioFilter, ServicoAtivoFilter, ExcluirConvenioFilter, ServicoFilter,
'inclusao_digital',) 'inclusao_digital',)
ordering = ('municipio__uf__nome', 'nome') ordering = ('municipio__uf__nome', 'nome')
queryset = queryset_ascii queryset = queryset_ascii

13
sigi/apps/casas/models.py

@ -194,6 +194,19 @@ class Orgao(models.Model):
return self.funcionario_set.get(setor='presidente') return self.funcionario_set.get(setor='presidente')
except Funcionario.DoesNotExist: except Funcionario.DoesNotExist:
return None return None
@property
def contato_interlegis(self):
""" Link para acessar diretamente o contato do presidente da casa
Util para relatorios antigos
"""
try:
if self.funcionario_set.filter(setor='contato_interlegis').count() > 1:
return self.funcionario_set.filter(setor='contato_interlegis')[0]
else:
return self.funcionario_set.get(setor='contato_interlegis')
except Funcionario.DoesNotExist:
return None
@property @property
def total_parlamentares(self): def total_parlamentares(self):

18
sigi/apps/convenios/admin.py

@ -62,15 +62,15 @@ class ConvenioAdmin(BaseModelAdmin):
'data_pub_diario',)} 'data_pub_diario',)}
), ),
(_(u'Gescon'), (_(u'Gescon'),
{'fields': ('atualizacao_gescon', 'observacao_gescon',)} {'fields': ('atualizacao_gescon', 'observacao_gescon', 'link_gescon')}
), ),
) )
readonly_fields = ('data_sigi', 'atualizacao_gescon', 'observacao_gescon',) readonly_fields = ('data_sigi', 'atualizacao_gescon', 'observacao_gescon', 'link_gescon')
actions = ['adicionar_convenios'] actions = ['adicionar_convenios']
inlines = (AnexosInline,) inlines = (AnexosInline,)
list_display = ('num_convenio', 'casa_legislativa', 'get_uf', list_display = ('num_convenio', 'projeto','casa_legislativa', 'get_uf',
'status_convenio', 'link_sigad', 'data_retorno_assinatura', 'status_convenio', 'link_sigad', 'data_retorno_assinatura',
'data_termino_vigencia', 'projeto',) 'data_termino_vigencia',)
list_display_links = ('num_convenio', 'casa_legislativa',) list_display_links = ('num_convenio', 'casa_legislativa',)
list_filter = (('casa_legislativa__gerentes_interlegis', list_filter = (('casa_legislativa__gerentes_interlegis',
GerentesInterlegisFilter), 'projeto', GerentesInterlegisFilter), 'projeto',
@ -115,6 +115,16 @@ class ConvenioAdmin(BaseModelAdmin):
link_sigad.short_description = _("Processo no Senado") link_sigad.short_description = _("Processo no Senado")
link_sigad.allow_tags = True link_sigad.allow_tags = True
def link_gescon(self, obj):
if not obj.id_contrato_gescon:
return u""
return (
u"<a href='https://adm.senado.gov.br/gestao-contratos/api/"
u"contratos/buscaTexto/{id}'>https://adm.senado.gov.br/"
u"gestao-contratos/api/{id}</a>").format(id=obj.id_contrato_gescon)
link_gescon.short_description = _("Download MINUTA ASSINADA do Gescon")
link_gescon.allow_tags = True
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
from sigi.apps.convenios.views import normaliza_data from sigi.apps.convenios.views import normaliza_data
request.GET._mutable = True request.GET._mutable = True

20
sigi/apps/convenios/migrations/0017_convenio_id_contrato_gescon.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('convenios', '0016_auto_20210909_0732'),
]
operations = [
migrations.AddField(
model_name='convenio',
name='id_contrato_gescon',
field=models.CharField(default=b'', verbose_name='ID do contrato no Gescon', max_length=20, editable=False, blank=True),
preserve_default=True,
),
]

21
sigi/apps/convenios/migrations/0018_auto_20211208_1256.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('convenios', '0017_convenio_id_contrato_gescon'),
]
operations = [
migrations.AlterField(
model_name='convenio',
name='projeto',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, verbose_name='Tipo de Convenio', to='convenios.Projeto'),
preserve_default=True,
),
]

18
sigi/apps/convenios/models.py

@ -57,6 +57,7 @@ class Convenio(models.Model):
projeto = models.ForeignKey( projeto = models.ForeignKey(
Projeto, Projeto,
on_delete=models.PROTECT, on_delete=models.PROTECT,
verbose_name=_(u'Tipo de Convenio')
) )
# numero designado pelo Senado Federal para o convênio # numero designado pelo Senado Federal para o convênio
num_processo_sf = models.CharField( num_processo_sf = models.CharField(
@ -71,6 +72,13 @@ class Convenio(models.Model):
max_length=10, max_length=10,
blank=True blank=True
) )
id_contrato_gescon = models.CharField(
_(u"ID do contrato no Gescon"),
max_length=20,
blank=True,
default="",
editable=False
)
data_sigi = models.DateField( data_sigi = models.DateField(
_(u"data de cadastro no SIGI"), _(u"data de cadastro no SIGI"),
blank=True, blank=True,
@ -504,7 +512,7 @@ class Gescon(models.Model):
self.add_message( self.add_message(
_(u"\tErro ao acessar {url}: {errmsg}").format( _(u"\tErro ao acessar {url}: {errmsg}").format(
url=url, url=url,
errmsg=str(e) errmsg=e.message.decode("utf8")
) )
) )
continue continue
@ -734,6 +742,12 @@ class Gescon(models.Model):
'terminoVigencia' 'terminoVigencia'
] ]
convenio.data_pub_diario = contrato['publicacao'] convenio.data_pub_diario = contrato['publicacao']
if contrato['codTextoContrato']:
convenio.id_contrato_gescon = contrato[
'codTextoContrato'
]
else:
convenio.id_contrato_gescon = ""
try: try:
convenio.save() convenio.save()
@ -748,7 +762,7 @@ class Gescon(models.Model):
convenio._meta.model_name), convenio._meta.model_name),
args=[convenio.id] args=[convenio.id]
), ),
errmsg=str(e) errmsg=e.message.decode("utf8")
) )
) )
erros += 1 erros += 1

20
sigi/apps/convenios/reports.py

@ -54,19 +54,19 @@ class ConvenioReport(ReportDefault):
), ),
Label( Label(
text=_(u"Projeto"), text=_(u"Projeto"),
left=label_left[5] * cm, left=label_left[3] * cm,
top=label_top + 0.4 * cm, top=label_top + 0.4 * cm,
width=2 * cm, width=2 * cm,
), ),
Label( Label(
text=_(u"Data do Convênio"), text=_(u"Data do Convênio"),
left=label_left[3] * cm, left=label_left[4] * cm,
top=label_top, top=label_top,
width=2 * cm, width=2 * cm,
), ),
Label( Label(
text=_(u"Data de Publicação"), text=_(u"Data de Publicação"),
left=label_left[4] * cm, left=label_left[5] * cm,
top=label_top, top=label_top,
width=2 * cm, width=2 * cm,
), ),
@ -100,17 +100,17 @@ class ConvenioReport(ReportDefault):
), ),
ObjectValue( ObjectValue(
attribute_name='projeto.sigla', attribute_name='projeto.sigla',
left=label_left[5] * cm left=label_left[3] * cm
), ),
ObjectValue( ObjectValue(
attribute_name='data_retorno_assinatura', attribute_name='data_retorno_assinatura',
left=label_left[3] * cm, left=label_left[4] * cm,
get_value=lambda instance: get_value=lambda instance:
instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura is not None else '-' instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura is not None else '-'
), ),
ObjectValue( ObjectValue(
attribute_name='data_pub_diario', attribute_name='data_pub_diario',
left=label_left[4] * cm, left=label_left[5] * cm,
get_value=lambda instance: get_value=lambda instance:
instance.data_pub_diario.strftime('%d/%m/%Y') if instance.data_pub_diario is not None else '-' instance.data_pub_diario.strftime('%d/%m/%Y') if instance.data_pub_diario is not None else '-'
), ),
@ -163,13 +163,13 @@ class ConvenioReportSemAceite(ConvenioReport):
), ),
Label( Label(
text=_(u"Projeto"), text=_(u"Projeto"),
left=label_left[4] * cm, left=label_left[3] * cm,
top=label_top, top=label_top,
width=2 * cm, width=2 * cm,
), ),
Label( Label(
text=_(u"Data do Convênio"), text=_(u"Data do Convênio"),
left=label_left[3] * cm, left=label_left[4] * cm,
top=label_top, top=label_top,
width=2 * cm, width=2 * cm,
), ),
@ -200,11 +200,11 @@ class ConvenioReportSemAceite(ConvenioReport):
), ),
ObjectValue( ObjectValue(
attribute_name='projeto.sigla', attribute_name='projeto.sigla',
left=label_left[4], left=label_left[3],
), ),
ObjectValue( ObjectValue(
attribute_name='data_retorno_assinatura', attribute_name='data_retorno_assinatura',
left=label_left[3] * cm, left=label_left[4] * cm,
get_value=lambda instance: get_value=lambda instance:
instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura is not None else '-' instance.data_retorno_assinatura.strftime('%d/%m/%Y') if instance.data_retorno_assinatura is not None else '-'
), ),

9
sigi/apps/eventos/admin.py

@ -23,7 +23,8 @@ from django.contrib import admin
from django.db import models from django.db import models
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from sigi.apps.eventos.models import ModeloDeclaracao, Modulo, TipoEvento, Funcao, Evento, Equipe, Convite from sigi.apps.eventos.models import (ModeloDeclaracao, Modulo, TipoEvento,
Funcao, Evento, Equipe, Convite, Anexo)
from sigi.apps.eventos.views import adicionar_eventos_carrinho from sigi.apps.eventos.views import adicionar_eventos_carrinho
from sigi.apps.eventos.forms import EventoAdminForm from sigi.apps.eventos.forms import EventoAdminForm
@ -50,6 +51,10 @@ class ConviteInline(admin.TabularInline):
class ModuloInline(admin.TabularInline): class ModuloInline(admin.TabularInline):
model = Modulo model = Modulo
class AnexoInline(admin.TabularInline):
model = Anexo
exclude = ('data_pub',)
@admin.register(Evento) @admin.register(Evento)
class EventoAdmin(admin.ModelAdmin): class EventoAdmin(admin.ModelAdmin):
form = EventoAdminForm form = EventoAdminForm
@ -62,7 +67,7 @@ class EventoAdmin(admin.ModelAdmin):
raw_id_fields = ('casa_anfitria', 'municipio',) raw_id_fields = ('casa_anfitria', 'municipio',)
search_fields = ('nome', 'tipo_evento__nome', 'casa_anfitria__search_text', search_fields = ('nome', 'tipo_evento__nome', 'casa_anfitria__search_text',
'municipio__search_text', 'solicitante') 'municipio__search_text', 'solicitante')
inlines = (EquipeInline, ConviteInline, ModuloInline) inlines = (EquipeInline, ConviteInline, ModuloInline, AnexoInline)
actions = ['adicionar_eventos', ] actions = ['adicionar_eventos', ]
def adicionar_eventos(self, request, queryset): def adicionar_eventos(self, request, queryset):

21
sigi/apps/eventos/migrations/0014_auto_20211124_0736.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import tinymce.models
class Migration(migrations.Migration):
dependencies = [
('eventos', '0013_modelodeclaracao'),
]
operations = [
migrations.AlterField(
model_name='modelodeclaracao',
name='texto',
field=tinymce.models.HTMLField(help_text='Use as seguintes marca\xe7\xf5es:<ul><li>{{ casa.nome }} para o nome da Casa Legislativa / \xf3rg\xe3o</li><li>{{ casa.municipio.uf.sigla }} para a sigla da UF da Casa legislativa</li><li>{{ nome }} para o nome do visitante</li><li>{{ data }} para a data de emiss\xe3o da declara\xe7\xe3o</li><li>{{ evento.data_inicio }} para a data/hora do in\xedcio da visita</li><li>{{ evento.data_termino }} para a data/hora do t\xe9rmino da visita</li><li>{{ evento.nome }} para o nome do evento</li><li>{{ evento.descricao }} para a descri\xe7\xe3o do evento</li></ul>', verbose_name='Texto da declara\xe7\xe3o'),
preserve_default=True,
),
]

29
sigi/apps/eventos/migrations/0015_anexo.py

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import datetime
class Migration(migrations.Migration):
dependencies = [
('eventos', '0014_auto_20211124_0736'),
]
operations = [
migrations.CreateModel(
name='Anexo',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('arquivo', models.FileField(max_length=500, upload_to=b'apps/eventos/anexo/arquivo')),
('descricao', models.CharField(max_length=b'70', verbose_name='descri\xe7\xe3o')),
('data_pub', models.DateTimeField(default=datetime.datetime.now, verbose_name='data da publica\xe7\xe3o do anexo')),
('evento', models.ForeignKey(verbose_name='evento', to='eventos.Evento')),
],
options={
'ordering': ('-data_pub',),
},
bases=(models.Model,),
),
]

26
sigi/apps/eventos/models.py

@ -262,8 +262,10 @@ class ModeloDeclaracao(models.Model):
) )
texto = HTMLField( texto = HTMLField(
_(u"Texto da declaração"), _(u"Texto da declaração"),
help_text=_(u"Use as seguintes marcações:<ul><li>{{ casa }} para o " help_text=_(u"Use as seguintes marcações:<ul><li>{{ casa.nome }} para o"
u"nome da Casa Legislativa / órgão</li><li>{{ nome }} " u" nome da Casa Legislativa / órgão</li>"
u"<li>{{ casa.municipio.uf.sigla }} para a sigla da UF da "
u"Casa legislativa</li><li>{{ nome }} "
u"para o nome do visitante</li><li>{{ data }} para a data " u"para o nome do visitante</li><li>{{ data }} para a data "
u"de emissão da declaração</li><li>{{ evento.data_inicio }}" u"de emissão da declaração</li><li>{{ evento.data_inicio }}"
u" para a data/hora do início da visita</li>" u" para a data/hora do início da visita</li>"
@ -282,3 +284,23 @@ class ModeloDeclaracao(models.Model):
nome=self.nome, nome=self.nome,
formato=self.get_formato_display() formato=self.get_formato_display()
) )
class Anexo(models.Model):
evento = models.ForeignKey(
Evento,
on_delete=models.CASCADE,
verbose_name=_(u'evento')
)
# caminho no sistema para o documento anexo
arquivo = models.FileField(upload_to='apps/eventos/anexo/arquivo', max_length=500)
descricao = models.CharField(_(u'descrição'), max_length='70')
data_pub = models.DateTimeField(
_(u'data da publicação do anexo'),
default=datetime.now
)
class Meta:
ordering = ('-data_pub',)
def __unicode__(self):
return unicode("%s publicado em %s" % (self.descricao, self.data_pub))

2
sigi/apps/eventos/templates/eventos/declaracao_pdf.html

@ -6,7 +6,7 @@
{% block report %} {% block report %}
{% for convite in evento.convite_set.all %} {% for convite in evento.convite_set.all %}
{% with convite.casa.nome as casa %} {% with convite.casa as casa %}
{% for nome in convite.nomes_participantes.splitlines %} {% for nome in convite.nomes_participantes.splitlines %}
{% block text_body %}{% endblock %} {% block text_body %}{% endblock %}
<pdf:nextpage /> <pdf:nextpage />

2
sigi/apps/metas/templates/metas/openmap.html

@ -46,7 +46,7 @@
<a href="#" style="float: right;" id="options-toggler" type="button" data-toggle="collapse" data-target="#filterbox" aria-expanded="false" aria-controls="collapseExample"> <a href="#" style="float: right;" id="options-toggler" type="button" data-toggle="collapse" data-target="#filterbox" aria-expanded="false" aria-controls="collapseExample">
<span class="glyphicon glyphicon-chevron-right"></span> <span class="glyphicon glyphicon-chevron-right"></span>
</a> </a>
<div class="collapse" id="filterbox"> <div class="collapse in" id="filterbox">
<form id="searchform" class="form-inline ui-front"> <form id="searchform" class="form-inline ui-front">
<input type="text" id="search-text" class="form-control" placeholder="Procurar" aria-label="Procurar" aria-describedby="basic-addon2"> <input type="text" id="search-text" class="form-control" placeholder="Procurar" aria-label="Procurar" aria-describedby="basic-addon2">
</form> </form>

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

@ -3,7 +3,7 @@ from django import template
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from sigi.apps.casas.models import Orgao from sigi.apps.casas.models import Orgao
from sigi.apps.metas.views import parliament_summary from sigi.apps.metas.views import openmap
register = template.Library() register = template.Library()
@ -14,7 +14,7 @@ def descricao_servicos(casa):
if not isinstance(casa, Orgao): if not isinstance(casa, Orgao):
return "" return ""
summary = parliament_summary(casa) summary = openmap(casa)
result = ''.join('<li>%s</li>' % info for info in summary['info']) result = ''.join('<li>%s</li>' % info for info in summary['info'])
return mark_safe(result) return mark_safe(result)
descricao_servicos.is_safe = True descricao_servicos.is_safe = True

2
sigi/apps/metas/views.py

@ -232,4 +232,4 @@ def openmapsearch(request):
'label': d['nome'], 'label': d['nome'],
'lat': d['municipio__latitude'], 'lat': d['municipio__latitude'],
'lng': d['municipio__longitude']} for d in dados] 'lng': d['municipio__longitude']} for d in dados]
return JsonResponse(list(dados), safe=False) return JsonResponse(list(dados), safe=False)

49
sigi/apps/servicos/admin.py

@ -11,6 +11,7 @@ from sigi.apps.casas.admin import FuncionariosInline, GerentesInterlegisFilter
from sigi.apps.casas.models import Orgao from sigi.apps.casas.models import Orgao
from sigi.apps.servicos.models import (Servico, LogServico, CasaAtendida, from sigi.apps.servicos.models import (Servico, LogServico, CasaAtendida,
TipoServico) TipoServico)
from sigi.apps.servicos.views import adicionar_servicos_carrinho
from sigi.apps.utils.base_admin import BaseModelAdmin from sigi.apps.utils.base_admin import BaseModelAdmin
@ -111,6 +112,7 @@ class ServicoAtivoFilter(admin.SimpleListFilter):
return queryset return queryset
class ServicoAdmin(BaseModelAdmin): class ServicoAdmin(BaseModelAdmin):
change_list_template = "servico/change_list.html"
form = ServicoFormAdmin form = ServicoFormAdmin
actions = ['calcular_data_uso', ] actions = ['calcular_data_uso', ]
list_display = ('casa_legislativa', 'get_codigo_interlegis', 'get_uf', 'tipo_servico', 'hospedagem_interlegis', list_display = ('casa_legislativa', 'get_codigo_interlegis', 'get_uf', 'tipo_servico', 'hospedagem_interlegis',
@ -137,6 +139,7 @@ class ServicoAdmin(BaseModelAdmin):
'casa_legislativa__municipio__uf', 'casa_legislativa__municipio__uf',
) )
list_display_links = [] list_display_links = []
actions = ['adicionar_servicos']
ordering = ('casa_legislativa__municipio__uf', 'casa_legislativa', 'tipo_servico',) ordering = ('casa_legislativa__municipio__uf', 'casa_legislativa', 'tipo_servico',)
inlines = (LogServicoInline,) inlines = (LogServicoInline,)
search_fields = ('casa_legislativa__search_text',) search_fields = ('casa_legislativa__search_text',)
@ -169,6 +172,22 @@ class ServicoAdmin(BaseModelAdmin):
get_link_erro.short_description = _(u"Erro na atualização") get_link_erro.short_description = _(u"Erro na atualização")
get_link_erro.admin_order_field = 'erro_atualizacao' get_link_erro.admin_order_field = 'erro_atualizacao'
def adicionar_servicos(self, request, queryset):
if 'carrinho_servicos' in request.session:
q1 = len(request.session['carrinho_servicos'])
else:
q1 = 0
adicionar_servicos_carrinho(request, queryset=queryset)
q2 = len(request.session['carrinho_servicos'])
quant = q2 - q1
if quant:
self.message_user(request, str(q2 - q1) + _(u" Serviços adicionados no carrinho"))
else:
self.message_user(request, _(u"Os Serviços selecionados já foram adicionadas anteriormente"))
return HttpResponseRedirect('.')
adicionar_servicos.short_description = _(u"Armazenar serviços no carrinho para exportar")
def calcular_data_uso(self, request, queryset): def calcular_data_uso(self, request, queryset):
for servico in queryset: for servico in queryset:
servico.atualiza_data_uso() servico.atualiza_data_uso()
@ -186,7 +205,7 @@ class ServicoAdmin(BaseModelAdmin):
def lookup_allowed(self, lookup, value): def lookup_allowed(self, lookup, value):
return super(ServicoAdmin, self).lookup_allowed(lookup, value) or \ return super(ServicoAdmin, self).lookup_allowed(lookup, value) or \
lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact'] lookup in ['casa_legislativa__municipio__uf__codigo_ibge__exact', ]
def add_view(self, request, form_url='', extra_context=None): def add_view(self, request, form_url='', extra_context=None):
id_casa = request.GET.get('id_casa', None) id_casa = request.GET.get('id_casa', None)
@ -234,6 +253,34 @@ class ServicoAdmin(BaseModelAdmin):
obj.casa_legislativa = Orgao.objects.get(pk=id_casa) obj.casa_legislativa = Orgao.objects.get(pk=id_casa)
return obj return obj
def changelist_view(self, request, extra_context=None):
from sigi.apps.convenios.views import normaliza_data
request.GET._mutable = True
normaliza_data(request.GET, 'data_ativacao__gte')
normaliza_data(request.GET, 'data_ativacao__lte')
request.GET._mutable = False
return super(ServicoAdmin, self).changelist_view(
request,
extra_context={'query_str': '?' + request.META['QUERY_STRING']}
)
def adicionar_servicos(self, request, queryset):
if 'carrinho_servicos' in request.session:
q1 = len(request.session['carrinho_servicos'])
else:
q1 = 0
adicionar_servicos_carrinho(request, queryset=queryset)
q2 = len(request.session['carrinho_servicos'])
quant = q2 - q1
if quant:
self.message_user(request, str(q2 - q1) + _(u" Convênios adicionados no carrinho"))
else:
self.message_user(request, _(u"Os Convênios selecionados já foram adicionadas anteriormente"))
return HttpResponseRedirect('.')
adicionar_servicos.short_description = _(u"Armazenar Serviços no carrinho para exportar")
class ContatosInline(FuncionariosInline): class ContatosInline(FuncionariosInline):

4
sigi/apps/servicos/templates/admin/servicos/servico/change_list.html

@ -1,4 +0,0 @@
{% extends "admin/change_list.html" %}
{% block object-tools-items %}
{% endblock %}

33
sigi/apps/servicos/templates/servico/change_list.html

@ -0,0 +1,33 @@
{% extends "change_list_with_cart.html" %}
{% load i18n %}
{% block extra_search %}
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Filtro de datas</a>
<p class="navbar-text">Use AAAA, AAAA-MM ou AAAA-MM-DD</p>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<form class="navbar-form navbar-left" role="extra-search" id="changelist-extrasearch" action="" method="get">
<div class="form-group">
<label for="data_ativacao__gte">{% trans 'Ativados a partir de' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_ativacao__gte" value="" id="data_ativacao__gte">
<label for="data_ativacao__lte">{% trans 'até' %}:</label>
<input type="text" class="form-control search-query" size="10" name="data_ativacao__lte" value="" id="data_ativacao__lte">
</div>
<button type="submit" class="btn btn-default navbar-btn ">
<span class="glyphicon glyphicon-search"></span>
</button>
</form>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% endblock %}

100
sigi/apps/servicos/templates/servicos/carrinho.html

@ -0,0 +1,100 @@
{% extends "admin/carrinho.html" %}
{% load admin_list i18n %}
{% block extrastyle %}
{{ block.super }}
{% include "admin/tabs_style.html" %}
{% endblock %}
{% block title %}{% trans 'Serviços no Carrinho | SIGI' %}{% endblock %}
{% block content_title %}<h1>{% trans 'Serviços no Carrinho' %}</h1>{% endblock %}
{% block mensagem%}
<ul class="messagelist">
{%if carIsEmpty%}
<li class="warning">{% trans 'O carrinho está vazio, sendo assim todos os Serviços entram na lista para exportação de acordo com os filtros aplicados.' %}</li>
{%else%}
<li>{{paginas.paginator.count}} {% trans 'Serviços no carrinho' %}.</li>
{%endif%}
</ul>
{% endblock %}
{% block action %}deleta_itens_carrinho{% endblock %}
{% block tabela %}
<table class="table table-striped">
<thead class="thead-dark">
<tr>
{%if not carIsEmpty%}
<th class="sorted ascending"><!-- <input type="checkbox" id="action-toggle" style="display: inline;">-->
</th>
{% endif %}
<th class="sorted ascending">{% trans 'Casa Legislativa' %}</th>
<th class="sorted ascending">{% trans 'UF' %}</th>
<th class="sorted ascending">{% trans 'Email' %}</th>
<th class="sorted ascending">{% trans 'Telefone' %}</th>
<th class="sorted ascending">{% trans 'Contato Interlegis' %}</th>
<th class="sorted ascending">{% trans 'Tipo de Serviço' %}</th>
<th class="sorted ascending">{% trans 'Data Ativação' %}</th>
</tr>
</thead>
<tbody>
{% for servico in paginas.object_list %}
<tr>
{%if not carIsEmpty%}
<th><input type="checkbox" name="_selected_action"
value="{{servico.id|safe}}" class="action-select" /></th>
{% endif %}
<td style="text-align: left;">{{servico.casa_legislativa}}</td>
<td>{{servico.casa_legislativa.municipio.uf.sigla}}</td>
<td>{{servico.casa_legislativa.email}}</td>
<td>{{servico.casa_legislativa.telefone}}</td>
<td>{{servico.casa_legislativa.contato_interlegis}}</td>
<td>{{servico.casa_legislativa.contato_interlegis.email}}</td>
<td>{{servico.tipo_servico}}</td>
<td>{{servico.data_ativacao}}</td></tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block botoes %}
<ul class="nav nav-tabs" role="tablist">
<li class="active" role="presentation"><a href="#tabs-2" aria-controls="tabs-2" role="tab" data-toggle="tab">{% trans 'Arquivo CSV (Excel, Calc)' %}</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tabs-2">
<form action="../csv/{{query_str}}" method="post">{% csrf_token %}
<fieldset>
<legend>{% trans 'Escolha os atributos para exportar' %}</legend>
<ul id="sortable" class="tabs-conteudo">
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Casa Legislativa"
class="action-select" checked="checked" />
<label>{% trans 'Casa Legislativa' %}</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Contato Interlegis"
class="action-select" checked="checked" />
<label>{% trans 'Contato Interlegis' %}</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Produto"
class="action-select" checked="checked" />
<label>{% trans 'Produto' %}</label>
</li>
<li>
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>
<input type="checkbox" name="itens_csv_selected" value="Data de Ativação"
class="action-select" checked="checked" />
<label>{% trans 'Data de Ativação' %}</label>
</li>
</ul>
</fieldset>
<input type="submit" value="Exportar CSV" type="button" class="btn btn-primary"/>
</form>
</div>
</div>
{% endblock %}

4
sigi/apps/servicos/urls.py

@ -9,6 +9,10 @@ urlpatterns = patterns(
'sigi.apps.servicos.views', 'sigi.apps.servicos.views',
url(r'^manifesta/$', 'casa_manifesta_view', name="casa-manifesta-view"), url(r'^manifesta/$', 'casa_manifesta_view', name="casa-manifesta-view"),
url(r'^servico/carrinho/$', 'visualizar_carrinho', name='visualizar-carrinho'),
url(r'^servico/carrinho/excluir_carrinho/$', 'excluir_carrinho', name='excluir-carrinho'), # tagerror
url(r'^servico/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho', name='deleta-itens-carrinho'), # tagerror
url(r'^servico/csv/$', 'export_csv', name='servicos-csv'),
url(r'^munatenjson/(?P<servico>\w+)/$', 'municipios_atendidos', name="municipios-atendidos"), url(r'^munatenjson/(?P<servico>\w+)/$', 'municipios_atendidos', name="municipios-atendidos"),
url(r'^mapa/(?P<servico>\w+)/$', MapaView.as_view(), name="servicos-mapa"), url(r'^mapa/(?P<servico>\w+)/$', MapaView.as_view(), name="servicos-mapa"),
# url(r'^listacasas/(?P<sigla>\w+)', 'casas_usam_servico', name="casas-usam-servico"), # url(r'^listacasas/(?P<sigla>\w+)', 'casas_usam_servico', name="casas-usam-servico"),

194
sigi/apps/servicos/views.py

@ -1,18 +1,24 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import csv
import json as simplejson # XXX trocar isso por simplesmente import json e refatorar o codigo import json as simplejson # XXX trocar isso por simplesmente import json e refatorar o codigo
from django import forms from django import forms
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.paginator import EmptyPage, InvalidPage, Paginator
from django.db.models import Q from django.db.models import Q
from django.forms.forms import BoundField from django.forms.forms import BoundField
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404 from django.http.response import HttpResponseRedirect
from django.shortcuts import render, render_to_response, get_object_or_404
from django.template.context import RequestContext from django.template.context import RequestContext
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from sigi.apps.casas.models import Orgao from sigi.apps.casas.models import Orgao
from sigi.apps.contatos.models import UnidadeFederativa from sigi.apps.contatos.models import UnidadeFederativa
from sigi.apps.servicos.models import (TipoServico, CasaManifesta, CasaAtendida, from sigi.apps.convenios.views import normaliza_data, query_ordena
from sigi.apps.servicos.models import (Servico, TipoServico, CasaManifesta, CasaAtendida,
ServicoManifesto) ServicoManifesto)
@ -144,3 +150,187 @@ def casa_manifesta_view(request):
extra_context = {'uf_list': UnidadeFederativa.objects.all()} extra_context = {'uf_list': UnidadeFederativa.objects.all()}
return render_to_response('servicos/casa_manifesta.html', extra_context, context_instance=RequestContext(request)) return render_to_response('servicos/casa_manifesta.html', extra_context, context_instance=RequestContext(request))
def adicionar_servicos_carrinho(request, queryset=None, id=None):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if 'carrinho_servicos' not in request.session:
request.session['carrinho_servicos'] = ids_selecionados
else:
lista = request.session['carrinho_servicos']
# Verifica se id já não está adicionado
for id in ids_selecionados:
if id not in lista:
lista.append(id)
request.session['carrinho_servicos'] = lista
def carrinhoOrGet_for_qs(request):
"""
Verifica se existe convênios na sessão se não verifica get e retorna qs correspondente.
"""
if 'carrinho_servicos' in request.session:
ids = request.session['carrinho_servicos']
qs = Servico.objects.filter(pk__in=ids)
qs = qs.order_by("casa_legislativa__municipio__uf", "casa_legislativa__municipio")
qs = get_for_qs(request.GET, qs)
else:
qs = Servico.objects.all()
if request.GET:
qs = qs.order_by("casa_legislativa__municipio__uf", "casa_legislativa__municipio")
qs = get_for_qs(request.GET, qs)
return qs
def adicionar_servicos_carrinho(request, queryset=None, id=None):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if 'carrinho_servicos' not in request.session:
request.session['carrinho_servicos'] = ids_selecionados
else:
lista = request.session['carrinho_servicos']
# Verifica se id já não está adicionado
for id in ids_selecionados:
if id not in lista:
lista.append(id)
request.session['carrinho_servicos'] = lista
@login_required
def excluir_carrinho(request):
if 'carrinho_servicos' in request.session:
del request.session['carrinho_servicos']
messages.info(request, u'O carrinho foi esvaziado')
return HttpResponseRedirect('../../')
@login_required
def deleta_itens_carrinho(request):
if request.method == 'POST':
ids_selecionados = request.POST.getlist('_selected_action')
if 'carrinho_servicos' in request.session:
lista = request.session['carrinho_servicos']
for item in ids_selecionados:
lista.remove(item)
if lista:
request.session['carrinho_servicos'] = lista
else:
del lista
del request.session['carrinho_servicos']
return HttpResponseRedirect('.')
@login_required
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('carrinho_servicos' in request.session)
return render(
request,
'servicos/carrinho.html',
{
'carIsEmpty': carrinhoIsEmpty,
'paginas': paginas,
'query_str': '?' + request.META['QUERY_STRING']
}
)
def get_for_qs(get, qs):
kwargs = {}
ids = 0
get._mutable = True
normaliza_data(get, 'data_ativacao__gte')
normaliza_data(get, 'data_ativacao__lte')
get._mutable = False
for k, v in get.iteritems():
if k not in ['page', 'pop', 'q', '_popup']:
if not k == 'o':
if k == "ot":
qs = query_ordena(qs, get["o"], get["ot"])
else:
kwargs[str(k)] = v
if(str(k) == 'ids'):
ids = 1
break
qs = qs.filter(**kwargs)
if ids:
query = 'id IN (' + kwargs['ids'].__str__() + ')'
qs = Servico.objects.extra(where=[query])
return qs
@login_required
def export_csv(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=servicos.csv'
csv_writer = csv.writer(response)
servicos = carrinhoOrGet_for_qs(request)
if not servicos:
return HttpResponseRedirect('../')
atributos = [_(u"Casa Legislativa"), _(u"Contato Interlegis"), _(u"Produto"),
_(u"Data de Ativação"), ]
if request.POST:
atributos = request.POST.getlist("itens_csv_selected")
col_titles = atributos
if _(u"Casa Legislativa") in col_titles:
pos = col_titles.index(_(u"Casa Legislativa")) + 1
col_titles.insert(pos, _(u"uf"))
pos+=1
col_titles.insert(pos, _(u"email"))
pos+=1
col_titles.insert(pos, _(u"telefone"))
if _(u"Contato Interlegis") in col_titles:
pos = col_titles.index(_(u"Contato Interlegis")) + 1
col_titles.insert(pos, _(u"Email do contato"))
csv_writer.writerow([s.encode("utf-8") for s in col_titles])
for servico in servicos:
lista = []
for atributo in atributos:
if _(u"Casa Legislativa") == atributo:
lista.append(servico.casa_legislativa.nome.encode("utf-8"))
lista.append(servico.casa_legislativa.municipio.uf.sigla.encode("utf-8"))
lista.append(servico.casa_legislativa.email.encode("utf-8"))
if servico.casa_legislativa.telefone is not None:
lista.append(servico.casa_legislativa.telefone)
else:
lista.append("")
elif _(u"Contato Interlegis") == atributo:
if servico.casa_legislativa.contato_interlegis is not None:
lista.append(servico.casa_legislativa.contato_interlegis)
lista.append(servico.casa_legislativa.contato_interlegis.email.encode("utf-8"))
else:
lista.append("")
lista.append("")
elif _(u"Produto") == atributo:
lista.append(servico.tipo_servico.nome.encode("utf-8"))
elif _(u"Data de Ativação") == atributo:
data = ''
if servico.data_ativacao:
data = servico.data_ativacao.strftime("%d/%m/%Y")
lista.append(data.encode("utf-8"))
else:
pass
csv_writer.writerow(lista)
return response

14
sigi/apps/servidores/models.py

@ -2,7 +2,7 @@
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes import generic from django.contrib.contenttypes import generic
from django.db import models from django.db import models
from django.db.models.signals import post_save from django.db.models.signals import post_save, pre_save
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
class Servico(models.Model): class Servico(models.Model):
@ -89,4 +89,14 @@ def create_user_profile(sender, instance, created, **kwargs):
nome_completo="%s %s" % (instance.first_name, instance.last_name) nome_completo="%s %s" % (instance.first_name, instance.last_name)
) )
post_save.connect(create_user_profile, sender=User) post_save.connect(create_user_profile, sender=User)
# Hack horrível para ajustar o first_name e o last_name do User criado pelo
# Django-ldap. Os campos first_name e last_name têm o tamanho máximo de
# 30 caracteres, mas o LDAP não tem esse limite, e alguns usuários podem ter
# nomes maiores que isso, o que provoca erro ao salvar o usuário.j
def ajusta_nome_usuario(sender, instance, *args, **kwargs):
instance.first_name = instance.first_name[:30]
instance.last_name = instance.last_name[:30]
pre_save.connect(ajusta_nome_usuario, sender=User)

1
sigi/settings/base.py

@ -95,6 +95,7 @@ LANGUAGE_CODE = 'pt-br'
USE_I18N = True USE_I18N = True
USE_L10N = True USE_L10N = True
USE_THOUSAND_SEPARATOR = True USE_THOUSAND_SEPARATOR = True
TIME_ZONE = "America/Sao_Paulo"
gettext_noop = lambda s: s # for gettext discovery gettext_noop = lambda s: s # for gettext discovery
LANGUAGES = ( LANGUAGES = (

8
templates/base_report.html

@ -15,6 +15,11 @@
font-size: 1.2em; font-size: 1.2em;
text-align: center; text-align: center;
} }
.orgao_name {
margin-bottom: 0px;
margin-top: 0px;
font-weight: bold;
}
h1 { h1 {
font-size: 2em; font-size: 2em;
text-align: center; text-align: center;
@ -82,7 +87,8 @@
<td class="logo"><img src="{% static 'img/logo-senado.jpg' %}" /></td> <td class="logo"><img src="{% static 'img/logo-senado.jpg' %}" /></td>
<td class="header_text"> <td class="header_text">
<p><strong>{% trans 'SENADO FEDERAL' %}</strong></p> <p><strong>{% trans 'SENADO FEDERAL' %}</strong></p>
<p><strong>{% trans 'INSTITUTO LEGISLATIVO BRASILEIRO - ILB / INTERLEGIS' %}</strong></p> <p class="orgao_name">{% trans 'Instituto Legislativo Brasileiro' %}</p>
<p class="orgao_name">{% trans "ILB / Interlegis" %}</p>
<p>{% block subsecretaria %}{% endblock %}</p> <p>{% block subsecretaria %}{% endblock %}</p>
</td> </td>
<td class="logo"><img src="{% static 'img/logo-interlegis.jpg' %}" /></td> <td class="logo"><img src="{% static 'img/logo-interlegis.jpg' %}" /></td>

Loading…
Cancel
Save