From 5546baa76e548701245c2e7b0088d146f49604af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ses=C3=B3stris=20Vieira?= Date: Wed, 17 Nov 2021 16:09:35 -0300 Subject: [PATCH 1/3] Fix #106 --- sigi/apps/eventos/admin.py | 14 +++- sigi/apps/eventos/migrations/0010_modulo.py | 37 +++++++++ .../migrations/0011_auto_20211117_0633.py | 24 ++++++ .../migrations/0012_auto_20211117_0657.py | 28 +++++++ sigi/apps/eventos/models.py | 77 ++++++++++++++++++- 5 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 sigi/apps/eventos/migrations/0010_modulo.py create mode 100644 sigi/apps/eventos/migrations/0011_auto_20211117_0633.py create mode 100644 sigi/apps/eventos/migrations/0012_auto_20211117_0657.py diff --git a/sigi/apps/eventos/admin.py b/sigi/apps/eventos/admin.py index 271c713..63ded3e 100644 --- a/sigi/apps/eventos/admin.py +++ b/sigi/apps/eventos/admin.py @@ -20,9 +20,10 @@ from django import forms from django.contrib import admin +from django.db import models from django.http import HttpResponseRedirect from django.utils.translation import ugettext as _ -from sigi.apps.eventos.models import TipoEvento, Funcao, Evento, Equipe, Convite +from sigi.apps.eventos.models import Modulo, TipoEvento, Funcao, Evento, Equipe, Convite from sigi.apps.eventos.views import adicionar_eventos_carrinho class EventoAdminForm(forms.ModelForm): @@ -31,7 +32,8 @@ class EventoAdminForm(forms.ModelForm): fields = ('tipo_evento', 'nome', 'descricao', 'virtual', 'solicitante', 'data_inicio', 'data_termino', 'carga_horaria', 'casa_anfitria', 'municipio', 'local', 'publico_alvo', - 'status', 'data_cancelamento', 'motivo_cancelamento', ) + 'total_participantes', 'status', 'data_cancelamento', + 'motivo_cancelamento', ) def clean(self): cleaned_data = super(EventoAdminForm, self).clean() @@ -60,18 +62,22 @@ class ConviteInline(admin.TabularInline): model = Convite raw_id_fields = ('casa',) +class ModuloInline(admin.TabularInline): + model = Modulo + @admin.register(Evento) class EventoAdmin(admin.ModelAdmin): form = EventoAdminForm date_hierarchy = 'data_inicio' list_display = ('nome', 'tipo_evento', 'status', 'data_inicio', - 'data_termino', 'municipio', 'solicitante') + 'data_termino', 'municipio', 'solicitante', + 'total_participantes',) list_filter = ('status', 'tipo_evento', 'tipo_evento__categoria', 'virtual', 'municipio__uf', 'solicitante') raw_id_fields = ('casa_anfitria', 'municipio',) search_fields = ('nome', 'tipo_evento__nome', 'casa_anfitria__search_text', 'municipio__search_text', 'solicitante') - inlines = (EquipeInline, ConviteInline) + inlines = (EquipeInline, ConviteInline, ModuloInline) actions = ['adicionar_eventos', ] def adicionar_eventos(self, request, queryset): diff --git a/sigi/apps/eventos/migrations/0010_modulo.py b/sigi/apps/eventos/migrations/0010_modulo.py new file mode 100644 index 0000000..a03ce5a --- /dev/null +++ b/sigi/apps/eventos/migrations/0010_modulo.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('servidores', '0007_auto_20210430_0735'), + ('eventos', '0009_tipoevento_categoria'), + ] + + operations = [ + migrations.CreateModel( + name='Modulo', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('nome', models.CharField(max_length=100, verbose_name='Nome')), + ('descricao', models.TextField(verbose_name='Descri\xe7\xe3o do m\xf3dulo')), + ('tipo', models.CharField(max_length=1, verbose_name='Tipo', choices=[(b'A', 'Aula'), (b'P', 'Palestra'), (b'R', 'Apresenta\xe7\xe3o')])), + ('inicio', models.DateTimeField(null=True, verbose_name='Data/hora de in\xedcio', blank=True)), + ('termino', models.DateTimeField(null=True, verbose_name='Data/hora de t\xe9rmino', blank=True)), + ('carga_horaria', models.PositiveIntegerField(default=0, verbose_name='carga hor\xe1ria')), + ('qtde_participantes', models.PositiveIntegerField(default=0, help_text='Deixar Zero significa que todos os participantes do evento participaram do m\xf3dulo', verbose_name='n\xfamero de participantes')), + ('apresentador', models.ForeignKey(related_name='modulo_apresentador', on_delete=django.db.models.deletion.PROTECT, verbose_name='Apresentador', blank=True, to='servidores.Servidor', null=True)), + ('evento', models.ForeignKey(verbose_name='Evento', to='eventos.Evento')), + ('monitor', models.ForeignKey(related_name='modulo_monitor', on_delete=django.db.models.deletion.PROTECT, blank=True, to='servidores.Servidor', help_text='Monitor, mediador, auxiliar, etc.', null=True, verbose_name='Monitor')), + ], + options={ + 'verbose_name': 'M\xf3dulo do evento', + 'verbose_name_plural': 'M\xf3dulos do evento', + }, + bases=(models.Model,), + ), + ] diff --git a/sigi/apps/eventos/migrations/0011_auto_20211117_0633.py b/sigi/apps/eventos/migrations/0011_auto_20211117_0633.py new file mode 100644 index 0000000..4b09869 --- /dev/null +++ b/sigi/apps/eventos/migrations/0011_auto_20211117_0633.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('eventos', '0010_modulo'), + ] + + operations = [ + migrations.AlterModelOptions( + name='modulo', + options={'ordering': ('inicio',), 'verbose_name': 'M\xf3dulo do evento', 'verbose_name_plural': 'M\xf3dulos do evento'}, + ), + migrations.AddField( + model_name='evento', + name='total_participantes', + field=models.PositiveIntegerField(default=0, help_text='Se informar quantidade de participantes na aba de convites, este campo ser\xe1 ajustado com a somat\xf3ria dos participantes naquela aba.', verbose_name='Total de participantes'), + preserve_default=True, + ), + ] diff --git a/sigi/apps/eventos/migrations/0012_auto_20211117_0657.py b/sigi/apps/eventos/migrations/0012_auto_20211117_0657.py new file mode 100644 index 0000000..662c4d1 --- /dev/null +++ b/sigi/apps/eventos/migrations/0012_auto_20211117_0657.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.db.models import Sum + +def atualiza_participantes(apps, schema_editor): + if schema_editor.connection.alias != 'default': + return + + Evento = apps.get_model('eventos', 'Evento') + + for e in Evento.objects.all(): + total = e.convite_set.aggregate(total=Sum('qtde_participantes')) + total = total['total'] + if (total is not None) or (total > 0): + e.total_participantes = total + e.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('eventos', '0011_auto_20211117_0633'), + ] + + operations = [ + migrations.RunPython(atualiza_participantes), + ] diff --git a/sigi/apps/eventos/models.py b/sigi/apps/eventos/models.py index 2eb1eed..f9acacd 100644 --- a/sigi/apps/eventos/models.py +++ b/sigi/apps/eventos/models.py @@ -2,6 +2,7 @@ from datetime import datetime import random from django.db import models +from django.db.models import Sum from django.utils.functional import lazy from django.utils.translation import ugettext as _ from django.contrib.contenttypes import generic @@ -76,6 +77,13 @@ class Evento(models.Model): ) local = models.TextField(_(u"Local do evento"), blank=True) publico_alvo = models.TextField(_(u"Público alvo"), blank=True) + total_participantes = models.PositiveIntegerField( + _(u"Total de participantes"), + default=0, + help_text=_(u"Se informar quantidade de participantes na aba de " + u"convites, este campo será ajustado com a somatória " + u"dos participantes naquela aba.") + ) status = models.CharField(_(u"Status"), max_length=1, choices=STATUS_CHOICES) data_cancelamento = models.DateField(_(u"Data de cancelamento"), blank=True, null=True) motivo_cancelamento = models.TextField(_(u"Motivo do cancelamento"), blank=True) @@ -96,7 +104,12 @@ class Evento(models.Model): self.data_cancelamento = None self.motivo_cancelamento = "" if self.data_inicio > self.data_termino: - raise ValidationError(_(u"Data de término deve ser posterior à data de início")) + raise ValidationError(_(u"Data de término deve ser posterior à " + u"data de início")) + total = self.convite_set.aggregate(total=Sum('qtde_participantes')) + total = total['total'] + if (total is not None) or (total > 0): + self.total_participantes = total return super(Evento, self).save(*args, **kwargs) class Funcao(models.Model): @@ -165,4 +178,64 @@ class Convite(models.Model): class Meta: ordering = ('evento', 'casa', '-data_convite') unique_together = ('evento', 'casa') - verbose_name, verbose_name_plural = _(u"Casa convidada"), _(u"Casas convidadas") \ No newline at end of file + verbose_name = _(u"Casa convidada") + verbose_name_plural = _(u"Casas convidadas") + +class Modulo(models.Model): + TIPO_CHOICES = ( + ('A', _(u'Aula')), + ('P', _(u'Palestra')), + ('R', _(u'Apresentação')), + ) + evento = models.ForeignKey(Evento, verbose_name=_(u"Evento")) + nome = models.CharField(_(u"Nome"), max_length=100) + descricao = models.TextField(_(u"Descrição do módulo")) + tipo = models.CharField(_(u'Tipo'), max_length=1, choices=TIPO_CHOICES) + inicio = models.DateTimeField( + _(u"Data/hora de início"), + null=True, + blank=True + ) + termino = models.DateTimeField( + _(u"Data/hora de término"), + null=True, + blank=True + ) + carga_horaria = models.PositiveIntegerField( + _(u"carga horária"), + default=0 + ) + apresentador = models.ForeignKey( + Servidor, + on_delete=models.PROTECT, + related_name="modulo_apresentador", + null=True, + blank=True, + verbose_name=_(u"Apresentador"), + ) + monitor = models.ForeignKey( + Servidor, + on_delete=models.PROTECT, + related_name="modulo_monitor", + null=True, + blank=True, + verbose_name=_(u"Monitor"), + help_text=_(u"Monitor, mediador, auxiliar, etc.") + ) + qtde_participantes = models.PositiveIntegerField( + _(u"número de participantes"), + default=0, + help_text=_(u"Deixar Zero significa que todos os participantes " + u"do evento participaram do módulo"), + ) + + class Meta: + ordering = ('inicio',) + verbose_name = _(u"Módulo do evento") + verbose_name_plural = _(u"Módulos do evento") + + def __unicode__(self): + return _(u"{nome} ({tipo})").format( + nome=self.nome, + tipo=self.get_tipo_display() + ) From fb15e1f9a34b8199cf7d8e73456339ffed7fb0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ses=C3=B3stris=20Vieira?= Date: Wed, 17 Nov 2021 17:54:17 -0300 Subject: [PATCH 2/3] Fix #112 --- sigi/apps/servicos/admin.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sigi/apps/servicos/admin.py b/sigi/apps/servicos/admin.py index 75cd0c3..5d38565 100644 --- a/sigi/apps/servicos/admin.py +++ b/sigi/apps/servicos/admin.py @@ -90,10 +90,25 @@ class DataUtimoUsoFilter(admin.SimpleListFilter): timedelta(days=0) ) queryset = queryset.filter(data_ultimo_uso__range=(de, ate)) - print (de, ate, queryset.count()) - return queryset +class ServicoAtivoFilter(admin.SimpleListFilter): + title = _(u"Serviço ativo") + parameter_name = 'ativo' + + def lookups(self, request, model_admin): + return ( + ('ativo', _(u"Ativo")), + ('desativado', _(u"Desativado")), + ) + + def queryset(self, request, queryset): + if self.value() is not None: + if self.value() == 'ativo': + queryset = queryset.filter(data_desativacao__isnull=True) + else: + queryset = queryset.filter(data_desativacao__isnull=False) + return queryset class ServicoAdmin(BaseModelAdmin): form = ServicoFormAdmin @@ -116,6 +131,7 @@ class ServicoAdmin(BaseModelAdmin): list_filter = ( 'tipo_servico', 'hospedagem_interlegis', + ServicoAtivoFilter, DataUtimoUsoFilter, ('casa_legislativa__gerentes_interlegis', GerentesInterlegisFilter), 'casa_legislativa__municipio__uf', From 5a81b896848311eb930d40dafa78efbd3c05e1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ses=C3=B3stris=20Vieira?= Date: Wed, 17 Nov 2021 21:12:14 -0300 Subject: [PATCH 3/3] Fix #110 --- sigi/apps/eventos/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sigi/apps/eventos/views.py b/sigi/apps/eventos/views.py index 464d392..dc530e5 100644 --- a/sigi/apps/eventos/views.py +++ b/sigi/apps/eventos/views.py @@ -62,17 +62,17 @@ def calendario(request): for evento in Evento.objects.filter(data_inicio__year=ano_pesquisa, data_inicio__month=mes_pesquisa).order_by('data_inicio'): - start = dates.index(evento.data_inicio) - if not evento.data_termino in dates: + start = dates.index(evento.data_inicio.date()) + if not evento.data_termino.date() in dates: lastday = dates[-1] - while lastday < evento.data_termino: + while lastday < evento.data_termino.date(): lastday = lastday + datetime.timedelta(days=1) dates.append(lastday) eventos.append({'evento': evento, 'start': start}) # Calcula a distância dos eventos para as bordas do calendário for evento in eventos: - end = dates.index(evento['evento'].data_termino) + end = dates.index(evento['evento'].data_termino.date()) evento['duration'] = end-evento['start']+1 evento['close'] = len(dates)-end-1