diff --git a/media/css/admin/diagnosticos/diagnostico/change_form.css b/media/css/admin/diagnosticos/diagnostico/change_form.css new file mode 100644 index 0000000..7582e05 --- /dev/null +++ b/media/css/admin/diagnosticos/diagnostico/change_form.css @@ -0,0 +1,14 @@ +form .aligned label { + float: none; + width: 100%; +} +form .aligned ul { + margin-left: 0px; + padding-left: 0px; +} +form .aligned ul li { + list-style: none; +} +form .form-row.data_visita_inicio { + float: left; +} diff --git a/media/css/diagnosticos/diagnosticos_categoria_model_form.css b/media/css/diagnosticos/diagnosticos_categoria_model_form.css new file mode 100644 index 0000000..26dfad2 --- /dev/null +++ b/media/css/diagnosticos/diagnosticos_categoria_model_form.css @@ -0,0 +1,27 @@ +div.ui-field-contain input.ui-input-text, div.ui-field-contain textarea.ui-input-text, div.ui-field-contain .ui-input-search { + width: 97%; + display: inline-block; +} +div.ui-field-contain.phone input.ui-input-text { + width: 65%; + display: inline-block; +} +div.ui-field-contain.phone .ui-select { + width: 30%; + float: left; + margin: -0.5em 0; +} +div.ui-field-contain.phone .ui-select .ui-btn-text { + text: left; + padding-left: 0.2em; +} + +div.ui-field-contain.phone .ui-select .ui-btn { + margin: 0.5em 10px 0.5em 0px; +} + +div.ui-field-contain.phone .ui-select .ui-btn-inner { + padding-left: 15px; +} + + diff --git a/media/css/diagnosticos/diagnosticos_categorias.css b/media/css/diagnosticos/diagnosticos_categorias.css new file mode 100644 index 0000000..d5675c4 --- /dev/null +++ b/media/css/diagnosticos/diagnosticos_categorias.css @@ -0,0 +1,26 @@ + +/* Destacando a ultima categoria visitada */ +.ui-btn-last-c { + border: 1px solid #155678; + background: #4596CE; + font-weight: bold; + cursor: pointer; + text-shadow: 0 -1px 1px #145072; + text-decoration: none; + background-image: -webkit-gradient(linear,left top,left bottom,from(#85bae4),to(#5393c5)); + background-image: -webkit-linear-gradient(#85bae4,#5393c5); + background-image: -moz-linear-gradient(#85bae4,#5393c5); + background-image: -ms-linear-gradient(#85bae4,#5393c5); + background-image: -o-linear-gradient(#85bae4,#5393c5); + background-image: linear-gradient(#85bae4,#5393c5); + font-family: Helvetica,Arial,sans-serif; +} + +.ui-btn-last-c a.ui-link-inherit { + color: white; +} + +/* Definindo as categorias que foram lidas */ +.ui-li-heading-read { + font-weight: normal !important; +} diff --git a/media/css/diagnosticos/diagnosticos_categorias_form.css b/media/css/diagnosticos/diagnosticos_categorias_form.css new file mode 100644 index 0000000..f667f3a --- /dev/null +++ b/media/css/diagnosticos/diagnosticos_categorias_form.css @@ -0,0 +1,13 @@ +.ui-field-contain input.ui-input-text, .ui-field-contain textarea.ui-input-text, .ui-field-contain .ui-input-search { + width: 97%; + display: inline-block; +} + +.ui-field-contain ul { + -webkit-padding-start: 0; +} + +span.errors { + display: block; + color: red; +} diff --git a/media/images/loader.gif b/media/images/loader.gif new file mode 100644 index 0000000..514a190 Binary files /dev/null and b/media/images/loader.gif differ diff --git a/media/images/mobile/logointerlegis_mobile.png b/media/images/mobile/logointerlegis_mobile.png new file mode 100644 index 0000000..32a77fe Binary files /dev/null and b/media/images/mobile/logointerlegis_mobile.png differ diff --git a/media/js/diagnosticos/diagnosticos_categorias_form.js b/media/js/diagnosticos/diagnosticos_categorias_form.js new file mode 100644 index 0000000..de6f848 --- /dev/null +++ b/media/js/diagnosticos/diagnosticos_categorias_form.js @@ -0,0 +1,97 @@ +// cntabiliza a quantidade de requests +// ajax para nao desabilitar o loader +// antes da hora +var nun_ajax = 0; + +$('#page').live('pageinit', function(event){ + // variaveis globais para as requisicoes ajax + $.ajaxSetup({ + url: $(location).attr('href'), + cache: false, + type: 'POST', + beforeSend: function() { + nun_ajax++; + $('#working').show(); + }, + success: function(data) { + nun_ajax--; + if (nun_ajax == 0) + $('#working').hide(); + + //Retirando o span existente + $("span.errors").html(""); + if (data.mensagem == "erro") { + for (var campo in data.erros) { + $("#"+ campo + " span").html(data.erros[campo].join('\n')) + } + } + }, + error: function(msg) { + nun_ajax--; + if (nun_ajax == 0) + $('#working').hide(); + $("#open-dialog").click(); + } + }); + + // remove a resposta vazia da interface + $("div.ui-radio span.ui-btn-text:contains('---------')").parentsUntil("ul").hide(); + + // para todo input do from registra um evento + // ao modificar o campo + $("div.ui-field-contain textarea, div.ui-field-contain input, div.ui-field-contain select").change(function () { + // mostra ou esconde uma pergunta dependente + var id_to_open = [] + var id_to_close = [] + $('input[name=' + $(this).attr('name') + ']').each(function () { + schema = $(this); + schema_to_open = schema.attr('schema_to_open'); + if (schema_to_open) { + if (schema.is(':checked')) + id_to_open.push(schema_to_open) + else + id_to_close.push(schema_to_open) + } + }); + + for (var i in id_to_close) { + id = id_to_close[i] + // Evita apagar uma pergunta caso ela possa + // ser exibida por outra questão + if (id_to_open.indexOf(id_to_close[i]) == -1) { + // limpa o valor para não salva-lo + // no submit do form + $("#" + id + " input").val(''); + $("#" + id).slideUp(); + } + } + + // Exibe as perguntas que devem estar disponiveis + for (var i in id_to_open) { + id = id_to_open[i] + $("#" + id).slideDown(); + } + + $.ajax({ + data: $('#diagnostico').serializeArray() + }); + + }); + + $('input[schema_to_open]').each(function () { + schema = $(this); + schema_to_open = $("#" + schema.attr('schema_to_open')); + schema_to_open.hide(); + }); + + $('input[schema_to_open]:checked').each(function () { + schema = $(this); + schema_to_open = $("#" + schema.attr('schema_to_open')); + schema_to_open.show(); + }); + + // se carregou o js sem erros mostra as perguntas + $("#waiting").hide(); + $("#working").hide(); + $("#form").show(); +}); diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3cd44f9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +PIL==1.1.7 +Django==1.2 +django-auth-ldap==1.0.12 +django-autoslug==1.4.1 +django-extensions==0.7.1 +django-treemenus==0.8.7 +eav-django==1.3.4 +html5lib==0.90 +pisa==3.0.33 +python-ldap==2.4.4 +reportlab==2.5 +wsgiref==0.1.2 diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..0d1cdfb --- /dev/null +++ b/setup.sh @@ -0,0 +1,79 @@ +#!bin/bash + +############################################################# +## Arquivo: setup.sh ## +## ## +## Esse arquivo foi criado para automatizar a instalação ## +## do projeto SIGI. ## +## ## +## Autor: Gilson Filho ## +## Data: 23 de Novembro de 2011 ## +## Versão: 1.0 ## +## ## +############################################################# + +# Definindo o nome do arquivo que contem as informações das dependências +requirements="requirements.txt" + +# Verifica se o easy_install e o pip está instalado +easy_install=`find /usr/bin/ -name easy_install` +pip=`find /usr/bin/ -name pip` +git=`find /usr/bin/ -name git` + +if [ ! -f $easy_install ] || [ ! -f $pip ]; then + echo "O aplicativo pip é obrigatório. Favor instalar para continuar a configuração do SIGI." + sleep 5 + exit +else + # Executando o arquivo requirements.txt + if [ -f $requirements ]; then + echo + echo "Instalando os módulos contidos no arquivo $requirements ..." + echo + sleep 2 + pip install -r $requirements + + # Verifica se o git está instalado + if [ ! -f $git]; then + echo + echo "O aplicativo git não está instalado. Caso contrário, faça o checkout diretamente." + sleep 5 + exit + else + # Faz o checkout do projeto e instala o módulo + echo + echo "Fazendo o checkout do projeto..." + echo + sleep 2 + git clone git://github.com/jacobian/django-googlecharts.git + + echo + echo "Iniciando a instalacao..." + echo + sleep 2 + cd django-googlecharts + python setup.py install + + # Instalando o django-geraldo + echo + echo "Fazendo o checkout do projeto django-geraldo..." + echo + sleep 2 + git clone https://github.com/marinho/geraldo.git + + echo + echo "Instalando o django-geraldo..." + echo + cd geraldo + python setup.py install + cp -Rvf reporting geraldo /usr/local/lib/python2.7/site-packages + fi + else + echo + echo "O arquivo requirements.txt não existe. Verifique se está na mesma pasta do arquivo de instalação do SIGI." + sleep 5 + exit + fi +fi + + diff --git a/sigi/admin/filterspecs.py b/sigi/admin/filterspecs.py index 51b14f8..5454a8a 100644 --- a/sigi/admin/filterspecs.py +++ b/sigi/admin/filterspecs.py @@ -1,10 +1,31 @@ -from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec +from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec, BooleanFieldFilterSpec 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 IsActiveFilterSpec(BooleanFieldFilterSpec): + """ + Adds filtering by user is_active attr in the admin filter sidebar + my_model_user_field.is_active__filter = True + """ + + def __init__(self, f, request, params, model, model_admin): + super(IsActiveFilterSpec, self).__init__(f, request, params, model, + model_admin) + self.lookup_kwarg = '%s__is_active__exact' % f.name + self.lookup_kwarg2 = '%s__is_active__isnull' % f.name + self.lookup_val = request.GET.get(self.lookup_kwarg, None) + self.lookup_val2 = request.GET.get(self.lookup_kwarg2, None) + + def title(self): + return _('active') + +# registering the filter +FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'is_active__filter', False), + IsActiveFilterSpec)) + class AlphabeticFilterSpec(ChoicesFilterSpec): """ Adds filtering by first char (alphabetic style) of values in the admin diff --git a/sigi/apps/casas/admin.py b/sigi/apps/casas/admin.py index b466119..3b2d059 100644 --- a/sigi/apps/casas/admin.py +++ b/sigi/apps/casas/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin 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.casas.models import CasaLegislativa, Presidente, Funcionario +from sigi.apps.contatos.models import Telefone from sigi.apps.convenios.models import Projeto, Convenio, EquipamentoPrevisto, Anexo from django.http import HttpResponse, HttpResponseRedirect from sigi.apps.casas.reports import CasasLegislativasLabels, CasasLegislativasReport @@ -13,14 +13,23 @@ from sigi.apps.casas.views import report_complete, labels_report, export_csv, \ adicionar_casas_carrinho from sigi.apps.utils import queryset_ascii -class ContatosInline(generic.GenericTabularInline): - model = Contato - extra = 2 - raw_id_fields = ('municipio',) - class TelefonesInline(generic.GenericTabularInline): model = Telefone - extra = 2 + extra = 1 + +class PresidenteInline(admin.StackedInline): + model = Presidente + exclude = ['cargo','funcao'] + extra = 1 + max_num = 1 + inlines = (TelefonesInline) + +class FuncionariosInline(admin.StackedInline): + model = Funcionario + extra = 1 + inlines = (TelefonesInline) + def queryset(self, request): + return self.model.objects.exclude(cargo="Presidente") class ConveniosInline(admin.TabularInline): model = Convenio @@ -32,16 +41,15 @@ class CasaLegislativaAdmin(admin.ModelAdmin): change_form_template = 'casas/change_form.html' change_list_template = 'casas/change_list.html' actions = ['adicionar_casas',] - inlines = (TelefonesInline, ContatosInline, ConveniosInline) - list_display = ('nome','municipio','presidente','logradouro') + inlines = (TelefonesInline, PresidenteInline, FuncionariosInline, ConveniosInline) + list_display = ('nome','municipio','logradouro') list_display_links = ('nome',) list_filter = ('tipo', 'municipio') ordering = ('nome','municipio__uf') queyrset = queryset_ascii fieldsets = ( (None, { - 'fields': ('tipo', 'nome', 'telefone', 'cnpj', - 'presidente'), + 'fields': ('tipo', 'nome', 'cnpj',) }), ('Endereço', { 'fields': ('logradouro', 'bairro', 'municipio', 'cep', 'pagina_web','email'), diff --git a/sigi/apps/casas/forms.py b/sigi/apps/casas/forms.py index d300b4f..603fbed 100644 --- a/sigi/apps/casas/forms.py +++ b/sigi/apps/casas/forms.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- from django import forms -from django.contrib.localflavor.br.forms import BRCNPJField, BRZipCodeField +from django.contrib.localflavor.br.forms import BRZipCodeField from sigi.apps.casas.models import CasaLegislativa + class CasaLegislativaForm(forms.ModelForm): #cnpj = BRCNPJField( # label='CNPJ', @@ -14,3 +15,6 @@ class CasaLegislativaForm(forms.ModelForm): class Meta: model = CasaLegislativa + + def clean(self): + print self.cleaned_data['bairro'] diff --git a/sigi/apps/casas/models.py b/sigi/apps/casas/models.py index 52aab33..81de46d 100644 --- a/sigi/apps/casas/models.py +++ b/sigi/apps/casas/models.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- 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 from sigi.apps.utils import SearchField @@ -35,7 +34,6 @@ class CasaLegislativa(models.Model): tipo = models.ForeignKey(TipoCasaLegislativa, verbose_name="Tipo") cnpj = models.CharField('CNPJ', max_length=32, blank=True) observacoes = models.TextField(u'observações', blank=True) - presidente = models.CharField('Presidente', max_length=150, blank=True) # Informações de contato logradouro = models.CharField( @@ -56,7 +54,6 @@ class CasaLegislativa(models.Model): blank=True, verify_exists=False ) - telefone = models.CharField('Telefone', max_length=100, blank=True) telefones = generic.GenericRelation('contatos.Telefone') foto = models.ImageField( @@ -68,7 +65,6 @@ class CasaLegislativa(models.Model): foto_largura = models.SmallIntegerField(editable=False, null=True) foto_altura = models.SmallIntegerField(editable=False, null=True) - contatos = generic.GenericRelation('contatos.Contato') class Meta: ordering = ('nome',) @@ -78,3 +74,55 @@ class CasaLegislativa(models.Model): def __unicode__(self): return self.nome + +class Funcionario(models.Model): + """ Modelo para registrar contatos vinculados às + Casas Legislativas + """ + SETOR_CHOICES = [ + ("presidencia","Presidencia"), + ("infraestrutura_fisica","Infraestrutura Física"), + ("estrutura_de_ti","Estrutura de TI"), + ("organizacao_do_processo_legislativo","Organização do Processo Legislativo"), + ("estrutura_de_comunicacao_social","Estrutura de Comunicação Social"), + ("estrutura_de_recursos_humanos","Estrutura de Recursos Humanos"), + ("estrutura_de_recursos_humanos","Estrutura de Recursos Humanos"), + ("estrutura_de_secretaria","Estrutura de Secretaria"), + ("outros","Outros"), + ] + casa_legislativa = models.ForeignKey(CasaLegislativa) + nome = models.CharField('nome completo', max_length=60, blank=True) + nome.alphabetic_filter = True + nota = models.CharField(max_length=70, null=True, blank=True) + email = models.EmailField('e-mail', null=True, blank=True) + telefones = generic.GenericRelation('contatos.Telefone') + endereco = generic.GenericRelation('contatos.Endereco') + cargo = models.CharField(max_length=100, null=True, blank=True) + funcao = models.CharField(u'função', max_length=100, null=True, blank=True) + setor = models.CharField(max_length=100, choices = SETOR_CHOICES, default="outros") + tempo_de_servico = models.CharField(u'tempo de serviço', max_length=50, null=True, blank=True) + + class Meta: + ordering = ('nome',) + verbose_name = 'contato Casa Legislativa' + verbose_name_plural = 'contatos Casas Legislativa' + + def __unicode__(self): + return self.nome + +class PresidenteManager(models.Manager): + def get_query_set(self): + qs = super(PresidenteManager, self).get_query_set() + qs = qs.filter(cargo='Presidente') + return qs + +class Presidente(Funcionario): + class Meta: + proxy = True + + objects = PresidenteManager() + + def save(self, *args, **kwargs): + self.cargo = 'Presidente' + self.setor = 'presidencia' + return super(Presidente, self).save(*args, **kwargs) diff --git a/sigi/apps/contatos/admin.py b/sigi/apps/contatos/admin.py index 8c2a670..0ed6a50 100644 --- a/sigi/apps/contatos/admin.py +++ b/sigi/apps/contatos/admin.py @@ -32,11 +32,11 @@ class MunicipioAdmin(admin.ModelAdmin): 'codigo_microrregiao', 'uf__sigla') class TelefoneAdmin(admin.ModelAdmin): - list_display = ('codigo_area', 'numero', 'tipo', 'nota') - list_display_links = ('codigo_area', 'numero') - list_filter = ('codigo_area', 'tipo') + list_display = ('numero', 'tipo', 'nota') + list_display_links = ('numero',) + list_filter = ('tipo',) radio_fields = {'tipo': admin.VERTICAL} - search_fields = ('codigo_area', 'numero', 'tipo', 'nota') + search_fields = ('numero', 'tipo', 'nota') class ContatoAdmin(admin.ModelAdmin): list_display = ('nome', 'nota', 'email', 'municipio') diff --git a/sigi/apps/contatos/models.py b/sigi/apps/contatos/models.py index 9af4495..e3ae451 100644 --- a/sigi/apps/contatos/models.py +++ b/sigi/apps/contatos/models.py @@ -116,22 +116,17 @@ class Telefone(models.Model): ('X', 'Fax'), ('I', 'Indefinido'), ) - codigo_area = models.CharField( - 'código de área', - max_length=4, - help_text='Exemplo: 31.', - blank=True - ) numero = models.CharField( 'número', max_length=64, # TODO: diminuir tamanho de campo após migração de dados - help_text='Somente números.' + help_text='Exemplo: (31)8851-9898.', ) tipo = models.CharField( max_length=1, choices=TELEFONE_CHOICES, + default= 'I' ) - nota = models.CharField(max_length=70, blank=True) + nota = models.CharField(max_length=70, null=True, blank=True) # guarda o tipo do objeto (classe) vinculado a esse registro content_type = models.ForeignKey(ContentType) @@ -140,16 +135,11 @@ class Telefone(models.Model): content_object = generic.GenericForeignKey('content_type', 'object_id') class Meta: - ordering = ('codigo_area', 'numero') - # desabilitado para facilitar a migração de dados - # TODO: voltar quando estiver em produção - #unique_together = ('codigo_area', 'numero', 'tipo') + ordering = ('numero',) + unique_together = ('numero', 'tipo') def __unicode__(self): - if self.codigo_area: - return "(%s) %s" % (unicode(self.codigo_area), unicode(self.numero)) - else: - return unicode(self.numero) + return unicode(self.numero) class Contato(models.Model): """ Modelo generico para registrar contatos vinculados aos @@ -272,6 +262,6 @@ class Endereco(models.Model): verbose_name_plural = u'endereços' def __unicode__(self): - return self.tipo + ' ' + seld.logradouro + ', ' + self.numero \ + return self.tipo + ' ' + self.logradouro + ', ' + self.numero \ + ' ' + self.complemento + ' - ' + self.bairro diff --git a/sigi/apps/diagnosticos/admin.py b/sigi/apps/diagnosticos/admin.py index e79f997..b5f1c2a 100644 --- a/sigi/apps/diagnosticos/admin.py +++ b/sigi/apps/diagnosticos/admin.py @@ -1,32 +1,94 @@ # -*- coding: utf-8 -*- +from datetime import datetime from django.contrib import admin from eav.admin import BaseEntityAdmin, BaseSchemaAdmin -from sigi.apps.diagnosticos.models import Diagnostico, Pergunta, Escolha, Equipe, Anexo +from sigi.apps.diagnosticos.models import Diagnostico, Pergunta, Escolha, Equipe, Anexo, Categoria from sigi.apps.diagnosticos.forms import DiagnosticoForm + +""" +Actions do Admin +""" +def publicar_diagnostico(self, request, queryset): + for registro in queryset: + diagnostico = Diagnostico.objects.get(pk=registro.id) + diagnostico.publicado = True + diagnostico.data_publicacao= datetime.now() + diagnostico.save() + + # Enviando o email avisando que o diagnóstico foi publicado + diagnostico.email_diagnostico_publicado(diagnostico.responsavel.email_pessoal, request.get_host()) + self.message_user(request, "Diagnóstico(s) publicado(s) com sucesso!") +publicar_diagnostico.short_description = u""" + Definir diagnósticos como publicado""" + + +def despublicar_diagnostico(self, request, queryset): + queryset.update(publicado=False) +despublicar_diagnostico.short_description = u""" + Definir diagnósticos como não publicado""" + + class EquipeInline(admin.TabularInline): model = Equipe - extra = 4 class AnexosInline(admin.TabularInline): model = Anexo extra = 2 - exclude = ['data_pub',] + exclude = ['data_pub', ] + class AnexoAdmin(admin.ModelAdmin): date_hierarchy = 'data_pub' - exclude = ['data_pub',] + exclude = ['data_pub', ] list_display = ('arquivo', 'descricao', 'data_pub', 'diagnostico') raw_id_fields = ('diagnostico',) search_fields = ('descricao', 'diagnostico__id', 'arquivo', 'diagnostico__casa_legislativa__nome') + class DiagnosticoAdmin(BaseEntityAdmin): form = DiagnosticoForm + actions = [publicar_diagnostico, despublicar_diagnostico] inlines = (EquipeInline, AnexosInline) + search_fields = ('casa_legislativa__nome', 'responsavel',) + list_display = ('casa_legislativa', 'data_visita_inicio', 'data_visita_fim', 'responsavel', 'publicado') + list_filter = ('publicado', 'data_publicacao', 'data_visita_inicio', 'data_visita_fim') raw_id_fields = ('casa_legislativa',) + eav_fieldsets = [ + (u'00. Identificação do Diagnóstico', {'fields': ('responsavel', 'data_visita_inicio', 'data_visita_fim',)}), + (u'01. Identificação da Casa Legislativa', {'fields': ('casa_legislativa',)}), + (u'02. Identificação de Competências da Casa Legislativa', {'fields': ()}) + ] + + # popula o eav fieldsets ordenando as categorias e as perguntas + # para serem exibidas no admin + for categoria in Categoria.objects.all(): + # ordena as perguntas pelo title e utiliza o name no fieldset + perguntas_by_title = [(p.title, p.name) for p in categoria.perguntas.all()] + perguntas = [pergunta[1] for pergunta in sorted(perguntas_by_title)] + + eav_fieldsets.append((categoria, { + 'fields': tuple(perguntas), + 'classes': ['collapse'] + })) + + +class PerguntaAdmin (BaseSchemaAdmin): + search_fields = ('title', 'help_text', 'name',) + list_display = ('title', 'categoria', 'datatype', 'help_text', 'required') + list_filter = ('datatype', 'categoria', 'required') + + +class EscolhaAdmin(admin.ModelAdmin): + search_fields = ('title',) + list_display = ('title', 'schema', 'schema_to_open') + raw_id_fields = ('schema', 'schema_to_open') + ordering = ('schema', 'title') + admin.site.register(Diagnostico, DiagnosticoAdmin) -admin.site.register(Pergunta, BaseSchemaAdmin) -admin.site.register(Escolha) +admin.site.register(Pergunta, PerguntaAdmin) +admin.site.register(Escolha, EscolhaAdmin) admin.site.register(Anexo, AnexoAdmin) +admin.site.register(Categoria) diff --git a/sigi/apps/diagnosticos/decorators.py b/sigi/apps/diagnosticos/decorators.py new file mode 100644 index 0000000..f568ea7 --- /dev/null +++ b/sigi/apps/diagnosticos/decorators.py @@ -0,0 +1,23 @@ +# -*- coding: utf8 -*- + +from django.template import RequestContext +from django.shortcuts import render_to_response +from sigi.apps.diagnosticos.models import Diagnostico + +def validate_diagnostico(func): + def decorator(request, id_diagnostico, *args, **kwargs): + """ Retorna 404 caso o diagnostico esteja publicado + ou o usuario nao seja um membro da equipe + """ + try: + diagnostico = Diagnostico.objects.filter(publicado=False).get(pk=id_diagnostico) + if (request.user.servidor in diagnostico.membros): + # continua o processamento normal da view + return func(request, id_diagnostico, *args, **kwargs) + except Diagnostico.DoesNotExist: + pass + + # renderiza a pagina de 404 + context = RequestContext(request, {}) + return render_to_response('mobile/404.html', context) + return decorator diff --git a/sigi/apps/diagnosticos/fixtures/initial_data.json b/sigi/apps/diagnosticos/fixtures/initial_data.json new file mode 100644 index 0000000..c929fdb --- /dev/null +++ b/sigi/apps/diagnosticos/fixtures/initial_data.json @@ -0,0 +1 @@ +[{"pk": 3, "model": "diagnosticos.categoria", "fields": {"nome": "03. Levantamento de Infraestrutura F\u00edsica"}}, {"pk": 4, "model": "diagnosticos.categoria", "fields": {"nome": "04. Levantamento de Estrutura de TI"}}, {"pk": 5, "model": "diagnosticos.categoria", "fields": {"nome": "05. Organiza\u00e7\u00e3o do Processo Legislativo"}}, {"pk": 6, "model": "diagnosticos.categoria", "fields": {"nome": "06. Estrutura de Comunica\u00e7\u00e3o"}}, {"pk": 7, "model": "diagnosticos.categoria", "fields": {"nome": "07. Estrutura de Recursos Humanos"}}, {"pk": 8, "model": "diagnosticos.categoria", "fields": {"nome": "08. An\u00e1lise da Produ\u00e7\u00e3o Legislativa"}}, {"pk": 9, "model": "diagnosticos.categoria", "fields": {"nome": "09. Levantamento de Ferramentas de Gest\u00e3o"}}, {"pk": 10, "model": "diagnosticos.categoria", "fields": {"nome": "10. Considera\u00e7\u00f5es e Sugest\u00f5es"}}, {"pk": 3, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "se_a_sede_da_camara_municipal_e_cedida_especifique", "title": "01.1 Se a sede da C\u00e2mara Municipal \u00e9 cedida, especifique:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 89, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "se_sim_com_quantos_servidores", "title": "01.1 Se sim, com quantos servidores?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 10, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "a_camara_municipal_deseja_receber_consultoria_do_interlegis_para_a_implantacao_eou_atualizacao_de_uma_rede_local", "title": "01. A C\u00e2mara Municipal deseja receber consultoria do Interlegis para a implanta\u00e7\u00e3o e/ou atualiza\u00e7\u00e3o de uma rede local?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 95, "model": "diagnosticos.pergunta", "fields": {"categoria": 9, "sortable": false, "name": "a_camara_municipal_possui", "title": "01. A C\u00e2mara Municipal possui:", "datatype": "many", "required": false, "searched": false, "help_text": "(anexar os documentos impressos e em meio eletr\u00f4nico)", "filtered": false}}, {"pk": 48, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "a_camara_municipal_possui_area_estruturada_de_comunicacao", "title": "01. A C\u00e2mara Municipal possui \u00e1rea ESTRUTURADA DE comunica\u00e7\u00e3o? ", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 88, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "a_camara_municipal_possui_um_quadro_de_pessoal_definido_para_auxiliar_os_trabalhos_da_mesa_diretora", "title": "01. A C\u00e2mara Municipal possui um quadro de pessoal definido para auxiliar os trabalhos da Mesa Diretora? ", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 2, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "a_sede_da_camara_municipal_e", "title": "01. A sede da C\u00e2mara Municipal \u00e9:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 96, "model": "diagnosticos.pergunta", "fields": {"categoria": 10, "sortable": false, "name": "consideracoes_gerais", "title": "01. Considera\u00e7\u00f5es Gerais", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 27, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "onde_se_inicia_o_registro_do_processo_legislativo_na_camara_municipal", "title": "01. Onde se inicia o registro do Processo Legislativo na C\u00e2mara Municipal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 101, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_servidores_da_camara_municipal", "title": "01. Qual o n\u00famero total de servidores da C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "(efetivos, comissionados, tempor\u00e1rios e celetistas, n\u00e3o incluir parlamentares, empregados terceirizados e estagi\u00e1rios)", "filtered": false}}, {"pk": 103, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "a_maioria_dos_parlamentares_possui", "title": "02.1. A maioria dos parlamentares possui:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 12, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "escreva_um_exemplo_de_e_mail_corporativo", "title": "02.1 Escreva um exemplo de e-mail corporativo:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 29, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "se_possui_alguma_quais_sao_elas", "title": "02.1 Se possui alguma, quais s\u00e3o elas?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 13, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "se_nao_a_camara_municipal_deseja_receber_orientacao_do_interlegis_para_implantar_e_mail_corporativo", "title": "02.2 Se n\u00e3o, a C\u00e2mara Municipal deseja receber orienta\u00e7\u00e3o do Interlegis para implantar e-mail corporativo?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 11, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "a_camara_municipal_disponibiliza_e_mail_corporativo_para_parlamentares_servidores", "title": "02. A C\u00e2mara Municipal disponibiliza e-mail CORPORATIVO, para parlamentares servidores?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 4, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "o_imovel_onde_funciona_a_camara_municipal_e_tombado_pelo_patrimonio_historico", "title": "02. O im\u00f3vel onde funciona a C\u00e2mara Municipal \u00e9 tombado pelo patrim\u00f4nio hist\u00f3rico?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 90, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "qual_a_periodicidade_de_mudanca_da_mesa_diretora", "title": "02. Qual a periodicidade de mudan\u00e7a da Mesa Diretora?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 102, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_parlamentares_da_camara_municipal", "title": "02. Qual o n\u00famero total de parlamentares da C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": " (n\u00e3o incluir servidores de qualquer tipo, empregados terceirizados e estagi\u00e1rios)", "filtered": false}}, {"pk": 28, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "quantas_comissoes_permanentes_a_camara_municipal_possui", "title": "02. Quantas Comiss\u00f5es Permanentes a C\u00e2mara Municipal possui?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 49, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "quantas_pessoas_trabalham_na_area_de_comunicacao_na_camara_municipal", "title": "02. Quantas pessoas trabalham na \u00e1rea de comunica\u00e7\u00e3o na C\u00e2mara Municipal? ", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 97, "model": "diagnosticos.pergunta", "fields": {"categoria": 10, "sortable": false, "name": "sugestoes_para_a_area_de_ti", "title": "02. Sugest\u00f5es para a \u00c1rea de TI", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 105, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "a_maioria_dos_servidores_efetivos_concursados_possui", "title": "03.1. A maioria dos servidores EFETIVOS (concursados) possui:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 92, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "em_quais_datas_sao_realizada_as_sessoes_da_camara_municipal", "title": "03.1 Em quais datas s\u00e3o realizada as sess\u00f5es da C\u00e2mara Municipal?", "datatype": "text", "required": false, "searched": false, "help_text": "(dias da semana ou determinadas data do m\u00eas)", "filtered": false}}, {"pk": 7, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "se_sim_especifique_quais_sao_as_restricoes_a_obras_civis_no_imovel_onde_esta_instalada_a_camara_municipal", "title": "03.1 Se sim, especifique quais s\u00e3o as restri\u00e7\u00f5es a obras civis no im\u00f3vel onde est\u00e1 instalada a C\u00e2mara Municipal?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 30, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_camara_municipal_possui_as_comissoes_ou_conselhos_para_debater_os_seguintes_temas", "title": "03. A C\u00e2mara Municipal possui as Comiss\u00f5es ou Conselhos para debater os seguintes temas:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 50, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "das_pessoas_que_trabalham_exclusivamente_na_area_de_comunicacao_quantas_tem_o_nivel_de_escolaridade_fundamental", "title": "03. Das pessoas que trabalham EXCLUSIVAMENTE na \u00e1rea de Comunica\u00e7\u00e3o, quantas tem o n\u00edvel de escolaridade fundamental?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 5, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "existem_restricoes_a_obras_civis_no_imovel_onde_esta_instalada_a_camara_municipal", "title": "03. Existem restri\u00e7\u00f5es a obras civis no im\u00f3vel onde est\u00e1 instalada a C\u00e2mara Municipal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 91, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "qual_a_periodicidade_das_sessoes_da_camara_municipal", "title": "03. Qual a periodicidade das sess\u00f5es da C\u00e2mara Municipal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 104, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_servidores_efetivos_da_camara_municipal", "title": "03. Qual o n\u00famero total de servidores efetivos da C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "(empossados ap\u00f3s concurso p\u00fablico)", "filtered": false}}, {"pk": 14, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "quantos_servidores_de_rede_possui_a_camara_municipal", "title": "03 Quantos servidores de rede possui a C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 98, "model": "diagnosticos.pergunta", "fields": {"categoria": 10, "sortable": false, "name": "sugestoes_para_a_area_de_comunicacao", "title": "03. Sugest\u00f5es para a \u00c1rea de Comunica\u00e7\u00e3o", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 108, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "caso_os_parlamentares_possam_nomear_servidores_comissionados_qual_e_o_limite_por_parlamentar", "title": "04.1.1 Caso os parlamentares possam nomear servidores comissionados, qual \u00e9 o limite por parlamentar?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 107, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "caso_exista_servidores_comissionados_quem_tem_poder_para_nomea_los", "title": "04.1. Caso exista servidores comissionados quem tem poder para nomea-los?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 94, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "caso_sejam_outros_meios_para_auxiliar_especifique", "title": "04.1 Caso sejam outros meios para auxiliar, especifique:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 9, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "onde_sera_a_nova_sede_da_camara_municipal", "title": "04.1 Onde ser\u00e1 a nova sede da C\u00e2mara Municipal?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 44, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "o_registro_de_tramitacao_e", "title": "04.1 O registro de tramita\u00e7\u00e3o \u00e9:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 109, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "a_maioria_dos_servidores_comissionados_nomeados_possui", "title": "04.2. A maioria dos servidores comissionados (nomeados) possui:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 51, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "das_pessoas_que_trabalham_exclusivamente_na_area_de_comunicacao_quantas_tem_o_nivel_de_escolaridade_medio", "title": "04. Das pessoas que trabalham EXCLUSIVAMENTE na \u00e1rea de Comunica\u00e7\u00e3o, quantas tem o n\u00edvel de escolaridade m\u00e9dio?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 31, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "e_mantido_registro_da_tramitacao_das_proposicoes_legislativas", "title": "04. \u00c9 mantido registro da tramita\u00e7\u00e3o das proposi\u00e7\u00f5es legislativas?", "datatype": "one", "required": false, "searched": false, "help_text": " (encaminhamentos, vota\u00e7\u00f5es, discuss\u00f5es, emendas etc.)", "filtered": false}}, {"pk": 8, "model": "diagnosticos.pergunta", "fields": {"categoria": 3, "sortable": false, "name": "existe_projeto_em_tramitacao_ou_decisao_para_a_mudanca_de_sede_da_camara_municipal_nos_proximos_5_anos", "title": "04. Existe projeto (em tramita\u00e7\u00e3o) ou decis\u00e3o para a mudan\u00e7a de sede da C\u00e2mara Municipal nos pr\u00f3ximos 5 anos?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 106, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_servidores_comissionados_nomeados", "title": "04. Qual o n\u00famero total de servidores comissionados (nomeados)?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 15, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "quantas_estacoes_de_trabalho_computadores_possui_a_camara_municipal", "title": "04 Quantas esta\u00e7\u00f5es de trabalho (computadores) possui a C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 93, "model": "diagnosticos.pergunta", "fields": {"categoria": 8, "sortable": false, "name": "que_meios_auxiliam_os_parlamentares_da_camara_municipal_na_fiscalizacao_e_controle_das_acoes_do_executivo_quanto_a_execucao_orcamentaria", "title": "04. Que meios auxiliam os parlamentares da C\u00e2mara Municipal na fiscaliza\u00e7\u00e3o e controle das a\u00e7\u00f5es do executivo quanto \u00e0 execu\u00e7\u00e3o or\u00e7amentaria?", "datatype": "many", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 99, "model": "diagnosticos.pergunta", "fields": {"categoria": 10, "sortable": false, "name": "sugestoes_para_a_area_de_capacitacao", "title": "04. Sugest\u00f5es para a \u00c1rea de Capacita\u00e7\u00e3o", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 45, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_organizacao_do_arquivo_e", "title": "05.1 A organiza\u00e7\u00e3o do arquivo \u00e9:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 32, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_camara_municipal_conta_com_uma_area_especifica_de_arquivo", "title": "05. A C\u00e2mara Municipal conta com uma \u00e1rea espec\u00edfica de arquivo?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 52, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "das_pessoas_que_trabalham_exclusivamente_na_area_de_comunicacao_quantas_tem_o_nivel_de_escolaridade_superior", "title": "05. Das pessoas que trabalham EXCLUSIVAMENTE na \u00e1rea de Comunica\u00e7\u00e3o, quantas tem o n\u00edvel de escolaridade superior?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 110, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_servidores_temporarios_da_camara_municipal", "title": "05. Qual o n\u00famero total de servidores tempor\u00e1rios da C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 16, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "quantos_notebooks_possui_a_camara_municipal", "title": "05 Quantos notebook\u2019s possui a C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 100, "model": "diagnosticos.pergunta", "fields": {"categoria": 10, "sortable": false, "name": "sugestoes_para_a_area_de_informacao", "title": "05. Sugest\u00f5es para a \u00c1rea de Informa\u00e7\u00e3o", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 54, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "especifique_quais_outros_meios_de_comunicacao_interna_a_camara_utiliza", "title": "06.1 Especifique quais outros meios de comunica\u00e7\u00e3o interna a C\u00e2mara utiliza:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 33, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "ha_quadro_de_pessoal_especifico_para_trabalhos_do_arquivo", "title": "06. H\u00e1 quadro de pessoal espec\u00edfico para trabalhos do arquivo?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 53, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "quais_sao_os_meios_de_comunicacao_interna_da_camaraconsiderar_apenas_os_meios_de_comunicacao_desenvolvidas_ou_pertencentes_a_propria_camara", "title": "06. Quais s\u00e3o os meios de comunica\u00e7\u00e3o INTERNA da C\u00e2mara?Considerar apenas os meios de comunica\u00e7\u00e3o desenvolvidas ou pertencentes \u00e0 pr\u00f3pria C\u00e2mara.", "datatype": "many", "required": false, "searched": false, "help_text": "(comunica\u00e7\u00e3o com servidores e/ou vereadores)", "filtered": false}}, {"pk": 111, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_empregados_celetistas_da_camara_municipal", "title": "06. Qual o n\u00famero total de empregados celetistas da C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": " (regidos pela Consolida\u00e7\u00e3o das Leis do Trabalho)", "filtered": false}}, {"pk": 17, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "quantos_netbooks_possui_a_camara_municipal", "title": "06 Quantos netbook\u2019s possui a C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 46, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_organizacao_da_biblioteca_legislativa_e", "title": "07.1 A organiza\u00e7\u00e3o da Biblioteca Legislativa \u00e9", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 113, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "caso_exista_empregados_terceirizados_quais_funcoes_eles_desempenham", "title": "07.1. Caso exista empregados terceirizados quais fun\u00e7\u00f5es eles desempenham?", "datatype": "many", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 56, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "especifique", "title": "07.1 Especifique:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 55, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "a_area_de_comunicacao_possui_caixa_postal_propria_para_envio_e_recebimento_de_e_mails", "title": "07. A \u00e1rea de Comunica\u00e7\u00e3o possui caixa postal pr\u00f3pria para envio e recebimento de e-mails? ", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 34, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_camara_possui_uma_biblioteca_legislativa", "title": "07. A C\u00e2mara possui uma Biblioteca Legislativa?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 112, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "qual_o_numero_total_de_empregados_terceirizados_da_camara_municipal", "title": "07. Qual o n\u00famero total de empregados terceirizados da C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 18, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "quantos_tablets_possui_a_camara_municipal", "title": "07 Quantos tablet\u2019s possui a C\u00e2mara Municipal?", "datatype": "float", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 58, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_norma", "title": "08.1 Qual a norma?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 19, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "a_camara_municipal_possui_conexao_de_banda_larga_com_a_internet", "title": "08. A C\u00e2mara Municipal possui conex\u00e3o de banda larga com a internet?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 114, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "a_camara_municipal_possui_escola_do_legislativo", "title": "08. A C\u00e2mara Municipal possui \u201cEscola do Legislativo\u201d?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 57, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "as_atividades_de_eventos_e_cerimonial_da_camara_estao_normatizados", "title": "08. As atividades de eventos e cerimonial da C\u00e2mara est\u00e3o normatizados?:", "datatype": "one", "required": false, "searched": false, "help_text": "(por ato, resolu\u00e7\u00e3o, regimento interno, portaria etc.)", "filtered": false}}, {"pk": 35, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "ha_quadro_de_pessoal_especifico_para_trabalhos_da_biblioteca_legislativa", "title": "08. H\u00e1 quadro de pessoal espec\u00edfico para trabalhos da biblioteca legislativa?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 22, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "se_a_camara_faz_uso_de_outro_sistema_de_apoio_ao_processo_legislativo_especifique", "title": "09.1.2 Se a C\u00e2mara faz uso de outro sistema de apoio ao Processo Legislativo, especifique:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 21, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "o_sistema_pode_ser_acessado_via_internet_por_qualquer_cidadao", "title": "09.1 O sistema pode ser acessado via internet por qualquer cidad\u00e3o?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 60, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_do_informativo", "title": "09.1 Qual a periodicidade de veicula\u00e7\u00e3o do informativo?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 61, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_atualizacao_do_portal", "title": "09.2 Qual a periodicidade de atualiza\u00e7\u00e3o do portal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 62, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_do_jornal", "title": "09.3 Qual a periodicidade de veicula\u00e7\u00e3o do jornal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 63, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_da_revista", "title": "09.4 Qual a periodicidade de veicula\u00e7\u00e3o da revista?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 64, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_do_programa_de_radio", "title": "09.5 Qual a periodicidade de veicula\u00e7\u00e3o do programa de r\u00e1dio?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 65, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_do_programa_de_radio_web", "title": "09.6 Qual a periodicidade de veicula\u00e7\u00e3o do programa de r\u00e1dio web?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 66, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_do_programa_de_tv", "title": "09.7 Qual a periodicidade de veicula\u00e7\u00e3o do programa de TV?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 67, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_do_programa_de_tv_web", "title": "09.8 Qual a periodicidade de veicula\u00e7\u00e3o do programa de TV web?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 20, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "a_camara_utiliza_um_sistema_de_apoio_ao_processo_legislativo", "title": "09. A C\u00e2mara utiliza um sistema de apoio ao Processo Legislativo?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 115, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "ha_planejamento_ou_execucao_permanente_de_acoes_de_treinamento", "title": "09. H\u00e1 planejamento ou execu\u00e7\u00e3o permanente de a\u00e7\u00f5es de treinamento?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 59, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "quais_sao_os_meios_de_comunicacao_com_a_comunidade_que_a_camara_possui", "title": "09. Quais s\u00e3o os meios de comunica\u00e7\u00e3o com a comunidade que a C\u00e2mara possui?", "datatype": "many", "required": false, "searched": false, "help_text": "(Registrar apenas ve\u00edculos pertencentes \u00e0 c\u00e2mara)", "filtered": false}}, {"pk": 36, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "qual_a_data_da_ultima_atualizacao_da_lei_organica_municial_da_camara_municipal", "title": "09. Qual a data da \u00faltima atualiza\u00e7\u00e3o da LEI ORG\u00c2NICA MUNICIAL da C\u00e2mara Municipal?", "datatype": "date", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 69, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_comunicacao_atraves_de_informativo", "title": "10.1 Qual a periodicidade de comunica\u00e7\u00e3o atrav\u00e9s de informativo?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 24, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "qual_o_endereco_do_portal", "title": "10.1 Qual o endere\u00e7o do portal?", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 70, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_envio_de_artigos_para_o_portal", "title": "10.2 Qual a periodicidade de envio de artigos para o portal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 71, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_envio_de_materias_ou_publicidade_para_o_jornal", "title": "10.3 Qual a periodicidade de envio de mat\u00e9rias ou publicidade para o jornal?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 72, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_envio_de_materias_ou_publicidade_para_a_revista", "title": "10.4 Qual a periodicidade de envio de mat\u00e9rias ou publicidade para a revista?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 73, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_de_materias_ou_publicidade_no_programa_de_radio", "title": "10.5 Qual a periodicidade de veicula\u00e7\u00e3o de mat\u00e9rias ou publicidade no programa de r\u00e1dio?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 74, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_de_materias_ou_publicidade_no_programa_de_radio_web", "title": "10.6 Qual a periodicidade de veicula\u00e7\u00e3o de mat\u00e9rias ou publicidade no programa de r\u00e1dio web?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 75, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_de_programas_ou_publicidade_na_tv", "title": "10.7 Qual a periodicidade de veicula\u00e7\u00e3o de programas ou publicidade na TV?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 76, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_periodicidade_de_veiculacao_de_programas_ou_publicidade_na_tv_web", "title": "10.8 Qual a periodicidade de veicula\u00e7\u00e3o de programas ou publicidade na TV web?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 68, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "a_camara_desenvolve_alguma_acao_de_comunicacao_ou_relacionamento_com_a_comunidade_local", "title": "10. A C\u00e2mara desenvolve alguma a\u00e7\u00e3o de comunica\u00e7\u00e3o ou relacionamento com a comunidade local? ", "datatype": "many", "required": false, "searched": false, "help_text": " (registrar apenas os casos em que os ve\u00edculos n\u00e3o perten\u00e7am \u00e0 c\u00e2mara)", "filtered": false}}, {"pk": 23, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "a_camara_municipal_possui_portal_de_internet", "title": "10. A C\u00e2mara Municipal possui portal de internet?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 116, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "como_sao_realizados_o_planejamento_ou_execucao_de_acoes_de_treinamento", "title": "10. Como s\u00e3o realizados o planejamento ou execu\u00e7\u00e3o de a\u00e7\u00f5es de treinamento?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 37, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "qual_a_data_da_ultima_atualizacao_do_regimento_interno_da_camara_municipal", "title": "10. Qual a data da \u00faltima atualiza\u00e7\u00e3o do REGIMENTO INTERNO da C\u00e2mara Municipal?", "datatype": "date", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 26, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "se_a_camara_faz_uso_de_outro_sistema_de_apoio_a_atividade_parlamentar_especifique", "title": "11.1. Se a C\u00e2mara faz uso de outro sistema de apoio \u00e0 Atividade Parlamentar, especifique:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 117, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "a_camara_municipal_possui_setor_especifico_de_treinamento", "title": "11. A C\u00e2mara Municipal possui setor espec\u00edfico de treinamento?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 25, "model": "diagnosticos.pergunta", "fields": {"categoria": 4, "sortable": false, "name": "a_camara_utiliza_um_sistema_de_apoio_a_atividade_parlamentar", "title": "11. A C\u00e2mara utiliza um sistema de apoio \u00e0 Atividade Parlamentar?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 38, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "de_que_forma_a_camara_resolve_duvidas_na_aplicacao_do_regimento_interno", "title": "11. De que forma a C\u00e2mara resolve d\u00favidas na aplica\u00e7\u00e3o do Regimento Interno:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 77, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_da_radio_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "11. Qual a import\u00e2ncia da r\u00e1dio como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 118, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "como_a_camara_municipal_proporciona_atividades_de_treinamento_presencial_para_seus_servidores", "title": "12. Como a C\u00e2mara Municipal proporciona atividades de treinamento PRESENCIAL para seus servidores?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 39, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "de_que_forma_a_camara_resolve_duvidas_na_aplicacao_da_lei_organica_do_municipio", "title": "12. De que forma a C\u00e2mara resolve d\u00favidas na aplica\u00e7\u00e3o da Lei Org\u00e2nica do Munic\u00edpio:", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 78, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_da_tv_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "12. Qual a import\u00e2ncia da TV como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 40, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_camara_municipal_deseja_receber_consultoria_do_interlegis_para_a_revisaoatualizacao_do_regimento_interno", "title": "13. A C\u00e2mara Municipal deseja receber consultoria do Interlegis para a revis\u00e3o/atualiza\u00e7\u00e3o do Regimento Interno?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 119, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "a_camara_municipal_proporciona_atividades_de_treinamento_a_distancia_para_seus_servidores", "title": "13. A C\u00e2mara Municipal proporciona atividades de treinamento A DIST\u00c2NCIA para seus servidores?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 79, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_da_internet_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "13. Qual a import\u00e2ncia da internet como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 47, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "a_camara_municipal_deseja_receber_consultoria_do_interlegis_para_a_revisaoatualizacao_da_lei_organica_do_municipio", "title": "14. A C\u00e2mara Municipal deseja receber consultoria do Interlegis para a revis\u00e3o/atualiza\u00e7\u00e3o da Lei Org\u00e2nica do Munic\u00edpio?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 120, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "parlamentares_da_camara_ja_participaram_de_cursos_via_internet", "title": "14. Parlamentares da C\u00e2mara j\u00e1 participaram de cursos via internet?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 80, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_do_jornal_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "14. Qual a import\u00e2ncia do jornal como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 41, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "os_vereadores_possuem_gabinetes_proprios_e_privativos", "title": "15. Os vereadores possuem gabinetes pr\u00f3prios e privativos?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 81, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_da_revista_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "15. Qual a import\u00e2ncia da revista como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 121, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "servidores_da_camara_ja_participaram_de_cursos_via_internet", "title": "15. Servidores da C\u00e2mara j\u00e1 participaram de cursos via internet?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 43, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "descreva_como_e_normatizado", "title": "16.1 Descreva como \u00e9 normatizado:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 122, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "descreva_5_cursos_prioritarios_para_treinamento_de_parlamentares_da_camara_municipal", "title": "16. Descreva 5 cursos priorit\u00e1rios para treinamento de PARLAMENTARES da C\u00e2mara Municipal:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 42, "model": "diagnosticos.pergunta", "fields": {"categoria": 5, "sortable": false, "name": "o_processo_de_aprovacao_e_de_fiscalizacao_do_orcamento_municipal_e_normatizado", "title": "16. O processo de aprova\u00e7\u00e3o e de fiscaliza\u00e7\u00e3o do or\u00e7amento municipal \u00e9 normatizado?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 82, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_de_outras_midias_impressas_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "16. Qual a import\u00e2ncia de outras m\u00eddias impressas como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "(faixas, outdoors, cartazes, placas)", "filtered": false}}, {"pk": 123, "model": "diagnosticos.pergunta", "fields": {"categoria": 7, "sortable": false, "name": "descreva_5_cursos_prioritarios_para_treinamento_de_servidores_da_camara_municipal", "title": "17. Descreva 5 cursos priorit\u00e1rios para treinamento de SERVIDORES da C\u00e2mara Municipal:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 83, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "qual_a_importancia_de_outros_servicos_locais_como_veiculo_de_comunicacao_para_a_comunidade_local", "title": "17. Qual a import\u00e2ncia de outros servi\u00e7os locais como ve\u00edculo de comunica\u00e7\u00e3o para a comunidade local?", "datatype": "one", "required": false, "searched": false, "help_text": "(carros de som, etc)", "filtered": false}}, {"pk": 85, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "se_a_camara_transmite_sessoes_em_outros_veiculos_especifique", "title": "18.1 Se a C\u00e2mara transmite sess\u00f5es em outros ve\u00edculos, especifique:", "datatype": "text", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 84, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "a_camara_transmite_sessoes", "title": "18. A C\u00e2mara transmite sess\u00f5es? ", "datatype": "many", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 86, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "a_camara_oferece_algum_mecanismo_junto_a_populacao_a_fim_de_responder_perguntas_ou_ouvir_criticas_e_sugestoes", "title": "19. A C\u00e2mara oferece algum mecanismo junto \u00e0 popula\u00e7\u00e3o a fim de responder perguntas ou ouvir cr\u00edticas e sugest\u00f5es?", "datatype": "many", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 87, "model": "diagnosticos.pergunta", "fields": {"categoria": 6, "sortable": false, "name": "a_camara_possui_mailing_list_isto_e_cadastro_de_contatos_enderecos_e_mails_e_telefones_de_jornalistas_jornais_radios_ou_outros_meios_de_comunicacao", "title": "20. A C\u00e2mara possui mailing list, isto \u00e9, cadastro de contatos, endere\u00e7os, e-mails e telefones de jornalistas, jornais, r\u00e1dios ou outros meios de comunica\u00e7\u00e3o?", "datatype": "one", "required": false, "searched": false, "help_text": "", "filtered": false}}, {"pk": 6, "model": "diagnosticos.escolha", "fields": {"schema": 2, "schema_to_open": 3, "title": "Cedida por \u00f3rg\u00e3o Particular"}}, {"pk": 7, "model": "diagnosticos.escolha", "fields": {"schema": 4, "schema_to_open": null, "title": "Sim"}}, {"pk": 8, "model": "diagnosticos.escolha", "fields": {"schema": 4, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 9, "model": "diagnosticos.escolha", "fields": {"schema": 5, "schema_to_open": 7, "title": "Sim"}}, {"pk": 10, "model": "diagnosticos.escolha", "fields": {"schema": 5, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 12, "model": "diagnosticos.escolha", "fields": {"schema": 8, "schema_to_open": 9, "title": "Sim"}}, {"pk": 13, "model": "diagnosticos.escolha", "fields": {"schema": 8, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 14, "model": "diagnosticos.escolha", "fields": {"schema": 10, "schema_to_open": null, "title": "Sim"}}, {"pk": 15, "model": "diagnosticos.escolha", "fields": {"schema": 10, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 16, "model": "diagnosticos.escolha", "fields": {"schema": 11, "schema_to_open": 12, "title": "Sim"}}, {"pk": 17, "model": "diagnosticos.escolha", "fields": {"schema": 11, "schema_to_open": 13, "title": "N\u00e3o"}}, {"pk": 18, "model": "diagnosticos.escolha", "fields": {"schema": 13, "schema_to_open": null, "title": "Sim"}}, {"pk": 19, "model": "diagnosticos.escolha", "fields": {"schema": 13, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 20, "model": "diagnosticos.escolha", "fields": {"schema": 19, "schema_to_open": null, "title": "Sim"}}, {"pk": 21, "model": "diagnosticos.escolha", "fields": {"schema": 19, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 23, "model": "diagnosticos.escolha", "fields": {"schema": 20, "schema_to_open": 21, "title": "Sim, utilizando outro sistema"}}, {"pk": 24, "model": "diagnosticos.escolha", "fields": {"schema": 20, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 25, "model": "diagnosticos.escolha", "fields": {"schema": 21, "schema_to_open": 22, "title": "Sim"}}, {"pk": 26, "model": "diagnosticos.escolha", "fields": {"schema": 21, "schema_to_open": 22, "title": "N\u00e3o"}}, {"pk": 27, "model": "diagnosticos.escolha", "fields": {"schema": 23, "schema_to_open": 24, "title": "Sim, utilizando o Portal Modelo do Interlegis"}}, {"pk": 28, "model": "diagnosticos.escolha", "fields": {"schema": 23, "schema_to_open": 24, "title": "Sim, utilizando outra ferramenta"}}, {"pk": 29, "model": "diagnosticos.escolha", "fields": {"schema": 23, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 30, "model": "diagnosticos.escolha", "fields": {"schema": 25, "schema_to_open": null, "title": "Sim, utilizando o SAAP do Interlegis"}}, {"pk": 31, "model": "diagnosticos.escolha", "fields": {"schema": 25, "schema_to_open": 26, "title": "Sim, utilizando outro sistema"}}, {"pk": 32, "model": "diagnosticos.escolha", "fields": {"schema": 25, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 33, "model": "diagnosticos.escolha", "fields": {"schema": 27, "schema_to_open": null, "title": "Protocolo Legislativo manual"}}, {"pk": 34, "model": "diagnosticos.escolha", "fields": {"schema": 27, "schema_to_open": null, "title": "Protocolo Legislativo informatizado"}}, {"pk": 35, "model": "diagnosticos.escolha", "fields": {"schema": 27, "schema_to_open": null, "title": "Secretaria-Geral da Mesa"}}, {"pk": 36, "model": "diagnosticos.escolha", "fields": {"schema": 27, "schema_to_open": null, "title": "Gabinete da Presid\u00eancia"}}, {"pk": 37, "model": "diagnosticos.escolha", "fields": {"schema": 27, "schema_to_open": null, "title": "Livro de expediente"}}, {"pk": 38, "model": "diagnosticos.escolha", "fields": {"schema": 27, "schema_to_open": null, "title": "Outro"}}, {"pk": 39, "model": "diagnosticos.escolha", "fields": {"schema": 30, "schema_to_open": null, "title": "Constitucionalidade"}}, {"pk": 40, "model": "diagnosticos.escolha", "fields": {"schema": 30, "schema_to_open": null, "title": "Or\u00e7amento e Finan\u00e7as"}}, {"pk": 41, "model": "diagnosticos.escolha", "fields": {"schema": 30, "schema_to_open": null, "title": "Fiscaliza\u00e7\u00e3o"}}, {"pk": 42, "model": "diagnosticos.escolha", "fields": {"schema": 30, "schema_to_open": null, "title": "\u00c9tica"}}, {"pk": 43, "model": "diagnosticos.escolha", "fields": {"schema": 30, "schema_to_open": null, "title": "N\u00e3o possui"}}, {"pk": 44, "model": "diagnosticos.escolha", "fields": {"schema": 31, "schema_to_open": 44, "title": "Sim"}}, {"pk": 46, "model": "diagnosticos.escolha", "fields": {"schema": 31, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 47, "model": "diagnosticos.escolha", "fields": {"schema": 32, "schema_to_open": 45, "title": "Sim"}}, {"pk": 50, "model": "diagnosticos.escolha", "fields": {"schema": 32, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 51, "model": "diagnosticos.escolha", "fields": {"schema": 33, "schema_to_open": null, "title": "Sim"}}, {"pk": 52, "model": "diagnosticos.escolha", "fields": {"schema": 33, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 53, "model": "diagnosticos.escolha", "fields": {"schema": 34, "schema_to_open": 46, "title": "Sim"}}, {"pk": 56, "model": "diagnosticos.escolha", "fields": {"schema": 34, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 57, "model": "diagnosticos.escolha", "fields": {"schema": 35, "schema_to_open": null, "title": "Sim"}}, {"pk": 59, "model": "diagnosticos.escolha", "fields": {"schema": 38, "schema_to_open": null, "title": "Decide internamente"}}, {"pk": 61, "model": "diagnosticos.escolha", "fields": {"schema": 39, "schema_to_open": null, "title": "Decide internamente"}}, {"pk": 62, "model": "diagnosticos.escolha", "fields": {"schema": 39, "schema_to_open": null, "title": "Realiza consulta externa ou Recorre a \u00f3rg\u00e3o externo"}}, {"pk": 63, "model": "diagnosticos.escolha", "fields": {"schema": 40, "schema_to_open": null, "title": "Sim"}}, {"pk": 66, "model": "diagnosticos.escolha", "fields": {"schema": 40, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 67, "model": "diagnosticos.escolha", "fields": {"schema": 41, "schema_to_open": null, "title": "Sim"}}, {"pk": 68, "model": "diagnosticos.escolha", "fields": {"schema": 41, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 69, "model": "diagnosticos.escolha", "fields": {"schema": 42, "schema_to_open": null, "title": "Sim"}}, {"pk": 70, "model": "diagnosticos.escolha", "fields": {"schema": 42, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 71, "model": "diagnosticos.escolha", "fields": {"schema": 44, "schema_to_open": null, "title": "Manual"}}, {"pk": 72, "model": "diagnosticos.escolha", "fields": {"schema": 44, "schema_to_open": null, "title": "Informatizado"}}, {"pk": 73, "model": "diagnosticos.escolha", "fields": {"schema": 45, "schema_to_open": null, "title": "Manual"}}, {"pk": 74, "model": "diagnosticos.escolha", "fields": {"schema": 45, "schema_to_open": null, "title": "Informatizada"}}, {"pk": 75, "model": "diagnosticos.escolha", "fields": {"schema": 45, "schema_to_open": null, "title": "Inexistente"}}, {"pk": 76, "model": "diagnosticos.escolha", "fields": {"schema": 46, "schema_to_open": null, "title": "Manual"}}, {"pk": 77, "model": "diagnosticos.escolha", "fields": {"schema": 46, "schema_to_open": null, "title": "Informatizada"}}, {"pk": 78, "model": "diagnosticos.escolha", "fields": {"schema": 46, "schema_to_open": null, "title": "Inexistente"}}, {"pk": 79, "model": "diagnosticos.escolha", "fields": {"schema": 47, "schema_to_open": null, "title": "Sim"}}, {"pk": 80, "model": "diagnosticos.escolha", "fields": {"schema": 47, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 81, "model": "diagnosticos.escolha", "fields": {"schema": 48, "schema_to_open": null, "title": "Sim"}}, {"pk": 82, "model": "diagnosticos.escolha", "fields": {"schema": 48, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 83, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Quadro de avisos (mural)"}}, {"pk": 84, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Reuni\u00f5es internas"}}, {"pk": 85, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Boletim impresso"}}, {"pk": 86, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Boletim eletr\u00f4nico"}}, {"pk": 87, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Comunica\u00e7\u00e3o via e-mail"}}, {"pk": 88, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Jornal-Mural"}}, {"pk": 89, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Jornal"}}, {"pk": 90, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Revista"}}, {"pk": 91, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Folheteria (folders, panfletos)"}}, {"pk": 92, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Contato via telefone"}}, {"pk": 93, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Intranet"}}, {"pk": 94, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Circular"}}, {"pk": 95, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Convite"}}, {"pk": 96, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Carta"}}, {"pk": 97, "model": "diagnosticos.escolha", "fields": {"schema": 53, "schema_to_open": null, "title": "Outros"}}, {"pk": 98, "model": "diagnosticos.escolha", "fields": {"schema": 55, "schema_to_open": 56, "title": "Sim"}}, {"pk": 99, "model": "diagnosticos.escolha", "fields": {"schema": 55, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 100, "model": "diagnosticos.escolha", "fields": {"schema": 57, "schema_to_open": 58, "title": "Sim"}}, {"pk": 101, "model": "diagnosticos.escolha", "fields": {"schema": 57, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 102, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "Informativo"}}, {"pk": 103, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "Portal de Internet"}}, {"pk": 104, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "Jornal"}}, {"pk": 105, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "Revista"}}, {"pk": 106, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "R\u00e1dio"}}, {"pk": 107, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "R\u00e1dio web"}}, {"pk": 108, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "TV"}}, {"pk": 109, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "TV web"}}, {"pk": 110, "model": "diagnosticos.escolha", "fields": {"schema": 59, "schema_to_open": null, "title": "Outros"}}, {"pk": 112, "model": "diagnosticos.escolha", "fields": {"schema": 60, "schema_to_open": null, "title": "Semanal"}}, {"pk": 113, "model": "diagnosticos.escolha", "fields": {"schema": 60, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 114, "model": "diagnosticos.escolha", "fields": {"schema": 60, "schema_to_open": null, "title": "Mensal"}}, {"pk": 115, "model": "diagnosticos.escolha", "fields": {"schema": 60, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 116, "model": "diagnosticos.escolha", "fields": {"schema": 60, "schema_to_open": null, "title": "Outra"}}, {"pk": 117, "model": "diagnosticos.escolha", "fields": {"schema": 61, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 118, "model": "diagnosticos.escolha", "fields": {"schema": 61, "schema_to_open": null, "title": "Semanal"}}, {"pk": 119, "model": "diagnosticos.escolha", "fields": {"schema": 61, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 120, "model": "diagnosticos.escolha", "fields": {"schema": 61, "schema_to_open": null, "title": "Mensal"}}, {"pk": 121, "model": "diagnosticos.escolha", "fields": {"schema": 61, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 122, "model": "diagnosticos.escolha", "fields": {"schema": 61, "schema_to_open": null, "title": "Outra"}}, {"pk": 123, "model": "diagnosticos.escolha", "fields": {"schema": 62, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 124, "model": "diagnosticos.escolha", "fields": {"schema": 62, "schema_to_open": null, "title": "Semanal"}}, {"pk": 125, "model": "diagnosticos.escolha", "fields": {"schema": 62, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 126, "model": "diagnosticos.escolha", "fields": {"schema": 62, "schema_to_open": null, "title": "Mensal"}}, {"pk": 128, "model": "diagnosticos.escolha", "fields": {"schema": 62, "schema_to_open": null, "title": "Outra"}}, {"pk": 129, "model": "diagnosticos.escolha", "fields": {"schema": 63, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 130, "model": "diagnosticos.escolha", "fields": {"schema": 63, "schema_to_open": null, "title": "Semanal"}}, {"pk": 131, "model": "diagnosticos.escolha", "fields": {"schema": 63, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 132, "model": "diagnosticos.escolha", "fields": {"schema": 63, "schema_to_open": null, "title": "Mensal"}}, {"pk": 133, "model": "diagnosticos.escolha", "fields": {"schema": 63, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 134, "model": "diagnosticos.escolha", "fields": {"schema": 63, "schema_to_open": null, "title": "Outra"}}, {"pk": 135, "model": "diagnosticos.escolha", "fields": {"schema": 64, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 136, "model": "diagnosticos.escolha", "fields": {"schema": 64, "schema_to_open": null, "title": "Semanal"}}, {"pk": 137, "model": "diagnosticos.escolha", "fields": {"schema": 64, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 138, "model": "diagnosticos.escolha", "fields": {"schema": 64, "schema_to_open": null, "title": "Mensal"}}, {"pk": 139, "model": "diagnosticos.escolha", "fields": {"schema": 64, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 140, "model": "diagnosticos.escolha", "fields": {"schema": 64, "schema_to_open": null, "title": "Outra"}}, {"pk": 141, "model": "diagnosticos.escolha", "fields": {"schema": 65, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 142, "model": "diagnosticos.escolha", "fields": {"schema": 65, "schema_to_open": null, "title": "Semanal"}}, {"pk": 143, "model": "diagnosticos.escolha", "fields": {"schema": 65, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 144, "model": "diagnosticos.escolha", "fields": {"schema": 65, "schema_to_open": null, "title": "Mensal"}}, {"pk": 146, "model": "diagnosticos.escolha", "fields": {"schema": 65, "schema_to_open": null, "title": "Outra"}}, {"pk": 147, "model": "diagnosticos.escolha", "fields": {"schema": 66, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 148, "model": "diagnosticos.escolha", "fields": {"schema": 66, "schema_to_open": null, "title": "Semanal"}}, {"pk": 149, "model": "diagnosticos.escolha", "fields": {"schema": 66, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 5, "model": "diagnosticos.escolha", "fields": {"schema": 2, "schema_to_open": 3, "title": "Cedida por \u00f3rg\u00e3o P\u00fablico"}}, {"pk": 173, "model": "diagnosticos.escolha", "fields": {"schema": 69, "schema_to_open": null, "title": "Mensal"}}, {"pk": 174, "model": "diagnosticos.escolha", "fields": {"schema": 69, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 175, "model": "diagnosticos.escolha", "fields": {"schema": 69, "schema_to_open": null, "title": "Outra"}}, {"pk": 176, "model": "diagnosticos.escolha", "fields": {"schema": 70, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 177, "model": "diagnosticos.escolha", "fields": {"schema": 70, "schema_to_open": null, "title": "Semanal"}}, {"pk": 178, "model": "diagnosticos.escolha", "fields": {"schema": 70, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 179, "model": "diagnosticos.escolha", "fields": {"schema": 70, "schema_to_open": null, "title": "Mensal"}}, {"pk": 181, "model": "diagnosticos.escolha", "fields": {"schema": 70, "schema_to_open": null, "title": "Outra"}}, {"pk": 182, "model": "diagnosticos.escolha", "fields": {"schema": 71, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 183, "model": "diagnosticos.escolha", "fields": {"schema": 71, "schema_to_open": null, "title": "Semanal"}}, {"pk": 184, "model": "diagnosticos.escolha", "fields": {"schema": 71, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 185, "model": "diagnosticos.escolha", "fields": {"schema": 71, "schema_to_open": null, "title": "Mensal"}}, {"pk": 186, "model": "diagnosticos.escolha", "fields": {"schema": 71, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 187, "model": "diagnosticos.escolha", "fields": {"schema": 71, "schema_to_open": null, "title": "Outra"}}, {"pk": 188, "model": "diagnosticos.escolha", "fields": {"schema": 72, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 189, "model": "diagnosticos.escolha", "fields": {"schema": 72, "schema_to_open": null, "title": "Semanal"}}, {"pk": 190, "model": "diagnosticos.escolha", "fields": {"schema": 72, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 191, "model": "diagnosticos.escolha", "fields": {"schema": 72, "schema_to_open": null, "title": "Mensal"}}, {"pk": 192, "model": "diagnosticos.escolha", "fields": {"schema": 72, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 193, "model": "diagnosticos.escolha", "fields": {"schema": 72, "schema_to_open": null, "title": "Outra"}}, {"pk": 194, "model": "diagnosticos.escolha", "fields": {"schema": 73, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 195, "model": "diagnosticos.escolha", "fields": {"schema": 73, "schema_to_open": null, "title": "Semanal"}}, {"pk": 196, "model": "diagnosticos.escolha", "fields": {"schema": 73, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 197, "model": "diagnosticos.escolha", "fields": {"schema": 73, "schema_to_open": null, "title": "Mensal"}}, {"pk": 199, "model": "diagnosticos.escolha", "fields": {"schema": 73, "schema_to_open": null, "title": "Outra"}}, {"pk": 200, "model": "diagnosticos.escolha", "fields": {"schema": 74, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 201, "model": "diagnosticos.escolha", "fields": {"schema": 74, "schema_to_open": null, "title": "Semanal"}}, {"pk": 203, "model": "diagnosticos.escolha", "fields": {"schema": 74, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 204, "model": "diagnosticos.escolha", "fields": {"schema": 74, "schema_to_open": null, "title": "Mensal"}}, {"pk": 205, "model": "diagnosticos.escolha", "fields": {"schema": 74, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 206, "model": "diagnosticos.escolha", "fields": {"schema": 74, "schema_to_open": null, "title": "Outra"}}, {"pk": 207, "model": "diagnosticos.escolha", "fields": {"schema": 75, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 208, "model": "diagnosticos.escolha", "fields": {"schema": 75, "schema_to_open": null, "title": "Semanal"}}, {"pk": 209, "model": "diagnosticos.escolha", "fields": {"schema": 75, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 210, "model": "diagnosticos.escolha", "fields": {"schema": 75, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 211, "model": "diagnosticos.escolha", "fields": {"schema": 75, "schema_to_open": null, "title": "Outra"}}, {"pk": 212, "model": "diagnosticos.escolha", "fields": {"schema": 76, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 213, "model": "diagnosticos.escolha", "fields": {"schema": 76, "schema_to_open": null, "title": "Semanal"}}, {"pk": 214, "model": "diagnosticos.escolha", "fields": {"schema": 76, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 215, "model": "diagnosticos.escolha", "fields": {"schema": 76, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 216, "model": "diagnosticos.escolha", "fields": {"schema": 76, "schema_to_open": null, "title": "Outra"}}, {"pk": 222, "model": "diagnosticos.escolha", "fields": {"schema": 77, "schema_to_open": null, "title": "Essencial"}}, {"pk": 223, "model": "diagnosticos.escolha", "fields": {"schema": 77, "schema_to_open": null, "title": "Importante"}}, {"pk": 224, "model": "diagnosticos.escolha", "fields": {"schema": 77, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 225, "model": "diagnosticos.escolha", "fields": {"schema": 77, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 226, "model": "diagnosticos.escolha", "fields": {"schema": 77, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 227, "model": "diagnosticos.escolha", "fields": {"schema": 78, "schema_to_open": null, "title": "Essencial"}}, {"pk": 228, "model": "diagnosticos.escolha", "fields": {"schema": 78, "schema_to_open": null, "title": "Importante"}}, {"pk": 230, "model": "diagnosticos.escolha", "fields": {"schema": 78, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 231, "model": "diagnosticos.escolha", "fields": {"schema": 78, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 232, "model": "diagnosticos.escolha", "fields": {"schema": 79, "schema_to_open": null, "title": "Essencial"}}, {"pk": 233, "model": "diagnosticos.escolha", "fields": {"schema": 79, "schema_to_open": null, "title": "Importante"}}, {"pk": 234, "model": "diagnosticos.escolha", "fields": {"schema": 79, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 235, "model": "diagnosticos.escolha", "fields": {"schema": 79, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 236, "model": "diagnosticos.escolha", "fields": {"schema": 79, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 237, "model": "diagnosticos.escolha", "fields": {"schema": 80, "schema_to_open": null, "title": "Essencial"}}, {"pk": 238, "model": "diagnosticos.escolha", "fields": {"schema": 80, "schema_to_open": null, "title": "Importante"}}, {"pk": 239, "model": "diagnosticos.escolha", "fields": {"schema": 80, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 240, "model": "diagnosticos.escolha", "fields": {"schema": 80, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 241, "model": "diagnosticos.escolha", "fields": {"schema": 80, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 242, "model": "diagnosticos.escolha", "fields": {"schema": 81, "schema_to_open": null, "title": "Essencial"}}, {"pk": 243, "model": "diagnosticos.escolha", "fields": {"schema": 81, "schema_to_open": null, "title": "Importante"}}, {"pk": 244, "model": "diagnosticos.escolha", "fields": {"schema": 81, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 246, "model": "diagnosticos.escolha", "fields": {"schema": 81, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 247, "model": "diagnosticos.escolha", "fields": {"schema": 81, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 248, "model": "diagnosticos.escolha", "fields": {"schema": 82, "schema_to_open": null, "title": "Essencial"}}, {"pk": 249, "model": "diagnosticos.escolha", "fields": {"schema": 82, "schema_to_open": null, "title": "Importante"}}, {"pk": 250, "model": "diagnosticos.escolha", "fields": {"schema": 82, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 251, "model": "diagnosticos.escolha", "fields": {"schema": 82, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 252, "model": "diagnosticos.escolha", "fields": {"schema": 82, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 253, "model": "diagnosticos.escolha", "fields": {"schema": 83, "schema_to_open": null, "title": "Essencial"}}, {"pk": 254, "model": "diagnosticos.escolha", "fields": {"schema": 83, "schema_to_open": null, "title": "Importante"}}, {"pk": 255, "model": "diagnosticos.escolha", "fields": {"schema": 83, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 256, "model": "diagnosticos.escolha", "fields": {"schema": 83, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 257, "model": "diagnosticos.escolha", "fields": {"schema": 83, "schema_to_open": null, "title": "Desnecess\u00e1rio"}}, {"pk": 258, "model": "diagnosticos.escolha", "fields": {"schema": 84, "schema_to_open": null, "title": "Sim, via r\u00e1dio"}}, {"pk": 259, "model": "diagnosticos.escolha", "fields": {"schema": 84, "schema_to_open": null, "title": "Sim, via TV aberta"}}, {"pk": 260, "model": "diagnosticos.escolha", "fields": {"schema": 84, "schema_to_open": null, "title": "Sim, via TV a cabo"}}, {"pk": 262, "model": "diagnosticos.escolha", "fields": {"schema": 84, "schema_to_open": 85, "title": "Sim, via outros ve\u00edculos"}}, {"pk": 263, "model": "diagnosticos.escolha", "fields": {"schema": 84, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 264, "model": "diagnosticos.escolha", "fields": {"schema": 86, "schema_to_open": null, "title": "Ouvidoria"}}, {"pk": 265, "model": "diagnosticos.escolha", "fields": {"schema": 86, "schema_to_open": null, "title": "E-mail \u201cFale Conosco\u201d"}}, {"pk": 266, "model": "diagnosticos.escolha", "fields": {"schema": 86, "schema_to_open": null, "title": "Central de Atendimento"}}, {"pk": 267, "model": "diagnosticos.escolha", "fields": {"schema": 86, "schema_to_open": null, "title": "Caixas de sugest\u00f5es"}}, {"pk": 268, "model": "diagnosticos.escolha", "fields": {"schema": 86, "schema_to_open": null, "title": "Outros"}}, {"pk": 269, "model": "diagnosticos.escolha", "fields": {"schema": 86, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 270, "model": "diagnosticos.escolha", "fields": {"schema": 87, "schema_to_open": null, "title": "Sim"}}, {"pk": 271, "model": "diagnosticos.escolha", "fields": {"schema": 87, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 272, "model": "diagnosticos.escolha", "fields": {"schema": 88, "schema_to_open": 89, "title": "Sim"}}, {"pk": 273, "model": "diagnosticos.escolha", "fields": {"schema": 88, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 274, "model": "diagnosticos.escolha", "fields": {"schema": 90, "schema_to_open": null, "title": "Anual"}}, {"pk": 275, "model": "diagnosticos.escolha", "fields": {"schema": 90, "schema_to_open": null, "title": "Bianual"}}, {"pk": 276, "model": "diagnosticos.escolha", "fields": {"schema": 91, "schema_to_open": 92, "title": "Di\u00e1ria"}}, {"pk": 277, "model": "diagnosticos.escolha", "fields": {"schema": 91, "schema_to_open": 92, "title": "Semanal"}}, {"pk": 278, "model": "diagnosticos.escolha", "fields": {"schema": 91, "schema_to_open": 92, "title": "Quinzenal"}}, {"pk": 279, "model": "diagnosticos.escolha", "fields": {"schema": 91, "schema_to_open": 92, "title": "Mensal"}}, {"pk": 280, "model": "diagnosticos.escolha", "fields": {"schema": 91, "schema_to_open": 92, "title": "Outra"}}, {"pk": 282, "model": "diagnosticos.escolha", "fields": {"schema": 93, "schema_to_open": null, "title": "SIAFI"}}, {"pk": 283, "model": "diagnosticos.escolha", "fields": {"schema": 93, "schema_to_open": 94, "title": "Outros"}}, {"pk": 284, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Previs\u00e3o Or\u00e7ament\u00e1ria"}}, {"pk": 285, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Planejamento Estrat\u00e9gico"}}, {"pk": 286, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Plano de Carreira"}}, {"pk": 287, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Organograma"}}, {"pk": 288, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Regulamento Administrativo"}}, {"pk": 289, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Norma de Gest\u00e3o Patrimonial"}}, {"pk": 290, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Norma de Gest\u00e3o de Documentos"}}, {"pk": 291, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Controle de Protocolo"}}, {"pk": 292, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Manuais de Procedimentos"}}, {"pk": 293, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "C\u00f3digo de \u00c9tica"}}, {"pk": 294, "model": "diagnosticos.escolha", "fields": {"schema": 95, "schema_to_open": null, "title": "Bras\u00e3o ou logotipo oficial"}}, {"pk": 296, "model": "diagnosticos.escolha", "fields": {"schema": 103, "schema_to_open": null, "title": "N\u00edvel m\u00e9dio (antigo 2\u00ba grau)"}}, {"pk": 297, "model": "diagnosticos.escolha", "fields": {"schema": 103, "schema_to_open": null, "title": "N\u00edvel fundamental (antigo 1\u00ba grau)"}}, {"pk": 298, "model": "diagnosticos.escolha", "fields": {"schema": 103, "schema_to_open": null, "title": "Outro"}}, {"pk": 299, "model": "diagnosticos.escolha", "fields": {"schema": 105, "schema_to_open": null, "title": "N\u00edvel superior ou de p\u00f3s-gradua\u00e7\u00e3o"}}, {"pk": 300, "model": "diagnosticos.escolha", "fields": {"schema": 105, "schema_to_open": null, "title": "N\u00edvel m\u00e9dio (antigo 2\u00ba grau)"}}, {"pk": 301, "model": "diagnosticos.escolha", "fields": {"schema": 105, "schema_to_open": null, "title": "N\u00edvel fundamental (antigo 1\u00ba grau)"}}, {"pk": 302, "model": "diagnosticos.escolha", "fields": {"schema": 105, "schema_to_open": null, "title": "Outro"}}, {"pk": 303, "model": "diagnosticos.escolha", "fields": {"schema": 107, "schema_to_open": 108, "title": "Os Parlamentares"}}, {"pk": 304, "model": "diagnosticos.escolha", "fields": {"schema": 107, "schema_to_open": null, "title": "O Presidente da C\u00e2mara"}}, {"pk": 305, "model": "diagnosticos.escolha", "fields": {"schema": 107, "schema_to_open": null, "title": "A Mesa Diretora"}}, {"pk": 306, "model": "diagnosticos.escolha", "fields": {"schema": 109, "schema_to_open": null, "title": "N\u00edvel superior ou de p\u00f3s-gradua\u00e7\u00e3o"}}, {"pk": 307, "model": "diagnosticos.escolha", "fields": {"schema": 109, "schema_to_open": null, "title": "N\u00edvel m\u00e9dio (antigo 2\u00ba grau)"}}, {"pk": 308, "model": "diagnosticos.escolha", "fields": {"schema": 109, "schema_to_open": null, "title": "N\u00edvel fundamental (antigo 1\u00ba grau)"}}, {"pk": 309, "model": "diagnosticos.escolha", "fields": {"schema": 109, "schema_to_open": null, "title": "Outro"}}, {"pk": 310, "model": "diagnosticos.escolha", "fields": {"schema": 113, "schema_to_open": null, "title": "Servi\u00e7os gerais"}}, {"pk": 311, "model": "diagnosticos.escolha", "fields": {"schema": 113, "schema_to_open": null, "title": "Apoio aos gabinetes (copeiros, cont\u00ednuos)"}}, {"pk": 312, "model": "diagnosticos.escolha", "fields": {"schema": 113, "schema_to_open": null, "title": "Apoio aos parlamentares (secret\u00e1rias e afins)"}}, {"pk": 313, "model": "diagnosticos.escolha", "fields": {"schema": 113, "schema_to_open": null, "title": "Setor de vigil\u00e2ncia"}}, {"pk": 314, "model": "diagnosticos.escolha", "fields": {"schema": 113, "schema_to_open": null, "title": "Setor de inform\u00e1tica"}}, {"pk": 315, "model": "diagnosticos.escolha", "fields": {"schema": 113, "schema_to_open": null, "title": "Apoio administrativo em geral"}}, {"pk": 316, "model": "diagnosticos.escolha", "fields": {"schema": 114, "schema_to_open": null, "title": "Sim"}}, {"pk": 317, "model": "diagnosticos.escolha", "fields": {"schema": 114, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 318, "model": "diagnosticos.escolha", "fields": {"schema": 115, "schema_to_open": null, "title": "Sim"}}, {"pk": 319, "model": "diagnosticos.escolha", "fields": {"schema": 115, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 321, "model": "diagnosticos.escolha", "fields": {"schema": 116, "schema_to_open": null, "title": "Independentes das a\u00e7\u00f5es da Escola do Legislativo"}}, {"pk": 322, "model": "diagnosticos.escolha", "fields": {"schema": 117, "schema_to_open": null, "title": "Sim"}}, {"pk": 323, "model": "diagnosticos.escolha", "fields": {"schema": 117, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 324, "model": "diagnosticos.escolha", "fields": {"schema": 118, "schema_to_open": null, "title": "Sim, em local apropriado na pr\u00f3pria C\u00e2mara"}}, {"pk": 325, "model": "diagnosticos.escolha", "fields": {"schema": 118, "schema_to_open": null, "title": "Sim, em local improvisado na pr\u00f3pria C\u00e2mara"}}, {"pk": 172, "model": "diagnosticos.escolha", "fields": {"schema": 69, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 151, "model": "diagnosticos.escolha", "fields": {"schema": 66, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 152, "model": "diagnosticos.escolha", "fields": {"schema": 66, "schema_to_open": null, "title": "Outra"}}, {"pk": 153, "model": "diagnosticos.escolha", "fields": {"schema": 67, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 154, "model": "diagnosticos.escolha", "fields": {"schema": 67, "schema_to_open": null, "title": "Semanal"}}, {"pk": 155, "model": "diagnosticos.escolha", "fields": {"schema": 67, "schema_to_open": null, "title": "Quinzenal"}}, {"pk": 156, "model": "diagnosticos.escolha", "fields": {"schema": 67, "schema_to_open": null, "title": "Mensal"}}, {"pk": 157, "model": "diagnosticos.escolha", "fields": {"schema": 67, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 158, "model": "diagnosticos.escolha", "fields": {"schema": 67, "schema_to_open": null, "title": "Outra"}}, {"pk": 159, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Informativo"}}, {"pk": 160, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Portal de Internet"}}, {"pk": 161, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Jornal"}}, {"pk": 162, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Revista"}}, {"pk": 163, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "R\u00e1dio"}}, {"pk": 164, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "R\u00e1dio web"}}, {"pk": 165, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "TV"}}, {"pk": 166, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "TV web"}}, {"pk": 167, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Outras m\u00eddias impressas (faixas, outdoors, cartazes, placas)"}}, {"pk": 168, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Outros servi\u00e7os (carros de som, )"}}, {"pk": 169, "model": "diagnosticos.escolha", "fields": {"schema": 68, "schema_to_open": null, "title": "Outros"}}, {"pk": 170, "model": "diagnosticos.escolha", "fields": {"schema": 69, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 180, "model": "diagnosticos.escolha", "fields": {"schema": 70, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 198, "model": "diagnosticos.escolha", "fields": {"schema": 73, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 4, "model": "diagnosticos.escolha", "fields": {"schema": 2, "schema_to_open": null, "title": "Alugada"}}, {"pk": 171, "model": "diagnosticos.escolha", "fields": {"schema": 69, "schema_to_open": null, "title": "Semanal"}}, {"pk": 22, "model": "diagnosticos.escolha", "fields": {"schema": 20, "schema_to_open": 21, "title": "Sim, utilizando o SAPL do Interlegis"}}, {"pk": 58, "model": "diagnosticos.escolha", "fields": {"schema": 35, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 60, "model": "diagnosticos.escolha", "fields": {"schema": 38, "schema_to_open": null, "title": "Realiza consulta externa ou Recorre a \u00f3rg\u00e3o externo"}}, {"pk": 111, "model": "diagnosticos.escolha", "fields": {"schema": 60, "schema_to_open": null, "title": "Di\u00e1ria"}}, {"pk": 127, "model": "diagnosticos.escolha", "fields": {"schema": 62, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 145, "model": "diagnosticos.escolha", "fields": {"schema": 65, "schema_to_open": null, "title": "Por sess\u00e3o plen\u00e1ria"}}, {"pk": 150, "model": "diagnosticos.escolha", "fields": {"schema": 66, "schema_to_open": null, "title": "Mensal"}}, {"pk": 229, "model": "diagnosticos.escolha", "fields": {"schema": 78, "schema_to_open": null, "title": "Indiferente"}}, {"pk": 245, "model": "diagnosticos.escolha", "fields": {"schema": 81, "schema_to_open": null, "title": "N\u00e3o \u00e9 importante"}}, {"pk": 261, "model": "diagnosticos.escolha", "fields": {"schema": 84, "schema_to_open": null, "title": "Sim, via internet"}}, {"pk": 281, "model": "diagnosticos.escolha", "fields": {"schema": 93, "schema_to_open": null, "title": "Relat\u00f3rios do Tribunal de Contas"}}, {"pk": 295, "model": "diagnosticos.escolha", "fields": {"schema": 103, "schema_to_open": null, "title": "N\u00edvel superior ou de p\u00f3s-gradua\u00e7\u00e3o"}}, {"pk": 320, "model": "diagnosticos.escolha", "fields": {"schema": 116, "schema_to_open": null, "title": "Em conjunto com as a\u00e7\u00f5es da Escola do Legislativo"}}, {"pk": 326, "model": "diagnosticos.escolha", "fields": {"schema": 118, "schema_to_open": null, "title": "Sim, em local externo"}}, {"pk": 327, "model": "diagnosticos.escolha", "fields": {"schema": 118, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 328, "model": "diagnosticos.escolha", "fields": {"schema": 119, "schema_to_open": null, "title": "Sim, em local apropriado na pr\u00f3pria C\u00e2mara"}}, {"pk": 329, "model": "diagnosticos.escolha", "fields": {"schema": 119, "schema_to_open": null, "title": "Sim, em local improvisado na pr\u00f3pria C\u00e2mara"}}, {"pk": 330, "model": "diagnosticos.escolha", "fields": {"schema": 119, "schema_to_open": null, "title": "Sim, cada servidor utiliza os mesmos computadores que usam para trabalhar"}}, {"pk": 331, "model": "diagnosticos.escolha", "fields": {"schema": 119, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 332, "model": "diagnosticos.escolha", "fields": {"schema": 120, "schema_to_open": null, "title": "Sim, via ILB/Senado"}}, {"pk": 333, "model": "diagnosticos.escolha", "fields": {"schema": 120, "schema_to_open": null, "title": "Sim, via Interlegis/Senado"}}, {"pk": 334, "model": "diagnosticos.escolha", "fields": {"schema": 120, "schema_to_open": null, "title": "Sim, por meio de outras institui\u00e7\u00f5es"}}, {"pk": 335, "model": "diagnosticos.escolha", "fields": {"schema": 120, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 336, "model": "diagnosticos.escolha", "fields": {"schema": 121, "schema_to_open": null, "title": "Sim, via ILB/Senado"}}, {"pk": 337, "model": "diagnosticos.escolha", "fields": {"schema": 121, "schema_to_open": null, "title": "Sim, via Interlegis/Senado"}}, {"pk": 338, "model": "diagnosticos.escolha", "fields": {"schema": 121, "schema_to_open": null, "title": "Sim, por meio de outras institui\u00e7\u00f5es"}}, {"pk": 339, "model": "diagnosticos.escolha", "fields": {"schema": 121, "schema_to_open": null, "title": "N\u00e3o"}}, {"pk": 3, "model": "diagnosticos.escolha", "fields": {"schema": 2, "schema_to_open": null, "title": "Pr\u00f3pria"}}] diff --git a/sigi/apps/diagnosticos/forms.py b/sigi/apps/diagnosticos/forms.py index 3c5ace0..8eda91a 100644 --- a/sigi/apps/diagnosticos/forms.py +++ b/sigi/apps/diagnosticos/forms.py @@ -1,5 +1,148 @@ -from models import Diagnostico +# -*- coding: utf8 -*- + +from copy import deepcopy +from django import forms +from django.forms.forms import BoundField +from django.forms import (BooleanField, CharField, DateField, + FloatField, ModelChoiceField, Textarea, + ModelMultipleChoiceField) +from django.contrib.contenttypes.generic import generic_inlineformset_factory +from sigi.apps.casas.models import CasaLegislativa, Funcionario +from sigi.apps.contatos.models import Telefone +from sigi.apps.diagnosticos.models import Diagnostico +from sigi.apps.diagnosticos.widgets import EavCheckboxSelectMultiple, EavRadioSelect from eav.forms import BaseDynamicEntityForm +from eav.fields import RangeField class DiagnosticoForm(BaseDynamicEntityForm): + """Classe responsável por contruir o formulário, + vinculando ao modelo Diagnostico + """ model = Diagnostico + + +class DiagnosticoMobileForm(BaseDynamicEntityForm): + """Classe responsável por construir o formulário + para ser usado no ambiente mobile, a partir do + do modelo Diagnostico, como também organizar sua + estrutura via categorias. + """ + + FIELD_CLASSES = { + 'text': CharField, + 'float': FloatField, + 'date': DateField, + 'bool': BooleanField, + 'one': ModelChoiceField, + 'many': ModelMultipleChoiceField, + 'range': RangeField, + } + + FIELD_EXTRA = { + 'one': {'widget': EavRadioSelect}, + 'many': {'widget': EavCheckboxSelectMultiple}, + } + + FIELD_WIDGET = { + 'consideracoes_gerais' : {'widget': Textarea}, + 'descreva_5_cursos_prioritarios_para_treinamento_de_parlamentares_da_camara_municipal' : {'widget': Textarea}, + 'descreva_5_cursos_prioritarios_para_treinamento_de_servidores_da_camara_municipal' : {'widget': Textarea}, + 'sugestoes_para_a_area_de_capacitacao' : {'widget': Textarea}, + 'sugestoes_para_a_area_de_comunicacao' : {'widget': Textarea}, + 'sugestoes_para_a_area_de_informacao' : {'widget': Textarea}, + 'sugestoes_para_a_area_de_ti' : {'widget': Textarea}, + } + class Meta: + model = Diagnostico + + def __init__(self, data=None, category=None, *args, **kwargs): + super(BaseDynamicEntityForm, self).__init__(data, *args, **kwargs) + self._build_dynamics_fields(category) + + def __iter__(self): + # ordena os campos do formulario usando o atributo label + fields_by_label = [(field.label, name, field) for name, field in self.fields.items()] + for label, name, field in sorted(fields_by_label): + yield BoundField(self, field, name) + + def _build_dynamics_fields(self, category): + """Método da classe ``BaseDynamicEntityForm`` sobrescrita, + para que as perguntas sejam agrupadas dentro das suas + categorias. + * category = ID da Categoria + """ + # Caso seja as duas primeiras categorias, utilize + # os campos do modelo + if int(category) in (0, 1, ): + self.fields = deepcopy(self.base_fields) + else: + self.fields = dict() + + # Se determinada pergunta é da categoria pesquisada, + # então, gere o campo no formulário. + for schema in self.instance.get_schemata(): + + if not schema.categoria_id == int(category): + continue + + defaults = { + 'label': schema.title, + 'required': schema.required, + 'help_text': schema.help_text, + } + + datatype = schema.datatype + if datatype == schema.TYPE_MANY: + choices = getattr(self.instance, schema.name) + defaults.update({'queryset': schema.get_choices(), + 'initial': [x.pk for x in choices]}) + elif datatype == schema.TYPE_ONE: + choice = getattr(self.instance, schema.name) + defaults.update({'queryset': schema.get_choices(), + 'initial': choice.pk if choice else None, + # if schema is required remove --------- from ui + 'empty_label': None if schema.required else u"---------"}) + + extra = self.FIELD_EXTRA.get(datatype, {}) + extra.update(self.FIELD_WIDGET.get(schema.name, {})) + if hasattr(extra, '__call__'): + extra = extra(schema) + defaults.update(extra) + + MappedField = self.FIELD_CLASSES[datatype] + self.fields[schema.name] = MappedField(**defaults) + + # fill initial data (if attribute was already defined) + value = getattr(self.instance, schema.name) + if value and not datatype in (schema.TYPE_ONE, schema.TYPE_MANY): # choices are already done above + self.initial[schema.name] = value + + +class CasaLegislativaMobileForm(forms.ModelForm): + class Meta: + model = CasaLegislativa + fields = ('cnpj', 'logradouro', 'bairro', 'cep', 'email', 'pagina_web') + +class TelefoneMobileForm(forms.ModelForm): + pass + class Meta: + model = Telefone + fields = ('numero', 'tipo') + +class FuncionariosMobileForm(forms.ModelForm): + TelefoneFormSet = generic_inlineformset_factory(Telefone, TelefoneMobileForm, extra=1, can_delete=False) + + def __init__(self, data=None, prefix=None, instance=None, *args, **kwargs): + super(FuncionariosMobileForm, self).__init__(data, prefix=prefix, instance=instance, *args, **kwargs) + self.telefones = self.TelefoneFormSet(data, prefix=prefix, instance=instance) + + def is_valid(self): + return self.telefones.is_valid() and super(FuncionariosMobileForm, self).is_valid() + + def save(self, commit=True): + self.telefones.save(commit) + return super(FuncionariosMobileForm, self).save(commit) + + class Meta: + model = Funcionario + fields = ('nome', 'email', 'cargo', 'funcao', 'tempo_de_servico') diff --git a/sigi/apps/diagnosticos/models.py b/sigi/apps/diagnosticos/models.py index 3a184c8..a9eedad 100644 --- a/sigi/apps/diagnosticos/models.py +++ b/sigi/apps/diagnosticos/models.py @@ -1,59 +1,141 @@ # -*- coding: utf-8 -*- from datetime import datetime from django.db import models + +from sigi.apps.casas.models import CasaLegislativa from sigi.apps.utils import SearchField +from sigi.apps.utils.email import enviar_email from eav.models import BaseChoice, BaseEntity, BaseSchema, BaseAttribute + class Diagnostico(BaseEntity): """ Modelo para representar unm diagnostico realizado em uma Casa Legislativa """ casa_legislativa = models.ForeignKey( 'casas.CasaLegislativa', - verbose_name='Casa Legislativa' - ) + verbose_name='Casa Legislativa') + # campo de busca em caixa baixa e sem acento search_text = SearchField(field_names=['casa_legislativa']) casa_legislativa.convenio_uf_filter = True casa_legislativa.convenio_cl_tipo_filter = True - data_visita = models.DateField( - 'data da visita', + data_visita_inicio = models.DateField( + u'data inicial da visita', null=True, blank=True, ) - data_questionario = models.DateField( - 'data do questionario', + data_visita_fim = models.DateField( + u'data final da visita', null=True, blank=True, - help_text='Convênio firmado.' ) - data_relatorio_questionario = models.DateField( - 'data do relatório do questionario', - null=True, - blank=True - ) - data_termo_aceite = models.DateField( - 'Equipadas', + publicado = models.BooleanField(default=False) + data_publicacao = models.DateField( + u'data de publicação do diagnóstico', null=True, blank=True, - help_text='Equipamentos recebidos.' ) + + responsavel = models.ForeignKey('servidores.Servidor', + verbose_name=u'responsável') + class Meta: verbose_name, verbose_name_plural = u'diagnóstico', u'diagnósticos' + @property + def membros(self): + """ Retorna a lista de membros do diagnostico, + isto é responsavel + equipe + """ + membros = set([self.responsavel]) + for equipe in self.equipe_set.all(): + membros.add(equipe.membro) + return list(membros) + + @property + def contatos_respondidos(self): + """Retorna uma lista de contatos que foram + respondidos + """ + return list(self.casa_legislativa.funcionario_set.all()) + + @property + def categorias_respondidas(self): + """ Retorna uma listas das categorias dinamicas que tem + ao menos uma resposta + """ + # unifica as categorias das perguntas dessas respostas + categoria_com_respostas = set([r.schema.categoria for r in self._get_respostas()]) + + return list(categoria_com_respostas) + + def _get_respostas(self): + # obtem todas as respostas dinamicas desse diagnostico + respostas = Resposta.objects.filter(entity_id=self.id).all() + + # remove as respostas nulas ou em branco + return [r for r in respostas if r._get_value()] + + def email_diagnostico_publicado(self, from_email, host): + """Enviando email quando o diagnóstico for publicado. Os + argumentos acima são: + * from_email - Email de remetente + * host - O Host do sistema, para ser usado na + construção do endereço do diagnóstico + """ + enviar_email(from_email, u"Diagnóstico publicado", + 'diagnosticos/email_diagnostico_publicado.txt', + { + 'responsavel': self.responsavel.nome_completo, + 'casa_legislativa': self.casa_legislativa, + 'data_diagnostico': self.data_questionario, + 'host': host, + 'url_diagnostico': self.get_absolute_url(), + 'status': u"Publicado", + }) + + def email_diagnostico_alterado(self, from_email, host): + """Enviando email quando o status do diagnóstico + for alterado. Os argumentos acima são: + * from_email - Email do destinatário + * host - O Host do sistema, para ser usado na + construção do endereço do diagnóstico + """ + enviar_email(from_email, u"Diagnóstico alterado", + 'diagnosticos/email_diagnostico_alterado.txt', + { + 'servidor': self.responsavel.nome_completo, + 'casa_legislativa': self.casa_legislativa, + 'data_diagnostico': self.data_questionario, + 'host': host, + 'url_diagnostico': self.get_absolute_url, + 'status': "Alterado", + }) + @classmethod def get_schemata_for_model(self): return Pergunta.objects.all() def __unicode__(self): - return str(self.casa_legislativa) + return str(self.casa_legislativa).decode('utf8') + + def get_absolute_url(self): + return "/sigi/diagnosticos/diagnostico/%i/" % (self.id, ) + class Categoria(models.Model): """ Modelo para representar a categoria de uma pergunta e sua ordem na hora de exibir no formulário """ - nome= models.CharField(max_length=50) - ordem = models.PositiveSmallIntegerField(blank=True, null=True) + nome = models.CharField(max_length=255) + + class Meta: + ordering = ('nome',) + + def __unicode__(self): + return self.nome + class Pergunta(BaseSchema): """ Modelo que representa uma pergunta no questionário @@ -61,37 +143,51 @@ class Pergunta(BaseSchema): Uma pergunta tem o nome e o tipo da resposta """ - categoria = models.ForeignKey(Categoria,blank=True, null=True) + categoria = models.ForeignKey(Categoria, related_name='perguntas') + class Meta: + ordering = ('title',) verbose_name, verbose_name_plural = 'pergunta', 'perguntas' + class Escolha(BaseChoice): """ Perguntas de multiplas escolhas tem as opções cadastradas neste modelo """ - schema = models.ForeignKey(Pergunta, related_name='choices', verbose_name='pergunta') + schema = models.ForeignKey(Pergunta, + related_name='choices', verbose_name='pergunta') + schema_to_open = models.ForeignKey(Pergunta, related_name='', + verbose_name='pergunta para abrir', blank=True, null=True) + class Meta: verbose_name, verbose_name_plural = 'escolha', 'escolhas' + class Resposta(BaseAttribute): """ Modelo para guardar as respostas das perguntas de um diagnosico """ - schema = models.ForeignKey(Pergunta, related_name='attrs', verbose_name='pergunta') - choice = models.ForeignKey(Escolha, verbose_name='escolha', blank=True, null=True) + schema = models.ForeignKey(Pergunta, related_name='attrs', + verbose_name='pergunta') + choice = models.ForeignKey(Escolha, verbose_name='escolha', + blank=True, null=True) + class Meta: verbose_name, verbose_name_plural = 'resposta', 'respostas' + class Equipe(models.Model): """ Modelo que representa a equipe de um diagnóstico """ diagnostico = models.ForeignKey(Diagnostico) membro = models.ForeignKey('servidores.Servidor') - # verdadeiro se o servidor é repsonsável por chefiar a equipe - is_chefe = models.BooleanField() + + class Meta: + verbose_name, verbose_name_plural = 'equipe', 'equipe' def __unicode__(self): - return str(self.id) + return str(self.membro) + class Anexo(models.Model): """ Modelo para representar os documentos levantados @@ -100,14 +196,11 @@ class Anexo(models.Model): diagnostico = models.ForeignKey(Diagnostico, verbose_name=u'diagnóstico') arquivo = models.FileField(upload_to='apps/diagnostico/anexo/arquivo',) descricao = models.CharField('descrição', max_length='70') - data_pub = models.DateTimeField( - 'data da publicação do anexo', - default=datetime.now - ) + data_pub = models.DateTimeField('data da publicação do anexo', + default=datetime.now) class Meta: ordering = ('-data_pub',) def __unicode__(self): return unicode(self.arquivo.name) - diff --git a/sigi/apps/diagnosticos/tests.py b/sigi/apps/diagnosticos/tests.py new file mode 100644 index 0000000..acf958e --- /dev/null +++ b/sigi/apps/diagnosticos/tests.py @@ -0,0 +1,15 @@ +# -*- coding: utf8 -*- + +from django.test import TestCase + + +class DiagnosticosViewsTest(TestCase): + """Testes feitos para verificar o funcionamento + do view de diagnósticos. + """ + + def test_diagnostico_list_success(self): + + response = self.client.get('/sigi/mobile/diagnosticos') + self.assertEquals(200, response.status_code) + self.assertTemplateUsed(response, 'diagnosticos/diagnosticos_list.html') diff --git a/sigi/apps/diagnosticos/urls.py b/sigi/apps/diagnosticos/urls.py new file mode 100644 index 0000000..b58f95c --- /dev/null +++ b/sigi/apps/diagnosticos/urls.py @@ -0,0 +1,35 @@ +# -*- coding: utf8 -*- +from django.conf.urls.defaults import patterns, url + +LOGIN_REDIRECT_URL = '/sigi/mobile/diagnosticos/login' + +urlpatterns = patterns('', + # Lista de Diagnósticos + url(r'^$', 'sigi.apps.diagnosticos.views.lista', name='lista_diagnosticos'), + + # Login do Diagnóstico + url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': + 'diagnosticos/diagnosticos_login.html'}, name='login'), + + # Logout do Diagnóstico + url(r'^logout/$', 'django.contrib.auth.views.logout', + {'next_page': LOGIN_REDIRECT_URL}, name='logout'), + + # Lista de Categorias + url(r'^(?P\d+)/categorias/$', 'sigi.apps.diagnosticos.views.categorias', name='lista_categorias'), + + # Detalhes da Categoria da Casa Legislativa + url(r'^(?P\d+)/categorias/1/$', + 'sigi.apps.diagnosticos.views.categoria_casa_legislativa', + name='detalhes_categoria_casa_legislativa'), + + # Detalhes da Categoria de Contatos + url(r'^(?P\d+)/categorias/2/$', + 'sigi.apps.diagnosticos.views.categoria_contatos', + name='detalhes_categoria_contatos'), + + # Detalhes de Categorias Dinamicas + url(r'^(?P\d+)/categorias/(?P\d+)/$', + 'sigi.apps.diagnosticos.views.categoria_detalhes', + name='detalhes_categoria'), +) diff --git a/sigi/apps/diagnosticos/views.py b/sigi/apps/diagnosticos/views.py new file mode 100644 index 0000000..164d491 --- /dev/null +++ b/sigi/apps/diagnosticos/views.py @@ -0,0 +1,187 @@ +# -*- coding: utf8 -*- + +from django.http import HttpResponse +from django.utils import simplejson +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.views.decorators.cache import never_cache + +from sigi.apps.diagnosticos.urls import LOGIN_REDIRECT_URL +from sigi.apps.utils.decorators import login_required +from sigi.apps.diagnosticos.decorators import validate_diagnostico +from sigi.apps.diagnosticos.models import Diagnostico, Categoria +from sigi.apps.casas.models import Funcionario +from sigi.apps.diagnosticos.forms import (DiagnosticoMobileForm, + CasaLegislativaMobileForm, FuncionariosMobileForm) + + +@never_cache +@login_required(login_url=LOGIN_REDIRECT_URL) +def lista(request): + """Consulta os diagnosticos do servidor logado, + que contenham o status de não publicado. + """ + servidor = request.user.servidor + diagnosticos = servidor.diagnosticos + context = RequestContext(request, {'diagnosticos': diagnosticos}) + return render_to_response('diagnosticos/diagnosticos_list.html', context) + + +@never_cache +@login_required(login_url=LOGIN_REDIRECT_URL) +@validate_diagnostico +def categorias(request, id_diagnostico): + """Consulta as categorias do diagnostico selecionado + a partir da sua identificação + """ + categorias = Categoria.objects.all() + diagnostico = Diagnostico.objects.get(pk=id_diagnostico) + + # Estilizando a lista de categorias para que ajude a identificar + # qual categoria foi a ultima a ser usada, como também as outras + # que ainda não foram acessadas + ultima_categoria = request.session.get('ultima_categoria', 0) + + context = RequestContext(request, {'categorias': categorias, + 'diagnostico': diagnostico, 'ultima_categoria': ultima_categoria}) + return render_to_response('diagnosticos/diagnosticos_categorias_list.html', + context) + + +@never_cache +@login_required(login_url=LOGIN_REDIRECT_URL) +@validate_diagnostico +def categoria_detalhes(request, id_diagnostico, id_categoria): + """Captura as perguntas da categoria + selecionada. Durante o preenchimento das perguntas, o camada + template do projeto, vai requisitar a inserção dos campos via + AJAX a cada mudança de pergunta + + Caso alguma inserção não passe na validação do formulário em + questão, será enviado as mensagens de erro no formato JSON, + para que a camada de template do projeto trate-as de forma adequada. + """ + + # Grava na sessão a categoria atual, para destacar que + # era foi a última visitada. + request.session['ultima_categoria'] = int(id_categoria) + + try: + categoria = Categoria.objects.get(pk=id_categoria) + except Categoria.DoesNotExist: + context = RequestContext(request) + return render_to_response('mobile/404.html', context) + + diagnostico = Diagnostico.objects.filter(publicado=False).get(pk=id_diagnostico) + + if request.method == "POST": + form = DiagnosticoMobileForm(request.POST, + instance=diagnostico, category=id_categoria) + if form.is_valid(): + form.save() + resposta = { + 'mensagem': 'sucesso' + } + else: + # Montando a estrutura das mensagens de erro no formato JSON + resposta = { + 'mensagem': 'erro', + 'erros': form.errors + } + json = simplejson.dumps(resposta) + return HttpResponse(json, mimetype="application/json") + else: + form = DiagnosticoMobileForm(instance=diagnostico, + category=id_categoria) + + context = RequestContext(request, {'form': form, 'categoria': categoria, + 'diagnostico': diagnostico}) + return render_to_response('diagnosticos/diagnosticos_categorias_form.html', + context) + + +@never_cache +@login_required(login_url=LOGIN_REDIRECT_URL) +@validate_diagnostico +def categoria_casa_legislativa(request, id_diagnostico): + + # Grava na sessão a categoria atual, para destacar que + # era foi a última visitada. + request.session['ultima_categoria'] = 1 + + diagnostico = Diagnostico.objects.get(pk=id_diagnostico) + casa_legislativa = diagnostico.casa_legislativa + + if request.method == "POST": + form = CasaLegislativaMobileForm(request.POST, + instance=casa_legislativa) + if form.is_valid(): + form.save() + resposta = { + 'mensagem': 'sucesso' + } + else: + # Montando a estrutura das mensagens de erro no formato JSON + resposta = { + 'mensagem': 'erro', + 'erros': form.errors + } + json = simplejson.dumps(resposta) + return HttpResponse(json, mimetype="application/json") + else: + form = CasaLegislativaMobileForm(instance=casa_legislativa) + + context = RequestContext(request, {'form': form, + 'diagnostico': diagnostico, 'casa_legislativa': casa_legislativa}) + return render_to_response( + 'diagnosticos/diagnosticos_categoria_casa_legislativa_form.html', + context) + + +@never_cache +@login_required(login_url=LOGIN_REDIRECT_URL) +@validate_diagnostico +def categoria_contatos(request, id_diagnostico): + + # Grava na sessão a categoria atual, para destacar que + # era foi a última visitada. + request.session['ultima_categoria'] = 2 + + diagnostico = Diagnostico.objects.get(pk=id_diagnostico) + casa_legislativa = diagnostico.casa_legislativa + + funcionarios = [casa_legislativa.funcionario_set.get_or_create(setor=n) + for n, l in Funcionario.SETOR_CHOICES] + + if request.method == "POST": + forms = [FuncionariosMobileForm( + request.POST, prefix=f.setor, instance=f) for f, c in funcionarios] + + resposta = { + 'mensagem': 'sucesso', + 'erros' : {} + } + + # valida e salva um formulario por vez + for form in forms: + if form.is_valid(): + form.save() + else: + # Montando a estrutura das mensagens de erro no formato JSON + resposta['mensagem'] = 'erro' + resposta['erros'].update(form.errors) + for form_telefones in form.telefones.forms: + for key, value in form_telefones.errors.iteritems(): + key = form_telefones.prefix + "-" + key + resposta['erros'][key] = value + + json = simplejson.dumps(resposta) + return HttpResponse(json, mimetype="application/json") + else: + forms = [FuncionariosMobileForm(prefix=f.setor, instance=f) + for f, c in funcionarios] + + context = RequestContext(request, {'forms': forms, + 'diagnostico': diagnostico, 'casa_legislativa': casa_legislativa}) + return render_to_response('diagnosticos/diagnosticos_categoria_contatos_form.html', + context) diff --git a/sigi/apps/diagnosticos/widgets.py b/sigi/apps/diagnosticos/widgets.py new file mode 100644 index 0000000..a9d630b --- /dev/null +++ b/sigi/apps/diagnosticos/widgets.py @@ -0,0 +1,61 @@ +from itertools import chain +from django.forms.widgets import CheckboxInput, CheckboxSelectMultiple, RadioSelect, RadioFieldRenderer, RadioInput +from django.utils.html import conditional_escape +from django.utils.encoding import force_unicode +from django.utils.safestring import mark_safe +from sigi.apps.diagnosticos.models import Escolha + +class EavCheckboxSelectMultiple(CheckboxSelectMultiple): + def render(self, name, value, attrs=None, choices=()): + if value is None: value = [] + final_attrs = self.build_attrs(attrs, name=name) + output = [u'
    '] + str_values = set([force_unicode(v) for v in value]) + for i, (option_value, option_label) in enumerate(chain(self.choices, choices)): + final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i)) + label_for = u' for="%s"' % final_attrs['id'] + + # Caso exista uma pergunta para abrir + # adiciona um atripbuto no checkbox + schema_to_open = Escolha.objects.get(pk=option_value).schema_to_open + if schema_to_open: + final_attrs['schema_to_open'] = schema_to_open.name + + cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) + option_value = force_unicode(option_value) + rendered_cb = cb.render(name, option_value) + option_label = conditional_escape(force_unicode(option_label)) + output.append(u'
  • %s %s
  • ' % (label_for, rendered_cb, option_label)) + output.append(u'
') + return mark_safe(u'\n'.join(output)) + +class EavRadioFieldRenderer(RadioFieldRenderer): + def __iter__(self): + for i, choice in enumerate(self.choices): + final_attrs = self.attrs.copy() + + # Caso exista uma pergunta para abrir + # adiciona um atripbuto no checkbox + if choice[0]: + schema_to_open = Escolha.objects.get(pk=choice[0]).schema_to_open + if schema_to_open: + final_attrs['schema_to_open'] = schema_to_open.name + + yield RadioInput(self.name, self.value, final_attrs, choice, i) + + def __getitem__(self, idx): + choice = self.choices[idx] + + final_attrs = self.attrs.copy() + + # Caso exista uma pergunta para abrir + # adiciona um atripbuto no checkbox + schema_to_open = Escolha.objects.get(pk=self.value).schema_to_open + if schema_to_open: + final_attrs['schema_to_open'] = schema_to_open.name + + return RadioInput(self.name, self.value,final_attrs, choice, idx) + +class EavRadioSelect(RadioSelect): + renderer = EavRadioFieldRenderer + diff --git a/sigi/apps/servicos/models.py b/sigi/apps/servicos/models.py index 94c5862..706bdb1 100644 --- a/sigi/apps/servicos/models.py +++ b/sigi/apps/servicos/models.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from django.db import models from django.contrib.contenttypes import generic -from apps.casas.models import CasaLegislativa +from sigi.apps.casas.models import CasaLegislativa from datetime import date class Servico(models.Model): @@ -75,4 +75,4 @@ class DominioLeg(models.Model): def __unicode__(self): return str(self.dominio) - \ No newline at end of file + diff --git a/sigi/apps/servidores/admin.py b/sigi/apps/servidores/admin.py index 4c9e5a5..1462b94 100644 --- a/sigi/apps/servidores/admin.py +++ b/sigi/apps/servidores/admin.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- from django.contrib import admin from django.contrib.contenttypes import generic + +from sigi.apps.utils.admin_widgets import AdminImageWidget from sigi.apps.servidores.models import Servidor, Funcao, Licenca, Ferias from sigi.apps.contatos.models import Endereco, Telefone - -class FuncaoInline(admin.TabularInline): - model = Funcao - extra = 1 +from sigi.apps.servidores.forms import FeriasForm, LicencaForm, FuncaoForm class FuncaoAdmin(admin.ModelAdmin): + form = FuncaoForm list_display = ('servidor', 'funcao', 'cargo','inicio_funcao', 'fim_funcao') list_filter = ('inicio_funcao', 'fim_funcao') search_fields = ('funcao', 'cargo', 'descricao', @@ -16,33 +16,25 @@ class FuncaoAdmin(admin.ModelAdmin): 'servidor__user__email', 'servidor__user__first_name', 'servidor__user__last_name', 'servidor__user__username') -class FeriasInline(admin.TabularInline): - model = Ferias - extra = 1 - class FeriasAdmin(admin.ModelAdmin): + form = FeriasForm list_display = ('servidor', 'inicio_ferias', 'fim_ferias') - list_filter = ('servidor', 'inicio_ferias', 'fim_ferias') + list_filter = ('inicio_ferias', 'fim_ferias') search_fields = ('obs', - 'servidor__nome_completo', 'servidor__obs', 'servidor__apontamentos', - 'servidor__user__email', 'servidor__user__first_name', - 'servidor__user__last_name', 'servidor__user__username') - -class LicencaInline(admin.TabularInline): - model = Licenca - extra = 1 + 'servidor__nome_completo', 'servidor__email_pesoal', + 'servidor__user__email', 'servidor__user__username') class LicencaAdmin(admin.ModelAdmin): + form = LicencaForm list_display = ('servidor', 'inicio_licenca', 'fim_licenca') list_filter = ('servidor', 'inicio_licenca', 'fim_licenca') search_fields = ('obs', - 'servidor__nome_completo', 'servidor__obs', 'servidor__apontamentos', - 'servidor__user__email', 'servidor__user__first_name', - 'servidor__user__last_name', 'servidor__user__username') + 'servidor__nome_completo', 'servidor__email_pesoal', + 'servidor__user__email', 'servidor__user__username') -class EnderecoInline(generic.GenericTabularInline): +class EnderecoInline(generic.GenericStackedInline): model = Endereco - extra = 1 + extra = 0 raw_id_fields = ('municipio',) class TelefonesInline(generic.GenericTabularInline): @@ -50,8 +42,24 @@ class TelefonesInline(generic.GenericTabularInline): model = Telefone class ServidorAdmin(admin.ModelAdmin): - list_display = ('nome_completo', 'servico') - list_filter = ('sexo', 'servico') + + def is_active(self, servidor): + return servidor.user.is_active + is_active.admin_order_field = 'is_active' + is_active.boolean = True + is_active.short_description = 'ativo' + + def queryset(self, request): + qs = super(ServidorAdmin, self).queryset(request) + qs = qs.extra(select={'is_active': """ + SELECT auth_user.is_active + FROM auth_user + WHERE auth_user.id = servidores_servidor.user_id + """}) + return qs + + list_display = ('nome_completo', 'is_active', 'foto', 'servico') + list_filter = ('user', 'sexo', 'servico',) search_fields = ('nome_completo', 'obs', 'apontamentos', 'user__email', 'user__first_name', 'user__last_name', 'user__username') @@ -62,20 +70,23 @@ class ServidorAdmin(admin.ModelAdmin): 'fields': ('user',), }), ('Cadastro', { - 'fields': ('nome_completo', 'foto', 'email_pessoal', 'rg', 'cpf', 'sexo', 'data_nascimento', 'matricula', 'ramal') + 'fields': ('nome_completo', 'foto', 'email_pessoal', 'rg', 'cpf', 'sexo', 'data_nascimento', 'matricula', 'ramal', 'data_nomeacao', 'ato_numero', 'ato_exoneracao') }), ('Origem', { - 'fields': ('turno',), + 'fields': ('turno', 'de_fora'), }), (u'Observações', { 'fields': ('apontamentos', 'obs'), }), - #('Advanced options', { - # 'classes': ('collapse',), - # 'fields': ('enable_comments', 'registration_required', 'template_name') - #}), ) + def formfield_for_dbfield(self, db_field, **kwargs): + if db_field.name == 'foto': + request = kwargs.pop("request", None) + kwargs['widget'] = AdminImageWidget + return db_field.formfield(**kwargs) + return super(ServidorAdmin,self).formfield_for_dbfield(db_field, **kwargs) + admin.site.register(Servidor, ServidorAdmin) admin.site.register(Funcao, FuncaoAdmin) admin.site.register(Ferias, FeriasAdmin) diff --git a/sigi/apps/servidores/forms.py b/sigi/apps/servidores/forms.py new file mode 100644 index 0000000..f87cebc --- /dev/null +++ b/sigi/apps/servidores/forms.py @@ -0,0 +1,60 @@ +# -*- coding: utf8 -*- + +from django import forms + +from sigi.apps.utils.validators import valida_data, valida_periodo_data + +from sigi.apps.servidores.models import Ferias, Licenca, Funcao, Servidor + + +class FeriasForm(forms.ModelForm): + class Meta: + model = Ferias + + def clean(self): + data = self.cleaned_data + if valida_data(data.get('inicio_ferias'), data.get('fim_ferias')): + raise forms.ValidationError(u"""A data de início deve ser menor + que a data final. Verifique novamente""") + return data + + +class LicencaForm(forms.ModelForm): + class Meta: + model = Licenca + + def clean(self): + data = self.cleaned_data + if valida_data(data.get('inicio_licenca'), data.get('fim_licenca')): + raise forms.ValidationError(u"""A data de início deve ser menor + que a data final. Verifique novamente""") + return data + + +class FuncaoForm(forms.ModelForm): + class Meta: + model = Funcao + + def clean(self): + data = self.cleaned_data + if valida_data(data.get('inicio_funcao'), data.get('fim_funcao')): + raise forms.ValidationError(u"""A data de início deve ser menor + que a data final. Verifique + novamente""") + + # Verifica na função anterior, se o seu período é igual + # ou está entre o período da função atual. + servidor = Servidor.objects.get(nome_completo=data.get('servidor')) + if len(servidor.funcao_set.all()): + if len(servidor.funcao_set.all()) > 1: + funcao_anterior = servidor.funcao_set.all()[1] + elif len(servidor.funcao_set.all()) == 1: + funcao_anterior = servidor.funcao_set.all()[0] + + if valida_periodo_data(funcao_anterior.inicio_funcao, + funcao_anterior.fim_funcao, data.get('inicio_funcao'), + data.get('fim_funcao')): + raise forms.ValidationError(u"""Você não pode exercer + uma função no mesmo período que a anterior, como também, + não pode ser entre o período da mesma.""") + return data diff --git a/sigi/apps/servidores/management/__init__.py b/sigi/apps/servidores/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sigi/apps/servidores/management/commands/__init__.py b/sigi/apps/servidores/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sigi/apps/servidores/management/commands/migra.py b/sigi/apps/servidores/management/commands/migra.py new file mode 100644 index 0000000..61a934f --- /dev/null +++ b/sigi/apps/servidores/management/commands/migra.py @@ -0,0 +1,233 @@ +# coding= utf-8 +import sys +import csv +import re +from datetime import datetime +from django.core.management.base import BaseCommand, CommandError +from django.contrib.auth.models import User +from sigi.apps.servidores.models import Servidor, Servico, Subsecretaria, Funcao, Ferias, Licenca +from sigi.apps.contatos.models import Municipio + +#Funcao.objects.all().delete() +#Ferias.objects.all().delete() +#Licenca.objects.all().delete() +#for u in User.objects.filter(date_joined__gte=datetime(2011, 12, 9, 10, 58, 49, 83734)).all(): +# u.servidor_set.all().delete() +# u.delete() + +class MigrationError(Exception): + pass + +class Command(BaseCommand): + help = 'Migra usuários do antigo Sistema de RH' + + def to_date(self, data): + return datetime.strptime(data, "%Y-%m-%d 00:00:00") + + def handle(self, *args, **options): + reader = csv.reader(open("/tmp/pessoal.csv"), delimiter=',', quotechar="\"") + + BRASILIA = Municipio.objects.get(codigo_ibge=5300108) + + # Read the column names from the first line of the file + fields = reader.next() + for row in reader: + # cria um dict com a primeira e a linha atual + pessoa = zip(fields, row) + p = {} + for (name, value) in pessoa: + p[name] = value.strip() + + user = None + if not p['email']: + username = '' + email = '' + elif not ('@interlegis' in p['email']): + username = p['email'].split('@')[0].strip().lower() + email = '' + else: + username = p['email'].split('@')[0].strip().lower() + email = username + '@interlegis.gov.br' + + # buscar usuário e servidor da linha atual + try: + # procuro o usuario por email do interlegis + if email: + try: user = User.objects.get(email=email) + except User.DoesNotExist: pass + + if not user and username: + try: user = User.objects.get(username=username) + except User.DoesNotExist: + try: user = User.objects.get(username=username + "__") + except User.DoesNotExist: pass + + if not user: + if not username: + raise MigrationError + + if not email: + # cria um username a partir do email sem + # colidir com os usuarios ldap + username = username + '__' + + names = p['nome_completo'].split(' ') + first_name = names[0] + last_name = " ".join(names[1:]) + + user = User.objects.create( + username = username, + email = email, + first_name = first_name, + last_name = last_name[:30], + is_active= False + ) + + servidor = user.servidor + except Servidor.DoesNotExist: + servidor = Servidor.objects.create( + user=user, + nome_completo= "%s %s" % (user.first_name, user.last_name) + ) + except MigrationError, e: + print ", ".join(row) + continue + + # mapeando dados simples + servidor.nome_completo = p['nome_completo'] + servidor.cpf = p['cpf'] + servidor.rg = p['identidade'] + servidor.apelido = p['username'] + servidor.matricula = p['matricula'] + servidor.ato_exoneracao = p['ato_exoneracao'] + servidor.ato_numero = p['ato_numero'] + servidor.ramal = p['ramal'] + + if p['email'] and not '@interlegis' in p['email']: + servidor.email_pessoal= p['email'] + + if p['inativo']=="-1": + servidor.user.is_active = False + else: + servidor.user.is_active = True + servidor.user.save() + + if p['de_fora']=="-1": + servidor.de_fora = True + else: + servidor.de_fora = False + + if p['sexo'].upper() == 'M': + servidor.sexo = 'M' + elif p['sexo'].upper() == 'F': + servidor.sexo = 'F' + + if p['turno']=="1": + servidor.turno = 'M' + elif p['turno']=="2": + servidor.turno = 'T' + elif p['turno']=="3": + servidor.turno = 'N' + + if p['aniversario']: + servidor.data_nascimento = self.to_date(p['aniversario']) + + if p['data_nomeacao']: + servidor.data_nomeacao = self.to_date(p['data_nomeacao']) + + if p['secretaria_sigla']: + if ' - ' in p['secretaria_nome']: + secretaria_nome = p['secretaria_nome'].split(' - ')[1] + else: + secretaria_nome = p['secretaria_nome'] + + secretaria = Subsecretaria.objects.get_or_create( + sigla = p['secretaria_sigla'], + nome = secretaria_nome + )[0] + + if ' - ' in p['servico_nome']: + servico_nome = p['servico_nome'].split(' - ')[1] + else: + servico_nome = p['servico_nome'] + + servico = Servico.objects.get_or_create( + sigla = p['servico_sigla'], + nome = servico_nome + )[0] + + servico.subsecretaria = secretaria + servico.save() + servidor.servico = servico + + if p['telefone']: + try: + t = servidor.telefones.get(numero=p['telefone']) + except: + t = servidor.telefones.create(numero=p['telefone']) + t.tipo = 'F' + t.save() + + if p['celular']: + try: + t = servidor.telefones.get(numero=p['celular']) + except: + t = servidor.telefones.create(numero=p['celular']) + t.tipo = 'M' + t.save() + + if p['endereco']: + try: + e = servidor.endereco.get(logradouro=p['endereco']) + except: + e = servidor.endereco.create(logradouro=p['endereco']) + e.municipio = BRASILIA + e.bairro = p['cidade'] # bizarro mas é isso mesmo + e.cep = re.sub("\D", "", p['cep']) + e.save() + + servidor.apontamentos = p['apontamentos'] + servidor.obs = p['obs'] + + if p['cargo'] or p['funcao']: + funcao = servidor.funcao_set.get_or_create( + funcao = p['funcao'], + cargo = p['cargo'], + )[0] + + if p['data_bap_entrada']: + funcao.data_bap_entrada = self.to_date(p['data_bap_entrada']) + + if p['data_bap_saida']: + funcao.data_bap_saida = self.to_date(p['data_bap_saida']) + + if p['data_entrada']: + funcao.inicio_funcao = self.to_date(p['data_entrada']) + + if p['data_saida']: + funcao.fim_funcao = self.to_date(p['data_saida']) + + funcao.bap_entrada = p['bap_entrada'] + funcao.bap_saida = p['bap_saida'] + funcao.save() + + if re.search(r'estagi.ri[o|a]',p['cargo'],re.I): + #TODO inserir dados de estagio + pass + + if p['inicio_ferias'] and p['final_ferias']: + servidor.ferias_set.get_or_create( + inicio_ferias = self.to_date(p['inicio_ferias']), + fim_ferias = self.to_date(p['final_ferias']), + obs = p['obs_ferias'] + ) + + if p['inicio_licenca'] and p['fim_licenca']: + servidor.licenca_set.get_or_create( + inicio_licenca = self.to_date(p['inicio_licenca']), + fim_licenca = self.to_date(p['fim_licenca']), + obs = p['obs_licenca'] + ) + + servidor.save() + diff --git a/sigi/apps/servidores/management/commands/sync_ldap.py b/sigi/apps/servidores/management/commands/sync_ldap.py new file mode 100644 index 0000000..4d24cd8 --- /dev/null +++ b/sigi/apps/servidores/management/commands/sync_ldap.py @@ -0,0 +1,93 @@ +# coding= utf-8 +import ldap +from django.core.management.base import BaseCommand, CommandError +from django.contrib.auth.models import User, Group +from sigi.settings import * +from sigi.apps.servidores.models import Servidor + +class Command(BaseCommand): + help = 'Sincroniza Usuários e Servidores com o LDAP' + + def handle(self, *args, **options): + self.sync_groups() + self.sync_users() + + def get_ldap_groups(self): + filter = "(&(objectclass=Group))" + values = ['cn',] + l = ldap.initialize(AUTH_LDAP_SERVER_URI) + l.protocol_version = ldap.VERSION3 + l.simple_bind_s(AUTH_LDAP_BIND_DN.encode('utf-8'),AUTH_LDAP_BIND_PASSWORD) + result_id = l.search(AUTH_LDAP_GROUP, ldap.SCOPE_SUBTREE, filter, values) + result_type, result_data = l.result(result_id, 1) + l.unbind() + return result_data + + def get_ldap_users(self): + filter = "(&(objectclass=user))" + values = ['sAMAccountName', 'userPrincipalName', 'givenName', 'sn', 'cn' ] + l = ldap.initialize(AUTH_LDAP_SERVER_URI) + l.protocol_version = ldap.VERSION3 + l.simple_bind_s(AUTH_LDAP_BIND_DN.encode('utf-8'),AUTH_LDAP_BIND_PASSWORD) + result_id = l.search(AUTH_LDAP_USER.encode('utf-8'), ldap.SCOPE_SUBTREE, filter, values) + result_type, result_data = l.result(result_id, 1) + l.unbind() + return result_data + + def sync_groups(self): + ldap_groups = self.get_ldap_groups() + for ldap_group in ldap_groups: + try: group_name = ldap_group[1]['cn'][0] + except: pass + else: + try: group = Group.objects.get(name=group_name) + except Group.DoesNotExist: + group = Group(name=group_name) + group.save() + print "Group '%s' created." % group_name + print "Groups are synchronized." + + def sync_users(self): + ldap_users = self.get_ldap_users() + for ldap_user in ldap_users: + try: username = ldap_user[1]['sAMAccountName'][0] + except: pass + else: + try: email = ldap_user[1]['userPrincipalName'][0] + except: email = '' + try: first_name = ldap_user[1]['givenName'][0] + except: first_name = username + try: last_name = ldap_user[1]['sn'][0][:30] + except: last_name = '' + try: user = User.objects.get(username=username) + except User.DoesNotExist: + user = User.objects.create_user(username, email, username) + user.first_name = first_name + user.last_name = last_name + print "User '%s' created." % username + try: nome_completo = ldap_user[1]['cn'][0] + except: nome_completo = '' + try: + servidor = user.servidor + if not servidor.nome_completo == nome_completo.decode('utf8'): + servidor.nome_completo = nome_completo + print "Servidor '%s' updated." % nome_completo + except Servidor.DoesNotExist: + try: servidor = Servidor.objects.get(nome_completo=nome_completo) + except Servidor.DoesNotExist: + servidor = user.servidor_set.create(nome_completo=nome_completo) + print "Servidor '%s' created." % nome_completo + else: + if not user.email == email.decode('utf8'): + user.email = email + print "User '%s' email updated." % username + if not user.first_name == first_name.decode('utf8'): + user.first_name = first_name + print "User '%s' first name updated." % username + if not user.last_name == last_name.decode('utf8'): + user.last_name = last_name + print "User '%s' last name updated." % username + servidor.user = user + servidor.save() + user.save() + print "Users are synchronized." diff --git a/sigi/apps/servidores/models.py b/sigi/apps/servidores/models.py index 9630507..6e8bae2 100644 --- a/sigi/apps/servidores/models.py +++ b/sigi/apps/servidores/models.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django.db import models +from django.db.models.signals import post_save from django.contrib.contenttypes import generic from django.contrib.auth.models import User @@ -7,10 +8,10 @@ class Subsecretaria(models.Model): """ Modelo para representação das Subsecretarias do Interlegis """ - nome = models.CharField(max_length=50) - sigla = models.CharField(max_length=10) + nome = models.CharField(max_length=250, null=True) + sigla = models.CharField(max_length=10, null=True) # servidor responsavel por dirigir a Subsecretaria - responsavel = models.ForeignKey('servidores.Servidor', related_name='diretor') + responsavel = models.ForeignKey('servidores.Servidor', related_name='diretor', null=True) class Meta: ordering = ('nome',) @@ -22,11 +23,11 @@ class Servico(models.Model): """ Modelo para representação dos Serviços de uma Subsecretaria """ - nome = models.CharField(max_length=50) - sigla = models.CharField(max_length=10) - subsecretaria = models.ForeignKey(Subsecretaria) + nome = models.CharField(max_length=250, null=True) + sigla = models.CharField(max_length=10, null=True) + subsecretaria = models.ForeignKey(Subsecretaria, null=True) # servidor responsavel por chefiar o serviço - responsavel = models.ForeignKey('servidores.Servidor', related_name='chefe') + responsavel = models.ForeignKey('servidores.Servidor', related_name='chefe', null=True) class Meta: ordering = ('nome',) @@ -56,6 +57,7 @@ class Servidor(models.Model): # usuario responsavel pela autenticação do servidor no sistema user = models.ForeignKey(User, unique=True) + user.is_active__filter = True nome_completo = models.CharField(max_length=128) nome_completo.alphabetic_filter = True apelido = models.CharField(max_length=50, blank=True) @@ -87,34 +89,36 @@ class Servidor(models.Model): blank=True, null=True, ) + de_fora = models.BooleanField(default=False) data_nomeacao = models.DateField(u'data de nomeação', blank=True, null=True) ato_exoneracao = models.CharField(u'ato de exoneração',max_length=150, blank=True, null=True) + ato_numero = models.CharField(u'ato de exoneração',max_length=150, blank=True, null=True) cpf = models.CharField('CPF', max_length=11, blank=True, null=True) rg = models.CharField('RG', max_length=25, blank=True, null=True) obs = models.TextField(u'observação', blank=True, null=True) apontamentos = models.TextField(u'apontamentos', blank=True, null=True) # Informações de contato - email_pessoal = models.EmailField('e-mail pessoal', blank=True, null=True) + email_pessoal = models.EmailField('email pessoal', blank=True, null=True) endereco = generic.GenericRelation('contatos.Endereco') telefones = generic.GenericRelation('contatos.Telefone') - ramal = models.IntegerField('ramal', blank=True, null=True) + ramal = models.CharField(max_length=25, blank=True, null=True) class Meta: ordering = ('nome_completo',) verbose_name_plural = 'servidores' - def is_chefe(): + def is_chefe(self): """ Verifica se o servidor é chefe ou diretor """ pass - def data_entrada(): + def data_entrada(self): """ Verifica a data de entrada da função mais antiga """ pass - def data_saida(): + def data_saida(self): """ Verifica a data de saída da função mais recente de um servidor desativado @@ -122,17 +126,45 @@ class Servidor(models.Model): """ pass + @property + def diagnosticos(self): + """ Retorna todos os diagnosticos que este servidor + participa, isto é, como responsavel ou parte da equipe + """ + diagnosticos = set(self.diagnostico_set.filter(publicado=True).all()) + + for equipe in self.equipe_set.all(): + diagnosticos.add(equipe.diagnostico) + + return list(diagnosticos) + def __unicode__(self): return self.nome_completo +# Soluçao alternativa para extender o usuário do django +# Acessa do servidor de um objeto user criando um profile +# baseado nos dados do LDAP +User.servidor = property(lambda user: Servidor.objects.get(user=user)) + +# Sinal para ao criar um usuário criar um servidor +# baseado no nome contino no LDAP +def create_user_profile(sender, instance, created, **kwargs): + if created: + Servidor.objects.create( + user=instance, + nome_completo= "%s %s" % (instance.first_name, instance.last_name) + ) + +post_save.connect(create_user_profile, sender=User) + class Funcao(models.Model): """ Modelo para guardar o histórico de funções dos servidores no Interlegis """ servidor = models.ForeignKey(Servidor) - funcao = models.CharField(max_length=50) - cargo = models.CharField(max_length=50, blank=True, null=True) - inicio_funcao = models.DateField(u'início da função') + funcao = models.CharField(max_length=250, null=True) + cargo = models.CharField(max_length=250, null=True) + inicio_funcao = models.DateField(u'início da função', null=True) fim_funcao = models.DateField(u'fim da função', blank=True, null=True) descricao = models.TextField(u'descrição', blank=True, null=True) diff --git a/sigi/apps/utils/admin_widgets.py b/sigi/apps/utils/admin_widgets.py new file mode 100644 index 0000000..3590a2b --- /dev/null +++ b/sigi/apps/utils/admin_widgets.py @@ -0,0 +1,16 @@ +from django.contrib.admin.widgets import AdminFileWidget +from django.utils.translation import ugettext as _ +from django.utils.safestring import mark_safe + +class AdminImageWidget(AdminFileWidget): + def render(self, name, value, attrs=None): + output = [] + if value and getattr(value, "url", None): + image_url = value.url + file_name=str(value) + output.append( + u''' %s
%s''' % \ + (image_url, image_url, file_name, _('Change:'))) + output.append(super(AdminFileWidget, self).render(name, value, attrs)) + return mark_safe(u''.join(output)) diff --git a/sigi/apps/utils/decorators.py b/sigi/apps/utils/decorators.py new file mode 100644 index 0000000..736d527 --- /dev/null +++ b/sigi/apps/utils/decorators.py @@ -0,0 +1,71 @@ +# -*- coding: utf8 -*- + +""" +Script baseado no arquivo decorators.py do django 1.3. +Ele foi copiado para usar o decorador ``login_required`` +que possui o argumento ``login_url``, responsável por +redirecionar ao template de login desejado. + +No ato de atualizar o framework, esse script torna-se +obsoleto. +""" + +import urlparse +try: + from functools import wraps +except ImportError: + from django.utils.functional import wraps # Python 2.4 fallback. + +from django.conf import settings +from django.contrib.auth import REDIRECT_FIELD_NAME +from django.utils.decorators import available_attrs + + +def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME): + """ + Decorator for views that checks that the user passes the given test, + redirecting to the log-in page if necessary. The test should be a callable + that takes the user object and returns True if the user passes. + """ + + def decorator(view_func): + @wraps(view_func, assigned=available_attrs(view_func)) + def _wrapped_view(request, *args, **kwargs): + if test_func(request.user): + return view_func(request, *args, **kwargs) + path = request.build_absolute_uri() + # If the login url is the same scheme and net location then just + # use the path as the "next" url. + login_scheme, login_netloc = urlparse.urlparse(login_url or + settings.LOGIN_URL)[:2] + current_scheme, current_netloc = urlparse.urlparse(path)[:2] + if ((not login_scheme or login_scheme == current_scheme) and + (not login_netloc or login_netloc == current_netloc)): + path = request.get_full_path() + from django.contrib.auth.views import redirect_to_login + return redirect_to_login(path, login_url, redirect_field_name) + return _wrapped_view + return decorator + + +def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None): + """ + Decorator for views that checks that the user is logged in, redirecting + to the log-in page if necessary. + """ + actual_decorator = user_passes_test( + lambda u: u.is_authenticated(), + login_url=login_url, + redirect_field_name=redirect_field_name + ) + if function: + return actual_decorator(function) + return actual_decorator + + +def permission_required(perm, login_url=None): + """ + Decorator for views that checks whether a user has a particular permission + enabled, redirecting to the log-in page if necessary. + """ + return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url) diff --git a/sigi/apps/utils/email.py b/sigi/apps/utils/email.py new file mode 100644 index 0000000..5ccda83 --- /dev/null +++ b/sigi/apps/utils/email.py @@ -0,0 +1,33 @@ +# -*- coding: utf8 -*- + +from django.template.loader import render_to_string +from django.core.mail import EmailMessage +from django.conf import settings + + +def enviar_email(from_email, subject, template, tags): + """Envia o email para o destinatário definido, a partir do template + definido para ser renderizado. Os argumentos são: + * from_email - Email do remetente + * subject - Assunto da Mensagem + * template - Template que será usado para gerar o corpo + da mensagem + * tags - Variáveis de contexto para ser renderizado no + template. + """ + if from_email is None: + raise ValueError("Insira o email do remetente.") + elif subject is None: + raise ValueError("Insira o assunto da mensagem.") + elif template is None: + raise ValueError(u"Template da mensagem não encontrado") + elif tags is None: + raise ValueError("Insira o conteúdo da mensagem.") + + # Gerando a mensagem + mensagem = render_to_string(template, tags) + + # Enviando a mensagem + email = EmailMessage(settings.EMAIL_SUBJECT_PREFIX + " " + subject, mensagem, + from_email, [from_email]) + email.send() diff --git a/sigi/apps/utils/validators.py b/sigi/apps/utils/validators.py new file mode 100644 index 0000000..fcfc8f7 --- /dev/null +++ b/sigi/apps/utils/validators.py @@ -0,0 +1,42 @@ +# -*- coding: utf8 -*- + + +def valida_data(data_inicio, data_final): + """Função responsável por validar se o intervalo das + datas estão erradas, ou seja, se a data de início está + maior ou igual a data final. + + Caso seja maior ou igual retornará ``True``, caso contrário + retornará ``False``. + """ + if data_inicio >= data_final: + return True + else: + return False + + +def valida_periodo_data(di01, df01, di02, df02): + """Função responsável por validar dois períodos de datas. + Isso é usado para verificar se determinado servidor exerceu + mais de uma função dentro de determinados períodos descritos + abaixo: + + 1 - A segunda função não pode ter exercido ao mesmo tempo que + a primeira função. Exemplo: + + Primeiro Função: 01/05/2011 -- 01/11/2011 + Segundo Função: 01/05/2011 -- 01/11/2011 + + 2 - A segunda função não pode ter exercido, dentro do período + da primeira função. Exemplo: + + Primeira Função: 01/05/2011 -- 01/11/2011 + Segunda Função: 02/05/2011 -- 30/10/2011 + """ + # Verificando a primeira situação + if di01 == di02 and df01 == df02: + return True + elif ((di01 >= di02) or (di02 <= df01)) and df01 <= df02: + return True + else: + return False diff --git a/sigi/fixtures/treemenus/initial_data.json b/sigi/fixtures/treemenus/initial_data.json index e124271..b1d24e6 100644 --- a/sigi/fixtures/treemenus/initial_data.json +++ b/sigi/fixtures/treemenus/initial_data.json @@ -1 +1 @@ -[{"pk": 1, "model": "treemenus.menuitem", "fields": {"parent": null, "level": 0, "url": "", "menu": 1, "rank": 0, "caption": "Root", "named_url": ""}}, {"pk": 26, "model": "treemenus.menuitem", "fields": {"parent": null, "level": 0, "url": "", "menu": 2, "rank": 0, "caption": "Root", "named_url": ""}}, {"pk": 27, "model": "treemenus.menuitem", "fields": {"parent": null, "level": 0, "url": "", "menu": 3, "rank": 0, "caption": "Root", "named_url": ""}}, {"pk": 32, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sites/site/", "menu": 3, "rank": 2, "caption": "Sites", "named_url": ""}}, {"pk": 24, "model": "treemenus.menuitem", "fields": {"parent": 23, "level": 2, "url": "/sigi/contatos/municipio/", "menu": 1, "rank": 0, "caption": "Munic\u00edpios", "named_url": ""}}, {"pk": 25, "model": "treemenus.menuitem", "fields": {"parent": 23, "level": 2, "url": "/sigi/contatos/unidadefederativa/", "menu": 1, "rank": 1, "caption": "Unidades Federativas", "named_url": ""}}, {"pk": 30, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sigi/auth/", "menu": 3, "rank": 0, "caption": "Usu\u00e1rios & Grupos", "named_url": ""}}, {"pk": 28, "model": "treemenus.menuitem", "fields": {"parent": 26, "level": 1, "url": "/sigi/password_change/", "menu": 2, "rank": 0, "caption": "Alterar senha", "named_url": ""}}, {"pk": 29, "model": "treemenus.menuitem", "fields": {"parent": 26, "level": 1, "url": "/sigi/logout/", "menu": 2, "rank": 1, "caption": "Encerrar sess\u00e3o", "named_url": ""}}, {"pk": 31, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sigi/treemenus/menu/", "menu": 3, "rank": 1, "caption": "Menus", "named_url": ""}}, {"pk": 33, "model": "treemenus.menuitem", "fields": {"parent": 3, "level": 2, "url": "/sigi/casas/casalegislativa/", "menu": 1, "rank": 0, "caption": "Todas", "named_url": ""}}, {"pk": 35, "model": "treemenus.menuitem", "fields": {"parent": 3, "level": 2, "url": "/sigi/casas/casalegislativa/?tipo__id__exact=2", "menu": 1, "rank": 2, "caption": "Assembl\u00e9ias Legislativas", "named_url": ""}}, {"pk": 34, "model": "treemenus.menuitem", "fields": {"parent": 3, "level": 2, "url": "/sigi/casas/casalegislativa/?tipo__id__exact=1", "menu": 1, "rank": 1, "caption": "C\u00e2maras Municipais", "named_url": ""}}, {"pk": 37, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/bem/", "menu": 1, "rank": 0, "caption": "Bens", "named_url": ""}}, {"pk": 38, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/fornecedor/", "menu": 1, "rank": 1, "caption": "Fornecedores", "named_url": ""}}, {"pk": 39, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/equipamento/", "menu": 1, "rank": 2, "caption": "Equipamentos", "named_url": ""}}, {"pk": 40, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/fabricante/", "menu": 1, "rank": 3, "caption": "Fabricantes", "named_url": ""}}, {"pk": 41, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/tipoequipamento/", "menu": 1, "rank": 4, "caption": "Tipos de equipamentos", "named_url": ""}}, {"pk": 42, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/modeloequipamento/", "menu": 1, "rank": 5, "caption": "Modelos de equipamentos", "named_url": ""}}, {"pk": 2, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi", "menu": 1, "rank": 0, "caption": "Gr\u00e1ficos", "named_url": ""}}, {"pk": 23, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/contatos/municipio/", "menu": 1, "rank": 1, "caption": "Munic\u00edpios", "named_url": ""}}, {"pk": 3, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/casas/casalegislativa/", "menu": 1, "rank": 2, "caption": "Casas Legislativas", "named_url": ""}}, {"pk": 14, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/convenios/convenio/", "menu": 1, "rank": 3, "caption": "Conv\u00eanios", "named_url": ""}}, {"pk": 36, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/inventario/bem/", "menu": 1, "rank": 4, "caption": "Invent\u00e1rio", "named_url": ""}}, {"pk": 1, "model": "treemenus.menu", "fields": {"root_item": 1, "name": "Barra de navega\u00e7\u00e3o"}}, {"pk": 2, "model": "treemenus.menu", "fields": {"root_item": 26, "name": "Usu\u00e1rio"}}, {"pk": 3, "model": "treemenus.menu", "fields": {"root_item": 27, "name": "Administrador"}}] +[{"pk": 2, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/", "menu": 1, "rank": 0, "caption": "Gr\u00e1ficos", "named_url": ""}}, {"pk": 55, "model": "treemenus.menuitem", "fields": {"parent": 54, "level": 2, "url": "/sigi/servidores/servidor/", "menu": 1, "rank": 0, "caption": "Pessoal", "named_url": ""}}, {"pk": 58, "model": "treemenus.menuitem", "fields": {"parent": 54, "level": 2, "url": "/sigi/servidores/licenca/", "menu": 1, "rank": 3, "caption": "Licen\u00e7as", "named_url": ""}}, {"pk": 1, "model": "treemenus.menuitem", "fields": {"parent": null, "level": 0, "url": "", "menu": 1, "rank": 0, "caption": "Root", "named_url": ""}}, {"pk": 26, "model": "treemenus.menuitem", "fields": {"parent": null, "level": 0, "url": "", "menu": 2, "rank": 0, "caption": "Root", "named_url": ""}}, {"pk": 27, "model": "treemenus.menuitem", "fields": {"parent": null, "level": 0, "url": "", "menu": 3, "rank": 0, "caption": "Root", "named_url": ""}}, {"pk": 24, "model": "treemenus.menuitem", "fields": {"parent": 23, "level": 2, "url": "/sigi/contatos/municipio/", "menu": 1, "rank": 0, "caption": "Munic\u00edpios", "named_url": ""}}, {"pk": 25, "model": "treemenus.menuitem", "fields": {"parent": 23, "level": 2, "url": "/sigi/contatos/unidadefederativa/", "menu": 1, "rank": 1, "caption": "Unidades Federativas", "named_url": ""}}, {"pk": 30, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sigi/auth/", "menu": 3, "rank": 0, "caption": "Usu\u00e1rios & Grupos", "named_url": ""}}, {"pk": 28, "model": "treemenus.menuitem", "fields": {"parent": 26, "level": 1, "url": "/sigi/password_change/", "menu": 2, "rank": 0, "caption": "Alterar senha", "named_url": ""}}, {"pk": 29, "model": "treemenus.menuitem", "fields": {"parent": 26, "level": 1, "url": "/sigi/logout/", "menu": 2, "rank": 1, "caption": "Encerrar sess\u00e3o", "named_url": ""}}, {"pk": 31, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sigi/treemenus/menu/", "menu": 3, "rank": 1, "caption": "Menus", "named_url": ""}}, {"pk": 33, "model": "treemenus.menuitem", "fields": {"parent": 3, "level": 2, "url": "/sigi/casas/casalegislativa/", "menu": 1, "rank": 0, "caption": "Todas", "named_url": ""}}, {"pk": 35, "model": "treemenus.menuitem", "fields": {"parent": 3, "level": 2, "url": "/sigi/casas/casalegislativa/?tipo__id__exact=2", "menu": 1, "rank": 2, "caption": "Assembl\u00e9ias Legislativas", "named_url": ""}}, {"pk": 34, "model": "treemenus.menuitem", "fields": {"parent": 3, "level": 2, "url": "/sigi/casas/casalegislativa/?tipo__id__exact=1", "menu": 1, "rank": 1, "caption": "C\u00e2maras Municipais", "named_url": ""}}, {"pk": 37, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/bem/", "menu": 1, "rank": 0, "caption": "Bens", "named_url": ""}}, {"pk": 38, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/fornecedor/", "menu": 1, "rank": 1, "caption": "Fornecedores", "named_url": ""}}, {"pk": 54, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/servidores/servidor/", "menu": 1, "rank": 6, "caption": "Servidores", "named_url": ""}}, {"pk": 40, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/fabricante/", "menu": 1, "rank": 3, "caption": "Fabricantes", "named_url": ""}}, {"pk": 41, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/tipoequipamento/", "menu": 1, "rank": 4, "caption": "Tipos de equipamentos", "named_url": ""}}, {"pk": 42, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/modeloequipamento/", "menu": 1, "rank": 5, "caption": "Modelos de equipamentos", "named_url": ""}}, {"pk": 39, "model": "treemenus.menuitem", "fields": {"parent": 36, "level": 2, "url": "/sigi/inventario/equipamento/", "menu": 1, "rank": 2, "caption": "Equipamentos", "named_url": ""}}, {"pk": 36, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/inventario/bem/", "menu": 1, "rank": 5, "caption": "Invent\u00e1rio", "named_url": ""}}, {"pk": 14, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/convenios/convenio/", "menu": 1, "rank": 4, "caption": "Conv\u00eanios", "named_url": ""}}, {"pk": 32, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sigi/sites/site/", "menu": 3, "rank": 3, "caption": "Sites", "named_url": ""}}, {"pk": 60, "model": "treemenus.menuitem", "fields": {"parent": 27, "level": 1, "url": "/sigi/diagnosticos/", "menu": 3, "rank": 2, "caption": "Diagn\u00f3sticos", "named_url": ""}}, {"pk": 59, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/diagnosticos/diagnostico/", "menu": 1, "rank": 3, "caption": "Diagn\u00f3sticos", "named_url": ""}}, {"pk": 56, "model": "treemenus.menuitem", "fields": {"parent": 54, "level": 2, "url": "/sigi/servidores/funcao", "menu": 1, "rank": 1, "caption": "Fun\u00e7\u00f5es", "named_url": ""}}, {"pk": 57, "model": "treemenus.menuitem", "fields": {"parent": 54, "level": 2, "url": "/sigi/servidores/ferias/", "menu": 1, "rank": 2, "caption": "F\u00e9rias", "named_url": ""}}, {"pk": 23, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/contatos/municipio/", "menu": 1, "rank": 1, "caption": "Munic\u00edpios", "named_url": ""}}, {"pk": 3, "model": "treemenus.menuitem", "fields": {"parent": 1, "level": 1, "url": "/sigi/casas/casalegislativa/", "menu": 1, "rank": 2, "caption": "Casas Legislativas", "named_url": ""}}, {"pk": 1, "model": "treemenus.menu", "fields": {"root_item": 1, "name": "Barra de navega\u00e7\u00e3o"}}, {"pk": 2, "model": "treemenus.menu", "fields": {"root_item": 26, "name": "Usu\u00e1rio"}}, {"pk": 3, "model": "treemenus.menu", "fields": {"root_item": 27, "name": "Administrador"}}] diff --git a/sigi/migrations/20111125_casas_funcionario.sql b/sigi/migrations/20111125_casas_funcionario.sql new file mode 100644 index 0000000..470876c --- /dev/null +++ b/sigi/migrations/20111125_casas_funcionario.sql @@ -0,0 +1,19 @@ +BEGIN; + +-- retirando null de algumas colunas +ALTER TABLE "contatos_telefone" ALTER COLUMN nota DROP NOT NULL; +ALTER TABLE "contatos_telefone" ALTER COLUMN codigo_area DROP NOT NULL; + +-- migrando dados de presidente da CasaLegislativa para Funcionarios +INSERT INTO casas_funcionario (casa_legislativa_id, cargo, setor, nome, nota, email) + SELECT id, 'Presidente', 'presidencia', presidente, '', '' FROM casas_casalegislativa; + +-- migrando dados de telefones da CasaLegislativa para model generic Telefone +INSERT INTO contatos_telefone (numero, tipo, content_type_id, object_id, codigo_area, nota) + SELECT telefone, 'F', 12, id, '', '' FROM casas_casalegislativa; + +-- deletando colunas fazer deois de estabilizar a versao +-- ALTER TABLE "casas_casalegislativa" DROP COLUMN presidente; +-- ALTER TABLE "casas_casalegislativa" DROP COLUMN telefone; +-- ALTER TABLE "contatos_telefone" DROP COLUMN codigo_area; +COMMIT; diff --git a/sigi/migrations/20111125_diagnosticos_responsavel.sql b/sigi/migrations/20111125_diagnosticos_responsavel.sql new file mode 100644 index 0000000..b9980cc --- /dev/null +++ b/sigi/migrations/20111125_diagnosticos_responsavel.sql @@ -0,0 +1,7 @@ +BEGIN; + +-- deletando colunas da CasaLegislativa +ALTER TABLE "diagnosticos_diagnostico" ADD COLUMN "responsavel_id" integer NOT NULL REFERENCES "servidores_servidor" ("id"); +ALTER TABLE "diagnosticos_equipe" DROP COLUMN "is_chefe"; + +COMMIT; diff --git a/sigi/settings.py b/sigi/settings.py index 5df353d..2487a1c 100644 --- a/sigi/settings.py +++ b/sigi/settings.py @@ -29,6 +29,14 @@ DEFAULT_FROM_EMAIL = 'noreply@localhost' INTERNAL_IPS = ('127.0.0.1',) +DEFAULT_FROM_EMAIL = 'sesostris@interlegis.leg.br' +EMAIL_SUBJECT_PREFIX = u'[SIGI]' +EMAIL_HOST = 'smtp.interlegis.leg.br' +EMAIL_PORT = 25 +EMAIL_HOST_USER = '' +EMAIL_HOST_PASSWORD = '' +#EMAIL_USE_TLS = True + #DATABASE_ENGINE = 'postgresql_psycopg2' DATABASE_ENGINE = 'sqlite3' DATABASE_NAME = 'devel.db' @@ -53,10 +61,12 @@ ADMIN_MEDIA_PREFIX = '/sigi/admin_media/' AUTH_LDAP_SERVER_URI = "ldap://w2k3dc01.interlegis.gov.br" AUTH_LDAP_BIND_DN = u"cn=sigi-ldap,ou=Usuários de Sistema,ou=Usuários,ou=Interlegis,dc=interlegis,dc=gov,dc=br" AUTH_LDAP_BIND_PASSWORD = "Sigi2609" -AUTH_LDAP_USER_SEARCH = LDAPSearch(u"ou=SINTER,ou=Usuários,ou=Sede,dc=interlegis,dc=gov,dc=br", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)") +AUTH_LDAP_USER = u"ou=SINTER,ou=Usuários,ou=Sede,dc=interlegis,dc=gov,dc=br" +AUTH_LDAP_USER_SEARCH = LDAPSearch(AUTH_LDAP_USER, ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)") # Set up the basic group parameters. -AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=Grupos Organizacionais,ou=Sede,dc=interlegis,dc=gov,dc=br", ldap.SCOPE_SUBTREE, "(objectClass=Group)") +AUTH_LDAP_GROUP = "ou=Grupos Organizacionais,ou=Sede,dc=interlegis,dc=gov,dc=br" +AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP, ldap.SCOPE_SUBTREE, "(objectClass=Group)") AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="cn") # Only users in this group can log in. @@ -74,9 +84,9 @@ AUTH_LDAP_USER_ATTR_MAP = { } # Populate the Django user_profile from the LDAP directory. -#AUTH_LDAP_PROFILE_ATTR_MAP = { -# "employee_number": "employeeNumber" -#} +AUTH_LDAP_PROFILE_ATTR_MAP = { + "nome_completo": "cn" +} #AUTH_LDAP_PROFILE_FLAGS_BY_GROUP = { # "is_awesome": "cn=awesome,ou=django,ou=groups,dc=example,dc=com", @@ -90,6 +100,8 @@ AUTH_LDAP_MIRROR_GROUPS = True AUTH_LDAP_CACHE_GROUPS = True AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 +AUTH_PROFILE_MODULE = 'servidores.Servidor' + # Keep ModelBackend around for per-user permissions and maybe a local superuser. AUTHENTICATION_BACKENDS = ( 'django_auth_ldap.backend.LDAPBackend', @@ -116,6 +128,7 @@ TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.debug', 'django.core.context_processors.i18n', 'django.core.context_processors.media', + 'django.core.context_processors.request', 'sigi.context_processors.charts_data', ) diff --git a/sigi/sites.py b/sigi/sites.py index 2bd2404..c5041bb 100644 --- a/sigi/sites.py +++ b/sigi/sites.py @@ -24,8 +24,9 @@ from sigi.apps.mesas.admin import (Legislatura, LegislaturaAdmin, Coligacao, from sigi.apps.parlamentares.admin import (Partido, PartidoAdmin, Parlamentar, ParlamentarAdmin, Mandato, MandatoAdmin) from sigi.apps.diagnosticos.admin import (Diagnostico, DiagnosticoAdmin, Pergunta, - BaseSchemaAdmin, Escolha, Anexo as AnexoDiagnostico, - AnexoAdmin as AnexoDiagnosticoAdmin) + PerguntaAdmin, Escolha, EscolhaAdmin, Anexo as AnexoDiagnostico, + AnexoAdmin as AnexoDiagnosticoAdmin, Categoria as + CategoriaDiagnostico) from sigi.apps.servidores.admin import (Servidor, ServidorAdmin, Funcao, FuncaoAdmin, Ferias, FeriasAdmin, Licenca, LicencaAdmin) from sigi.apps.ocorrencias.admin import (Ocorrencia, OcorrenciaAdmin, Anexo as AnexoOcorrencia, @@ -93,9 +94,10 @@ default.register(Mandato, MandatoAdmin) # sigi.apps.diagnosticos default.register(Diagnostico, DiagnosticoAdmin) -default.register(Pergunta, BaseSchemaAdmin) -default.register(Escolha) +default.register(Pergunta, PerguntaAdmin) +default.register(Escolha, EscolhaAdmin) default.register(AnexoDiagnostico, AnexoDiagnosticoAdmin) +default.register(CategoriaDiagnostico) # sigi.apps.servidores default.register(Servidor, ServidorAdmin) diff --git a/sigi/templates/admin/diagnosticos/diagnostico/change_form.html b/sigi/templates/admin/diagnosticos/diagnostico/change_form.html new file mode 100644 index 0000000..e806c30 --- /dev/null +++ b/sigi/templates/admin/diagnosticos/diagnostico/change_form.html @@ -0,0 +1,6 @@ +{% extends 'admin/change_form.html' %} + +{% block extrastyle %} + {{ block.super }} + +{% endblock %} diff --git a/sigi/templates/admin/servidores/servidor/change_form.html b/sigi/templates/admin/servidores/servidor/change_form.html new file mode 100644 index 0000000..3f05808 --- /dev/null +++ b/sigi/templates/admin/servidores/servidor/change_form.html @@ -0,0 +1,27 @@ +{% extends 'admin/change_form.html' %} + +{% block form_top %} +{% if adminform.form.instance.user %} +
+

Dados do servidor LDAP

+
+
+ +

{{adminform.form.instance.user.first_name}}

+
+
+
+
+ +

{{adminform.form.instance.user.last_name}}

+
+
+
+
+ +

{{adminform.form.instance.user.email}}

+
+
+
+{% endif %} +{% endblock %} diff --git a/sigi/templates/base_mobile.html b/sigi/templates/base_mobile.html new file mode 100644 index 0000000..225f945 --- /dev/null +++ b/sigi/templates/base_mobile.html @@ -0,0 +1,54 @@ + + + + + + {% block titulo %} + SIGI - Diagnósticos + {% endblock titulo %} + {% block media %} + + + + + + {% endblock media %} + + +
+
+ + {% block cabecalho %}{% endblock cabecalho %} +
+
+ {% block corpo %}{% endblock corpo %} +
+
+
+
    + {% block rodape %} +
  • Home
  • + {% endblock rodape %} +
+
+
+
+ + +
+
+

Ops! Não foi possivel salvar os dados.

+
+
+ Algum erro ocorreu ao salvar os dados do diagnóstico, + verifique a sua conectividade e/ou entre em contato + com a equipe técnica o mais rápido possível. +
+
+ + diff --git a/sigi/templates/diagnosticos/diagnosticos_categoria_casa_legislativa_form.html b/sigi/templates/diagnosticos/diagnosticos_categoria_casa_legislativa_form.html new file mode 100644 index 0000000..9dfe475 --- /dev/null +++ b/sigi/templates/diagnosticos/diagnosticos_categoria_casa_legislativa_form.html @@ -0,0 +1,49 @@ +{% extends "base_mobile.html" %} + +{% block media %} + {{ block.super }} + +{% endblock %} + +{% block cabecalho %} +

01. Identificação da Camara Municipal

+ Voltar +{% endblock cabecalho %} + +{% block corpo %} + {% if form %} +
+ +

Aguarde carregando perguntas para essa categoria...

+
+ + {% else %} +

Nenhuma existem perguntas para essa categoria.

+ {% endif %} +{% endblock corpo %} + +{% block rodape %} + +{% endblock rodape %} diff --git a/sigi/templates/diagnosticos/diagnosticos_categoria_contatos_form.html b/sigi/templates/diagnosticos/diagnosticos_categoria_contatos_form.html new file mode 100644 index 0000000..224b881 --- /dev/null +++ b/sigi/templates/diagnosticos/diagnosticos_categoria_contatos_form.html @@ -0,0 +1,52 @@ +{% extends "base_mobile.html" %} + +{% block media %} + {{ block.super }} + +{% endblock %} + +{% block cabecalho %} +

02. Identificação de Competências

+ Voltar +{% endblock cabecalho %} + +{% block corpo %} +
+ +

Aguarde carregando perguntas para essa categoria...

+
+ +{% endblock corpo %} + +{% block rodape %} + +{% endblock rodape %} diff --git a/sigi/templates/diagnosticos/diagnosticos_categorias_form.html b/sigi/templates/diagnosticos/diagnosticos_categorias_form.html new file mode 100644 index 0000000..6c2daed --- /dev/null +++ b/sigi/templates/diagnosticos/diagnosticos_categorias_form.html @@ -0,0 +1,43 @@ +{% extends "base_mobile.html" %} + +{% block media %} + {{ block.super }} + +{% endblock %} + +{% block cabecalho %} +

{{ categoria.nome }}

+ Voltar +{% endblock cabecalho %} + +{% block corpo %} + {% if form %} +
+ +

Aguarde carregando perguntas para essa categoria...

+
+ + {% else %} +

Nenhuma existem perguntas para essa categoria.

+ {% endif %} +{% endblock corpo %} +
    + {% block rodape %} + {{ block.super }} +
  • Listar
  • +
  • Sair
  • + {% endblock rodape %} +
+ + diff --git a/sigi/templates/diagnosticos/diagnosticos_categorias_list.html b/sigi/templates/diagnosticos/diagnosticos_categorias_list.html new file mode 100644 index 0000000..212c9f9 --- /dev/null +++ b/sigi/templates/diagnosticos/diagnosticos_categorias_list.html @@ -0,0 +1,63 @@ +{% extends "base_mobile.html" %} + +{% block cabecalho %} +

Categorias

+ Voltar +{% endblock cabecalho %} + +{% block media %} + {{ block.super }} + +{% endblock media %} + +{% block corpo %} + {% if categorias %} + + {% else %} +

Nenhuma categoria existente.

+ {% endif %} +{% endblock corpo %} +
    + {% block rodape %} + {{ block.super }} +
  • Sair
  • + {% endblock rodape %} +
diff --git a/sigi/templates/diagnosticos/diagnosticos_list.html b/sigi/templates/diagnosticos/diagnosticos_list.html new file mode 100644 index 0000000..8e5efde --- /dev/null +++ b/sigi/templates/diagnosticos/diagnosticos_list.html @@ -0,0 +1,26 @@ +{% extends "base_mobile.html" %} + +{% block cabecalho %} +

Diagnósticos

+ Sair +{% endblock cabecalho %} + +{% block corpo %} + {% if diagnosticos %} + + {% else %} +

Nenhum diagnóstico aberto.

+ {% endif %} +{% endblock corpo %} + +{% block rodape %}{% endblock rodape %} diff --git a/sigi/templates/diagnosticos/diagnosticos_login.html b/sigi/templates/diagnosticos/diagnosticos_login.html new file mode 100644 index 0000000..3514c44 --- /dev/null +++ b/sigi/templates/diagnosticos/diagnosticos_login.html @@ -0,0 +1,51 @@ + + + + + + SIGI - Login de Acesso + + + + + + +
+ Interlegis +
+ {% if form.errors %} +
+

Erro ao logar

+
    + {% for field in form %} + {% if field.errors %} +
  • {{ field.errors|striptags }}
  • + {% endif %} + {% endfor %} +
+

Verifique se seu login e senha foram preenchidos corretamente.

+
+ {% endif %} + +
+
+ {% csrf_token %} +
+ + +
+
+ + +
+ + +
+
+ + diff --git a/sigi/templates/diagnosticos/email_diagnostico_atualizado.txt b/sigi/templates/diagnosticos/email_diagnostico_atualizado.txt new file mode 100644 index 0000000..f917c67 --- /dev/null +++ b/sigi/templates/diagnosticos/email_diagnostico_atualizado.txt @@ -0,0 +1,8 @@ +Foi atualizado um diagnóstico no SIGI. Os dados do diagnóstico são: + +Criador do Diagnóstico: {{ servidor }} +Dados do Diagnóstico: {{ casa_legislativa }} +Data do Diagnóstico: {{ data_diagnostico }} +Data do Relatório do Diagnóstico: {{ data_relatorio_diagnostico }} + +O seu status está como {{ status }} diff --git a/sigi/templates/diagnosticos/email_diagnostico_publicado.txt b/sigi/templates/diagnosticos/email_diagnostico_publicado.txt new file mode 100644 index 0000000..00cb012 --- /dev/null +++ b/sigi/templates/diagnosticos/email_diagnostico_publicado.txt @@ -0,0 +1,10 @@ +Olá {{ responsavel }} + +Foi publicado um diagnóstico no SIGI. +Os dados do diagnóstico são: + +Dados do Diagnóstico: {{ casa_legislativa }} +Data do Diagnóstico: {{ data_diagnostico }} + +Para mais detalhes, acesse: +http://{{ host }}{{ url_diagnostico }} diff --git a/sigi/templates/mobile/404.html b/sigi/templates/mobile/404.html new file mode 100644 index 0000000..584add7 --- /dev/null +++ b/sigi/templates/mobile/404.html @@ -0,0 +1,15 @@ +{% extends "base_mobile.html" %} + +{% block cabecalho %} +

Ocorreu um erro

+{% endblock cabecalho %} +{% block corpo %} +

A página que está procurando não existe.

+

Verifique se o diagnóstico, categoria ou pergunta está cadastrado no sistema.

+ Voltar +{% endblock corpo %} + +{% block rodape %} + +{% endblock rodape %} diff --git a/sigi/urls.py b/sigi/urls.py index 9a07631..8ac039a 100644 --- a/sigi/urls.py +++ b/sigi/urls.py @@ -1,6 +1,7 @@ #-*- coding:utf-8 -*- from django.conf import settings -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, include, url +from django.views.generic.simple import redirect_to import sites # register admin filters @@ -9,67 +10,72 @@ import admin.filterspecs urlpatterns = patterns( '', + ('^$', redirect_to, {'url': '/sigi/'}), + + # Diagnosticos + (r'^sigi/mobile/diagnosticos/', include('sigi.apps.diagnosticos.urls')), + # Informacoes de uma casa legislativa - (r'^casas/casalegislativa/(?P\w+)/report_complete/', + (r'^sigi/casas/casalegislativa/(?P\w+)/report_complete/', 'sigi.apps.casas.views.report_complete'), - (r'^casas/casalegislativa/report_complete/', + (r'^sigi/casas/casalegislativa/report_complete/', 'sigi.apps.casas.views.report_complete'), # reports labels - (r'^casas/casalegislativa/labels/', + (r'^sigi/casas/casalegislativa/labels/', 'sigi.apps.casas.views.labels_report'), - (r'^casas/casalegislativa/(?P\w+)/labels/', + (r'^sigi/casas/casalegislativa/(?P\w+)/labels/', 'sigi.apps.casas.views.labels_report'), - # reports labels sem presidente - (r'^casas/casalegislativa/labels_sem_presidente/', + # reports labels sem presidente + (r'^sigi/casas/casalegislativa/labels_sem_presidente/', 'sigi.apps.casas.views.labels_report_sem_presidente'), - (r'^casas/casalegislativa/(?P\w+)/labels_sem_presidente/', + (r'^sigi/casas/casalegislativa/(?P\w+)/labels_sem_presidente/', 'sigi.apps.casas.views.labels_report_sem_presidente'), # reports casa - (r'^casas/casalegislativa/reports/', + (r'^sigi/casas/casalegislativa/reports/', 'sigi.apps.casas.views.report'), - (r'^casas/casalegislativa/casas_sem_convenio_report/', + (r'^sigi/casas/casalegislativa/casas_sem_convenio_report/', 'sigi.apps.casas.views.casas_sem_convenio_report'), # reports convenios - (r'^convenios/convenio/reports/', + (r'^sigi/convenios/convenio/reports/', 'sigi.apps.convenios.views.report'), - #Carrinho Casa - (r'^casas/casalegislativa/carrinho/deleta_itens_carrinho', + #Carrinho Casa + (r'^sigi/casas/casalegislativa/carrinho/deleta_itens_carrinho', 'sigi.apps.casas.views.deleta_itens_carrinho'), - (r'^casas/casalegislativa/carrinho/excluir_carrinho', + (r'^sigi/casas/casalegislativa/carrinho/excluir_carrinho', 'sigi.apps.casas.views.excluir_carrinho'), - (r'^casas/casalegislativa/carrinho/', + (r'^sigi/casas/casalegislativa/carrinho/', 'sigi.apps.casas.views.visualizar_carrinho'), - #Carrinho Convenio - (r'^convenios/convenio/carrinho/deleta_itens_carrinho', + #Carrinho Convenio + (r'^sigi/convenios/convenio/carrinho/deleta_itens_carrinho', 'sigi.apps.convenios.views.deleta_itens_carrinho'), - (r'^convenios/convenio/carrinho/excluir_carrinho', + (r'^sigi/convenios/convenio/carrinho/excluir_carrinho', 'sigi.apps.convenios.views.excluir_carrinho'), - (r'^convenios/convenio/carrinho/', + (r'^sigi/convenios/convenio/carrinho/', 'sigi.apps.convenios.views.visualizar_carrinho'), - #CSV Casa - (r'^casas/casalegislativa/csv/', - 'sigi.apps.casas.views.export_csv'), + #CSV Casa + (r'^sigi/casas/casalegislativa/csv/', + 'sigi.apps.casas.views.export_csv'), #CSV Convenio - (r'^convenios/convenio/csv/', + (r'^sigi/convenios/convenio/csv/', 'sigi.apps.convenios.views.export_csv'), - # Resumo por região PDF - (r'^reportsRegiao/(?P\w+)', + # Resumo por região PDF + (r'^sigi/reportsRegiao/(?P\w+)', 'sigi.apps.convenios.views.report_regiao'), - # Submenu com Birt reports - (r'^birt/menu/(?P\w+)', + # Submenu com Birt reports + (r'^sigi/birt/menu/(?P\w+)', 'sigi.apps.birt.views.menu'), - # Execução com Birt reports - (r'^birt/run/(?P.+)', + # Execução com Birt reports + (r'^sigi/birt/run/(?P.+)', 'sigi.apps.birt.views.run'), - # Mostrar um relatório em formato HTML - (r'^birt/showreport/', + # Mostrar um relatório em formato HTML + (r'^sigi/birt/showreport/', 'sigi.apps.birt.views.show'), - # Menu com Birt reports - (r'^birt/', + # Menu com Birt reports + (r'^sigi/birt/', 'sigi.apps.birt.views.menu'), - + # automatic interface based on admin - (r'^(.*)', sites.default.root), + (r'^sigi/(.*)', sites.default.root), ) if settings.DEBUG: