Browse Source

Nova APP de servicos para atender a demanda da SEIT, que deseja controlar os serviços de hospedagem que o Interlegis presta às Casas Legislativas.

stable/1.0
Claudio Morale 13 years ago
parent
commit
c88e2a55ba
  1. 10
      .pydevproject
  2. 168
      sigi/apps/servicos/admin.py
  3. 1
      sigi/apps/servicos/fixtures/initial_data.json
  4. 169
      sigi/apps/servicos/models.py
  5. 6
      sigi/sites.py
  6. 42
      sigi/templates/admin/servicos/casaatendida/change_form.html
  7. 26
      sigi/templates/admin/servicos/casaatendida/change_list.html
  8. 3
      sigi/urls.py

10
.pydevproject

@ -1,5 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?> <?eclipse-pydev version="1.0"?>
<pydev_project> <pydev_project>
@ -34,12 +35,13 @@
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/sigi</path> <path>/sigi</path>
</pydev_pathproperty> <path>/sigi/sigi</path>
</pydev_pathproperty>
</pydev_project> </pydev_project>

168
sigi/apps/servicos/admin.py

@ -1,30 +1,148 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.contrib import admin from django.contrib import admin
from django.contrib.contenttypes import generic from sigi.apps.servicos.models import Servico, LogServico, CasaAtendida, TipoServico
from sigi.apps.contatos.models import Contato #from sigi.apps.casas.models import Funcionario
from sigi.apps.servicos.models import Servico from sigi.apps.casas.admin import FuncionariosInline
from sigi.apps.servicos.models import DominioLeg from django.http import Http404, HttpResponseRedirect
from django.forms.models import ModelForm
class ContatosInline(generic.GenericTabularInline): from django.utils.encoding import force_unicode
model = Contato from django.utils.translation import ugettext as _
extra = 2 from django.core.urlresolvers import reverse
raw_id_fields = ('municipio',) from apps.casas.models import CasaLegislativa
verbose_name = 'colaborador Interlegis'
verbose_name_plural = 'colaboradores Interlegis' #---------------- inlines ---------------------
class LogServicoInline(admin.StackedInline):
model = LogServico
Fieldset = ((None, {'fields': (('data', 'descricao'), 'log')}))
extra = 1
# --------------- forms -----------------------
class ServicoFormAdmin(ModelForm):
class Meta:
model = Servico
def __init__(self, *args, **kwargs):
super(ServicoFormAdmin, self).__init__(*args, **kwargs)
self.fields['contato_tecnico'].choices = ()
self.fields['contato_administrativo'].choices = ()
if self.instance.casa_legislativa_id:
id_casa = self.instance.casa_legislativa_id
elif kwargs.has_key('initial') and kwargs['initial'].has_key('id_casa'):
id_casa = kwargs['initial']['id_casa']
self.instance.casa_legislativa_id = id_casa
else:
id_casa = None
if id_casa:
casa = CasaAtendida.objects.get(pk=id_casa)
contatos = [(f.id, unicode(f)) for f in casa.funcionario_set.all()]
self.fields['contato_tecnico'].choices = contatos
self.fields['contato_administrativo'].choices = contatos
#---------------- admins ----------------------
class TipoServicoAdmin(admin.ModelAdmin):
list_display = ('id', 'sigla', 'nome', )
ordering = ['id']
class ServicoAdmin(admin.ModelAdmin): class ServicoAdmin(admin.ModelAdmin):
date_hierarchy = 'data_inicio' form = ServicoFormAdmin
inlines = (ContatosInline,) list_display = ('casa_legislativa', 'tipo_servico', 'hospedagem_interlegis', 'data_ativacao', 'data_desativacao',)
list_display = ('id', 'titulo', 'tipo', 'convenio', 'situacao') fieldsets = (( None, {
list_filter = ('tipo','situacao', 'avaliacao') 'fields': ('casa_legislativa', 'data_ativacao',)
raw_id_fields = ('convenio',) }),
search_fields = ('titulo', 'tipo', 'descricao') ( 'Serviço', {
class DominiolegAdmin(admin.ModelAdmin): 'fields': ('tipo_servico', ('url', 'hospedagem_interlegis'), ('nome_servidor', 'porta_servico', 'senha_inicial'),)
model = DominioLeg }),
date_hierarchy = 'data_preenchimento' ( 'Contatos', {
list_display = ('id', 'dominio', 'contato_administrativo', 'contato_tecnico', 'data_preenchimento', 'data_recebimento', 'data_atendimento',) 'fields': ('contato_tecnico', 'contato_administrativo',)
search_fields = ('dominio',) }),
( 'Alterações', {
'fields': ('data_alteracao', 'data_desativacao', 'motivo_desativacao',)
}))
readonly_fields = ('casa_legislativa', 'data_ativacao', 'data_alteracao')
inlines = (LogServicoInline,)
def add_view(self, request, form_url='', extra_context=None):
id_casa = request.GET.get('id_casa', None)
if not id_casa:
raise Http404
return super(ServicoAdmin, self).add_view(request, form_url, extra_context=extra_context)
def response_add(self, request, obj):
opts = obj._meta
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
if request.POST.has_key("_addanother"):
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect(request.path + '?id_casa=%s' % (obj.casa_legislativa.id,))
elif request.POST.has_key("_save"):
self.message_user(request, msg)
return HttpResponseRedirect(reverse('admin:servicos_casaatendida_change', args=[obj.casa_legislativa.id]))
return super(ServicoAdmin, self).response_add(request, obj)
def response_change(self, request, obj):
opts = obj._meta
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj)}
if request.POST.has_key("_addanother"):
self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name)))
return HttpResponseRedirect("../add/?id_casa=%s" % (obj.casa_legislativa.id,))
elif request.POST.has_key("_save"):
self.message_user(request, msg)
return HttpResponseRedirect(reverse('admin:servicos_casaatendida_change', args=[obj.casa_legislativa.id]))
return super(ServicoAdmin, self).response_change(request, obj)
def save_form(self, request, form, change):
obj = super( ServicoAdmin, self).save_form(request, form, change)
if not change:
id_casa = request.GET.get('id_casa', None)
if not id_casa:
raise Http404
obj.casa_legislativa = CasaAtendida.objects.get(pk=id_casa)
return obj
class ContatosInline(FuncionariosInline):
can_delete = False # Equipe do SEIT não pode excluir pessoas de contato
class CasaAtendidaAdmin(admin.ModelAdmin):
actions = None
list_display = ('codigo_interlegis', 'nome', 'servicos',)
ordering = ['nome']
fieldsets = (
('Casa legislativa', {
'fields': (('codigo_interlegis', 'nome'), ('logradouro', 'bairro', 'municipio', 'cep'), ('email', 'pagina_web'))
})
,)
readonly_fields = ('nome', 'logradouro', 'bairro', 'municipio', 'cep')
inlines = (ContatosInline,)
list_filter = ('tipo', 'municipio')
search_fields = ('search_text','cnpj', 'bairro', 'logradouro',
'cep', 'municipio__nome', 'municipio__uf__nome',
'municipio__codigo_ibge', 'pagina_web', 'observacoes')
def change_view(self, request, object_id, extra_context=None):
# Se a Casa ainda não é atendida, gerar o código interlegis para ela
# Assim ela passa a ser uma casa atendida
casa = CasaLegislativa.objects.get(id=object_id)
if casa.codigo_interlegis == '':
casa.gerarCodigoInterlegis()
return super(CasaAtendidaAdmin, self).change_view(request, object_id, extra_context=extra_context)
def has_add_permission(self, request):
return False # Nunca é permitido inserir uma nova Casa Legislativa por aqui
admin.site.register(DominioLeg, DominiolegAdmin) def has_delete_permission(self, request, obj=None):
admin.site.register(Servico, ServicoAdmin) return False # Nunca deletar casas por aqui

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

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

169
sigi/apps/servicos/models.py

@ -1,78 +1,117 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.db import models from django.db import models
from django.contrib.contenttypes import generic from sigi.apps.casas.models import CasaLegislativa, Funcionario
from sigi.apps.casas.models import CasaLegislativa
from datetime import date from datetime import date
from django.core.mail import send_mail
from sigi.settings import DEFAULT_FROM_EMAIL
class Servico(models.Model): class TipoServico(models.Model):
SITUACAO_CHOICES = ( email_help = '''Use:<br/>
('P', 'Pendente'), {url} para incluir a URL do serviço,<br/>
('A', 'Em andamento'), {senha} para incluir a senha inicial do serviço'''
('E', 'Executado'), nome = models.CharField('Nome', max_length=60)
('D', 'Demanda'), sigla = models.CharField('Sigla', max_length='12')
('C', 'Cancelado'), template_email_ativa = models.TextField('Template de email de ativação', help_text = email_help, blank=True)
) template_email_altera = models.TextField('Template de email de alteração', help_text = email_help, blank=True)
AVALIACAO_CHOICES = ( template_email_desativa = models.TextField('Template de email de desativação', help_text = email_help + '<br/>{motivo} para incluir o motivo da desativação do serviço', blank=True)
(4, 'Ótimo'),
(3, 'Bom'),
(2, 'Regular'),
(1, 'Ruim'),
)
titulo = models.CharField('título', max_length=60)
tipo = models.CharField(max_length=30)
descricao = models.TextField(u'descrição')
convenio = models.ForeignKey('convenios.Convenio', verbose_name='Convênio')
colaboradores = generic.GenericRelation('contatos.Contato')
data_inicio = models.DateField(
u'início',
blank=True,
null=True,
help_text = 'Início da realização do serviço.',
)
data_fim = models.DateField(
'fim',
blank=True,
null=True,
help_text = 'Fim da realização do serviço.',
)
situacao = models.CharField(
u'situação',
max_length=1,
choices=SITUACAO_CHOICES
)
avaliacao = models.PositiveSmallIntegerField(
u'avaliação',
choices=AVALIACAO_CHOICES,
blank=True,
null=True,
help_text='Avaliação que o serviço obteve, quando aplicável.'
)
class Meta: class Meta:
verbose_name = 'serviço' verbose_name = 'Tipo de serviço'
verbose_name_plural = 'serviços' verbose_name_plural = 'Tipos de serviço'
def __unicode__(self): def __unicode__(self):
return str(self.titulo) return self.nome;
class DominioLeg(models.Model): class Servico(models.Model):
casa_legislativa = models.OneToOneField(CasaLegislativa) casa_legislativa = models.ForeignKey(CasaLegislativa, verbose_name='Casa legislativa')
dominio = models.URLField('Domínio', verify_exists=False) tipo_servico = models.ForeignKey(TipoServico, verbose_name='Tipo de serviço')
contato_administrativo = models.CharField('Contato administrativo', max_length=60) contato_tecnico = models.ForeignKey(Funcionario, verbose_name='Contato técnico', related_name='contato_tecnico')
telefone_administrativo = models.CharField('Telefone administrativo', max_length=10, help_text='Somente números: ddaaaannnn.') contato_administrativo = models.ForeignKey(Funcionario, verbose_name='Contato administrativo', related_name='contato_administrativo')
email_administrativo = models.EmailField('e-mail') url = models.URLField('URL do serviço', verify_exists=False, blank=True)
contato_tecnico = models.CharField('Contato técnico', max_length=60) hospedagem_interlegis = models.BooleanField('Hospedagem no Interlegis?')
telefone_tecnico = models.CharField('Telefone administrativo', max_length=10, help_text='Somente números: ddaaaannnn.') nome_servidor = models.CharField('Hospedado em', max_length=60, blank=True, help_text='Se hospedado no Interlegis, informe o nome do servidor.<br/>Senão, informe o nome do provedor de serviços.')
email_tecnico = models.EmailField('e-mail') porta_servico = models.PositiveSmallIntegerField('Porta de serviço (instância)', blank=True, null=True)
data_preenchimento = models.DateField('Data de preenchimento', default=date.today) senha_inicial = models.CharField('Senha inicial', max_length=33, blank=True)
data_recebimento = models.DateField('Data de recebimento', null=True, blank=True) data_ativacao = models.DateField('Data de ativação', default=date.today)
data_atendimento = models.DateField('Data de atendimento', null=True, blank=True) data_alteracao = models.DateField('Data da última alteração', blank=True, null=True, auto_now=True)
data_desativacao = models.DateField('Data de desativação', blank=True, null=True)
motivo_desativacao = models.TextField('Motivo da desativação', blank=True)
class Meta: def __unicode__(self):
verbose_name = 'Registro de domínio .leg.br' return "%s (%s)" % (self.tipo_servico.nome, 'ativo' if self.data_desativacao is None else 'Desativado')
verbose_name_plural = 'Registros de domínios .leg.br'
def save(self, *args, **kwargs):
# Reter o objeto original para verificar mudanças
if self.id is not None:
original = Servico.objects.get(id=self.id)
if self.id is None:
# Novo serviço, email de ativação
subject = 'INTERLEGIS - Ativação de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_ativa
elif self.data_desativacao is not None and original.data_desativacao is None:
# Serviço foi desativado. Email de desativação
subject = 'INTERLEGIS - Desativação de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_desativa
elif (self.tipo_servico != original.tipo_servico or
self.contato_tecnico != original.contato_tecnico or
self.url != original.url or
self.nome_servidor != original.nome_servidor or
self.senha_inicial != original.senha_inicial):
# Serviço foi alterado
subject = 'INTERLEGIS - Alteração de serviço %s' % (self.tipo_servico.nome,)
body = self.tipo_servico.template_email_altera
else:
# Salvar o Servico
super(Servico, self).save(*args, **kwargs)
return # sem enviar email
# Prepara e envia o email
body = body.replace('{url}', self.url) \
.replace('{senha}', self.senha_inicial) \
.replace('{motivo}', self.motivo_desativacao)
# send_mail(subject, body, DEFAULT_FROM_EMAIL, \
# (self.contato_tecnico.email,), fail_silently=False)
# Salvar o Servico
super(Servico, self).save(*args, **kwargs)
return
class LogServico(models.Model):
servico = models.ForeignKey(Servico, verbose_name='Serviço')
descricao = models.CharField('Breve descrição da ação', max_length=60)
data = models.DateField('Data da ação', default=date.today)
log = models.TextField('Log da ação')
def __unicode__(self): def __unicode__(self):
return str(self.dominio) return "%s (%s)" % (self.descricao, self.data)
class Meta:
verbose_name = 'Log do serviço'
verbose_name_plural = 'Logs do serviço'
class CasaAtendidaManager(models.Manager):
def get_query_set(self):
qs = super(CasaAtendidaManager, self).get_query_set()
qs = qs.exclude(codigo_interlegis='')
return qs
class CasaAtendida(CasaLegislativa):
class Meta:
proxy = True
verbose_name_plural = 'Casas atendidas'
objects = CasaAtendidaManager()
@property
def servicos(self):
qs = Servico.objects.filter(casa_legislativa=self.id)
result = []
for servico in qs:
result.append(unicode(servico))
return ", ".join(result)

6
sigi/sites.py

@ -14,7 +14,8 @@ from sigi.apps.inventario.admin import (Fornecedor, FornecedorAdmin, Fabricante,
EquipamentoAdmin, TipoEquipamento, EquipamentoAdmin, TipoEquipamento,
TipoEquipamentoAdmin, ModeloEquipamento, TipoEquipamentoAdmin, ModeloEquipamento,
ModeloEquipamentoAdmin, Bem, BemAdmin) ModeloEquipamentoAdmin, Bem, BemAdmin)
from sigi.apps.servicos.admin import Servico, ServicoAdmin, DominioLeg, DominiolegAdmin from sigi.apps.servicos.admin import (TipoServico, TipoServicoAdmin, CasaAtendida,
CasaAtendidaAdmin, Servico, ServicoAdmin)
from sigi.apps.mesas.admin import (Legislatura, LegislaturaAdmin, Coligacao, from sigi.apps.mesas.admin import (Legislatura, LegislaturaAdmin, Coligacao,
ColigacaoAdmin, ComposicaoColigacao, ColigacaoAdmin, ComposicaoColigacao,
ComposicaoColigacaoAdmin, SessaoLegislativa, ComposicaoColigacaoAdmin, SessaoLegislativa,
@ -75,8 +76,9 @@ default.register(Equipamento, EquipamentoAdmin)
default.register(Bem, BemAdmin) default.register(Bem, BemAdmin)
# sigi.apps.servicos # sigi.apps.servicos
default.register(TipoServico, TipoServicoAdmin)
default.register(Servico, ServicoAdmin) default.register(Servico, ServicoAdmin)
default.register(DominioLeg, DominiolegAdmin) default.register(CasaAtendida, CasaAtendidaAdmin)
# sigi.apps.mesas # sigi.apps.mesas
default.register(Legislatura, LegislaturaAdmin) default.register(Legislatura, LegislaturaAdmin)

42
sigi/templates/admin/servicos/casaatendida/change_form.html

@ -0,0 +1,42 @@
{% extends "admin/change_form.html" %}
{% load i18n admin_modify adminmedia %}
{% block after_related_objects %}
{{ block.super }}
<div id="servico_list-group" class="inline-group">
<div class="tabular inline-related last-related">
<fieldset class="module">
<h2>Servicos</h2>
<table>
<thead>
<tr>
<th colspan="2">Tipo de serviço</th>
<th>Hospedagem no Interlegis?</th>
<th>Data de ativação</th>
<th>Data da última alteração</th>
<th>Data de desativação</th>
</tr>
</thead>
<tbody>
{% for srv in original.servico_set.all %}
<tr>
<td><p><a href="{% url admin:servicos_servico_change srv.id %}">{{ srv.tipo_servico.sigla }}</a></p></td>
<td>{{ srv.tipo_servico }}</td>
<td><img alt="{{ srv.hospedagem_interlegis }}" src="{% admin_media_prefix %}img/admin/icon-{{ srv.hospedagem_interlegis|yesno:'yes,no' }}.gif"></td>
<td>{{ srv.data_ativacao|date:'SHORT_DATE_FORMAT' }}</td>
<td>{{ srv.data_alteracao|date:'SHORT_DATE_FORMAT' }}</td>
<td>{{ srv.data_desativacao|date:'SHORT_DATE_FORMAT' }}</td>
</tr>
{% empty %}
<tr> <td colspan="6">Nenhum serviço cadastrado para esta Casa Legislativa</td> </tr>
{% endfor %}
<tr class="add-row">
<td colspan="6"><a href="{% url admin:servicos_servico_add %}?id_casa={{ original.id }}">Adicionar outro Servico</a></td>
</tr>
</tbody>
</table>
</fieldset>
</div>
</div>
{% endblock %}

26
sigi/templates/admin/servicos/casaatendida/change_list.html

@ -0,0 +1,26 @@
{% extends "admin/change_list.html" %}
{% load adminmedia admin_list i18n %}
{% block extrahead %}
{{ block.super }}
<script type="text/javascript">
function dismissRelatedLookupPopup(win, chosenId) {
win.close();
url = '{% url admin:servicos_casaatendida_changelist %}' + chosenId;
// alert(url);
document.location.href = url;
}
</script>
{% endblock %}
{% block object-tools %}
<ul class="object-tools">
<li>
<a id="lookup_id_casa_legislativa" onclick="return showRelatedObjectLookupPopup(this);" href="{% url admin:casas_casalegislativa_changelist %}?t=id&codigo_interlegis__exact=" class="addlink">
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
</a>
</li>
</ul>
<input type="hidden" id="id_casa_legislativa" value="nenhum" onchange="alert('Eu mudei')"/>
{% endblock %}

3
sigi/urls.py

@ -87,7 +87,8 @@ urlpatterns = patterns(
(r'^sigi/api/diagnosticos/$', (r'^sigi/api/diagnosticos/$',
'sigi.apps.diagnosticos.views.grafico_api'), 'sigi.apps.diagnosticos.views.grafico_api'),
# automatic interface based on admin # automatic interface based on admin
(r'^sigi/(.*)', sites.default.root), #(r'^sigi/(.*)', sites.default.root),
(r'^sigi/', include(sites.default.urls)),
) )
if settings.DEBUG: if settings.DEBUG:

Loading…
Cancel
Save