forked from DGNum/gestioCOF
Merge branch 'master' of git.eleves.ens.fr:cof-geek/gestioCOF into qwann/zolicss
This commit is contained in:
commit
29a125f4e4
9 changed files with 213 additions and 5 deletions
21
bda/admin.py
21
bda/admin.py
|
@ -20,10 +20,25 @@ class ChoixSpectacleInline(admin.TabularInline):
|
|||
|
||||
class AttributionInline(admin.TabularInline):
|
||||
model = Attribution
|
||||
extra = 0
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(AttributionInline, self).get_queryset(request)
|
||||
return qs.filter(spectacle__listing=False)
|
||||
|
||||
|
||||
class AttributionInlineListing(admin.TabularInline):
|
||||
model = Attribution
|
||||
exclude = ('given', )
|
||||
extra = 0
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(AttributionInlineListing, self).get_queryset(request)
|
||||
return qs.filter(spectacle__listing=True)
|
||||
|
||||
|
||||
class ParticipantAdmin(admin.ModelAdmin):
|
||||
inlines = [AttributionInline]
|
||||
inlines = [AttributionInline, AttributionInlineListing]
|
||||
|
||||
def get_queryset(self, request):
|
||||
return Participant.objects.annotate(nb_places=Count('attributions'),
|
||||
|
@ -164,9 +179,11 @@ class ChoixSpectacleAdmin(admin.ModelAdmin):
|
|||
|
||||
class SpectacleAdmin(admin.ModelAdmin):
|
||||
model = Spectacle
|
||||
list_display = ("title", "date", "tirage", "location", "slots", "price")
|
||||
list_display = ("title", "date", "tirage", "location", "slots", "price",
|
||||
"listing")
|
||||
list_filter = ("location", "tirage",)
|
||||
search_fields = ("title", "location__name")
|
||||
readonly_fields = ("rappel_sent", )
|
||||
|
||||
|
||||
class TirageAdmin(admin.ModelAdmin):
|
||||
|
|
25
bda/migrations/0004_mails-rappel.py
Normal file
25
bda/migrations/0004_mails-rappel.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bda', '0003_update_tirage_and_spectacle'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='spectacle',
|
||||
name='listing',
|
||||
field=models.BooleanField(default=False, verbose_name=b'Les places sont sur listing'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='spectacle',
|
||||
name='rappel_sent',
|
||||
field=models.DateTimeField(null=True, verbose_name=b'Mail de rappel envoy\xc3\xa9', blank=True),
|
||||
),
|
||||
]
|
|
@ -4,7 +4,16 @@ import calendar
|
|||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.template import loader, Context
|
||||
from django.core import mail
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def render_template(template_name, data):
|
||||
tmpl = loader.get_template(template_name)
|
||||
ctxt = Context(data)
|
||||
return tmpl.render(ctxt)
|
||||
|
||||
|
||||
class Tirage(models.Model):
|
||||
|
@ -39,6 +48,9 @@ class Spectacle(models.Model):
|
|||
slots = models.IntegerField("Places")
|
||||
priority = models.IntegerField("Priorité", default=1000)
|
||||
tirage = models.ForeignKey(Tirage)
|
||||
listing = models.BooleanField("Les places sont sur listing")
|
||||
rappel_sent = models.DateTimeField("Mail de rappel envoyé", blank=True,
|
||||
null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Spectacle"
|
||||
|
@ -57,6 +69,38 @@ class Spectacle(models.Model):
|
|||
return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(),
|
||||
self.location, self.price)
|
||||
|
||||
def send_rappel(self):
|
||||
# On récupère la liste des participants
|
||||
members = {}
|
||||
for attr in Attribution.objects.filter(spectacle=self).all():
|
||||
member = attr.participant.user
|
||||
if member.id in members:
|
||||
members[member.id].nb_attr = 2
|
||||
else:
|
||||
member.nb_attr = 1
|
||||
members[member.id] = member
|
||||
# On écrit un mail personnalisé à chaque participant
|
||||
mails_to_send = []
|
||||
mail_object = "%s - %s - %s" % (self.title, self.date_no_seconds(),
|
||||
self.location)
|
||||
for member in members.values():
|
||||
mail_body = render_template('mail-rappel.txt', {
|
||||
'member': member,
|
||||
'show': self})
|
||||
mail_tot = mail.EmailMessage(
|
||||
mail_object, mail_body,
|
||||
settings.RAPPEL_FROM, [member.email],
|
||||
[], headers={'Reply-To': settings.RAPPEL_REPLY_TO})
|
||||
mails_to_send.append(mail_tot)
|
||||
# On envoie les mails
|
||||
connection = mail.get_connection()
|
||||
connection.send_messages(mails_to_send)
|
||||
# On enregistre le fait que l'envoi a bien eu lieu
|
||||
self.rappel_sent = timezone.now()
|
||||
self.save()
|
||||
# On renvoie la liste des destinataires
|
||||
return members.values()
|
||||
|
||||
PAYMENT_TYPES = (
|
||||
("cash", u"Cash"),
|
||||
("cb", "CB"),
|
||||
|
|
23
bda/templates/mail-rappel.txt
Normal file
23
bda/templates/mail-rappel.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
Bonjour {{ member.get_full_name }},
|
||||
|
||||
Nous te rappellons que tu as eu la chance d'obtenir {{ member.nb_attr|pluralize:"une place,deux places" }}
|
||||
pour {{ show.title }}, le {{ show.date_no_seconds }} au {{ show.location }}. N'oublie pas de t'y rendre !
|
||||
{% if member.nb_attr == 2 %}
|
||||
Tu as obtenu deux places pour ce spectacle. Nous te rappelons que
|
||||
ces places sont strictement réservées aux personnes de moins de 28 ans.
|
||||
{% endif %}
|
||||
{% if show.listing %}Pour ce spectacle, tu as reçu des places sur
|
||||
listing. Il te faudra donc te rendre 15 minutes en avance sur les lieux de la représentation
|
||||
pour retirer {{ member.nb_attr|pluralize:"ta place,tes places" }}.
|
||||
{% else %}Pour assister à ce spectacle, tu dois présenter les billets qui ont
|
||||
été distribués au burô.
|
||||
{% endif %}
|
||||
|
||||
Si tu ne peux plus assister à cette représentation, tu peux
|
||||
revendre ta place via BdA-revente, accessible directement sur
|
||||
GestioCOF (lien "revendre une place du premier tirage" sur la page
|
||||
d'accueil https://www.cof.ens.fr/gestion/).
|
||||
|
||||
En te souhaitant un excellent spectacle,
|
||||
|
||||
Le Bureau des Arts
|
35
bda/templates/mails-rappel.html
Normal file
35
bda/templates/mails-rappel.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
{% extends "base_title.html" %}
|
||||
|
||||
{% block realcontent %}
|
||||
{% if sent %}
|
||||
<h3>Les mails de rappel pour le spectacle {{ show.title }} ont bien été envoyés aux personnes suivantes</h3>
|
||||
<ul>
|
||||
{% for member in members %}
|
||||
<li>{{ member.get_full_name }} ({{ member.email }})</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<h3>Voulez vous envoyer les mails de rappel pour le spectacle
|
||||
{{ show.title }} ?</h3>
|
||||
{% if show.rappel_sent %}
|
||||
<p class="error">Attention, les mails ont déjà été envoyés le
|
||||
{{ show.rappel_sent }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if not sent %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<br />
|
||||
<input type="submit" value="Envoyer" />
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<h3>Forme des mails</h3>
|
||||
|
||||
<br />Une seule place<br /><br />
|
||||
<pre>{{ exemple_mail_1place }}</pre>
|
||||
|
||||
<br />Deux places<br /><br />
|
||||
<pre>{{ exemple_mail_2places }}</pre>
|
||||
{% endblock %}
|
|
@ -33,4 +33,5 @@ urlpatterns = patterns(
|
|||
url(r'spectacles/unpaid/(?P<tirage_id>\d+)$',
|
||||
"bda.views.unpaid",
|
||||
name="bda-unpaid"),
|
||||
url(r'mails-rappel/(?P<spectacle_id>\d+)$', "bda.views.send_rappel"),
|
||||
)
|
||||
|
|
32
bda/views.py
32
bda/views.py
|
@ -19,7 +19,7 @@ import time
|
|||
|
||||
from gestioncof.decorators import cof_required, buro_required
|
||||
from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution,\
|
||||
Tirage
|
||||
Tirage, render_template
|
||||
from bda.algorithm import Algorithm
|
||||
|
||||
from bda.forms import BaseBdaFormSet, TokenForm, ResellForm
|
||||
|
@ -249,7 +249,7 @@ def do_tirage(request, tirage_id):
|
|||
# À partir d'ici, le tirage devient effectif
|
||||
# FIXME: Établir les conditions de validations (formulaire ?)
|
||||
# cf. issue #32
|
||||
if False:
|
||||
if True:
|
||||
Attribution.objects.filter(
|
||||
spectacle__tirage=tirage_elt
|
||||
).delete()
|
||||
|
@ -370,3 +370,31 @@ def liste_spectacles_ics(request, tirage_id):
|
|||
return render(request, "liste_spectacles.ics",
|
||||
{"spectacles": spectacles, "tirage": tirage},
|
||||
content_type="text/calendar")
|
||||
|
||||
|
||||
@buro_required
|
||||
def send_rappel(request, spectacle_id):
|
||||
show = get_object_or_404(Spectacle, id=spectacle_id)
|
||||
# Mails d'exemples
|
||||
fake_member = request.user
|
||||
fake_member.nb_attr = 1
|
||||
exemple_mail_1place = render_template('mail-rappel.txt', {
|
||||
'member': fake_member,
|
||||
'show': show})
|
||||
fake_member.nb_attr = 2
|
||||
exemple_mail_2places = render_template('mail-rappel.txt', {
|
||||
'member': fake_member,
|
||||
'show': show})
|
||||
# Contexte
|
||||
ctxt = {'show': show,
|
||||
'exemple_mail_1place': exemple_mail_1place,
|
||||
'exemple_mail_2places': exemple_mail_2places}
|
||||
# Envoi confirmé
|
||||
if request.method == 'POST':
|
||||
members = show.send_rappel()
|
||||
ctxt['sent'] = True
|
||||
ctxt['members'] = members
|
||||
# Demande de confirmation
|
||||
else:
|
||||
ctxt['sent'] = False
|
||||
return render(request, "mails-rappel.html", ctxt)
|
||||
|
|
|
@ -137,6 +137,9 @@ PETITS_COURS_FROM = "Le COF <cof@ens.fr>"
|
|||
PETITS_COURS_BCC = "archivescof@gmail.com"
|
||||
PETITS_COURS_REPLYTO = "cof@ens.fr"
|
||||
|
||||
RAPPEL_FROM = 'Le BdA <bda@ens.fr>'
|
||||
RAPPEL_REPLY_TO = RAPPEL_FROM
|
||||
|
||||
LOGIN_URL = "/login"
|
||||
LOGIN_REDIRECT_URL = "/"
|
||||
|
||||
|
|
32
gestioncof/migrations/0004_registration_mail.py
Normal file
32
gestioncof/migrations/0004_registration_mail.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
def create_mail(apps, schema_editor):
|
||||
CustomMail = apps.get_model("gestioncof", "CustomMail")
|
||||
db_alias = schema_editor.connection.alias
|
||||
if CustomMail.objects.filter(shortname="bienvenue").count() == 0:
|
||||
CustomMail.objects.using(db_alias).bulk_create([
|
||||
CustomMail(
|
||||
shortname="bienvenue",
|
||||
title="Bienvenue au COF",
|
||||
content="Mail de bienvenue au COF, envoyé automatiquement à " \
|
||||
+ "l'inscription.\n\n" \
|
||||
+ "Les balises {{ ... }} sont interprétées comme expliqué " \
|
||||
+ "ci-dessous à l'envoi.",
|
||||
comments="{{ nom }} \t fullname de la personne.\n"\
|
||||
+ "{{ prenom }} \t prénom de la personne.")
|
||||
])
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gestioncof', '0002_enable_unprocessed_demandes'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Pas besoin de supprimer le mail lors de la migration dans l'autre
|
||||
# sens.
|
||||
migrations.RunPython(create_mail, migrations.RunPython.noop),
|
||||
]
|
Loading…
Reference in a new issue