diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..f420a9f5 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,40 @@ +services: + - mysql:latest + - redis:latest + +variables: + # GestioCOF settings + DJANGO_SETTINGS_MODULE: "cof.settings_dev" + DBNAME: "cof_gestion" + DBUSER: "cof_gestion" + DBPASSWD: "cof_password" + DBHOST: "mysql" + REDIS_HOST: "redis" + + # Cached packages + PYTHONPATH: "$CI_PROJECT_DIR/vendor/python" + + # mysql service configuration + MYSQL_DATABASE: "$DBNAME" + MYSQL_USER: "$DBUSER" + MYSQL_PASSWORD: "$DBPASSWD" + MYSQL_ROOT_PASSWORD: "root_password" + + +cache: + paths: + - vendor/python + - vendor/pip + - vendor/apt + +before_script: + - mkdir -p vendor/{python,pip,apt} + - apt-get update -q && apt-get -o dir::cache::archives="vendor/apt" install -yqq mysql-client + - mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host="$DBHOST" + -e "GRANT ALL ON test_$DBNAME.* TO '$DBUSER'@'%'" + - pip install --cache-dir vendor/pip -t vendor/python -r requirements-devel.txt + +test: + stage: test + script: + - python manage.py test diff --git a/Vagrantfile b/Vagrantfile index c84c3dd9..e12a45ed 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,7 +10,7 @@ Vagrant.configure(2) do |config| # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. - config.vm.box = "ubuntu/trusty64" + config.vm.box = "ubuntu/xenial64" # On associe le port 80 dans la machine virtuelle avec le port 8080 de notre # ordinateur, et le port 8000 avec le port 8000. diff --git a/bda/admin.py b/bda/admin.py index b23d79e0..a9b3c51f 100644 --- a/bda/admin.py +++ b/bda/admin.py @@ -5,12 +5,13 @@ from __future__ import print_function from __future__ import unicode_literals from django.core.mail import send_mail - from django.contrib import admin from django.db.models import Sum, Count -from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\ - Attribution, Tirage, Quote, CategorieSpectacle +from django.template.defaultfilters import pluralize +from django.utils import timezone from django import forms +from bda.models import Spectacle, Salle, Participant, ChoixSpectacle,\ + Attribution, Tirage, Quote, CategorieSpectacle, SpectacleRevente from datetime import timedelta @@ -210,6 +211,70 @@ class SalleAdmin(admin.ModelAdmin): search_fields = ('name', 'address') +class SpectacleReventeAdmin(admin.ModelAdmin): + """ + Administration des reventes de spectacles + """ + model = SpectacleRevente + + def spectacle(self, obj): + """ + Raccourci vers le spectacle associé à la revente. + """ + return obj.attribution.spectacle + + list_display = ("spectacle", "seller", "date", "soldTo") + raw_id_fields = ("attribution",) + readonly_fields = ("shotgun", "expiration_time") + search_fields = ['attribution__spectacle__title', + 'seller__user__username', + 'seller__user__first_name', + 'seller__user__last_name'] + + actions = ['transfer', 'reinit'] + actions_on_bottom = True + + def transfer(self, request, queryset): + """ + Effectue le transfert des reventes pour lesquels on connaît l'acheteur. + """ + reventes = queryset.exclude(soldTo__isnull=True).all() + count = reventes.count() + for revente in reventes: + attrib = revente.attribution + attrib.participant = revente.soldTo + attrib.save() + self.message_user( + request, + "%d attribution%s %s été transférée%s avec succès." % ( + count, pluralize(count), + pluralize(count, "a,ont"), pluralize(count)) + ) + transfer.short_description = "Transférer les reventes sélectionnées" + + def reinit(self, request, queryset): + """ + Réinitialise les reventes. + """ + count = queryset.count() + for revente in queryset.filter( + attribution__spectacle__date__gte=timezone.now()): + revente.date = timezone.now() - timedelta(hours=1) + revente.soldTo = None + revente.notif_sent = False + revente.tirage_done = False + if revente.answered_mail: + revente.answered_mail.clear() + revente.save() + self.message_user( + request, + "%d attribution%s %s été réinitialisée%s avec succès." % ( + count, pluralize(count), + pluralize(count, "a,ont"), pluralize(count)) + ) + reinit.short_description = "Réinitialiser les reventes sélectionnées" + + admin.site.register(CategorieSpectacle) admin.site.register(Spectacle, SpectacleAdmin) admin.site.register(Salle, SalleAdmin) @@ -217,3 +282,4 @@ admin.site.register(Participant, ParticipantAdmin) admin.site.register(Attribution, AttributionAdmin) admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin) admin.site.register(Tirage, TirageAdmin) +admin.site.register(SpectacleRevente, SpectacleReventeAdmin) diff --git a/bda/forms.py b/bda/forms.py index 9f5e3890..fe20e565 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -4,9 +4,13 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals +from datetime import timedelta + from django import forms from django.forms.models import BaseInlineFormSet -from bda.models import Spectacle +from django.db.models import Q +from django.utils import timezone +from bda.models import Attribution, Spectacle class BaseBdaFormSet(BaseInlineFormSet): @@ -35,17 +39,47 @@ class TokenForm(forms.Form): token = forms.CharField(widget=forms.widgets.Textarea()) -class SpectacleModelChoiceField(forms.ModelChoiceField): +class AttributionModelMultipleChoiceField(forms.ModelMultipleChoiceField): def label_from_instance(self, obj): - return "%s le %s (%s) à %.02f€" % (obj.title, obj.date_no_seconds(), - obj.location, obj.price) + return "%s" % obj.spectacle class ResellForm(forms.Form): - count = forms.ChoiceField(choices=(("1", "1"), ("2", "2"),)) - spectacle = SpectacleModelChoiceField(queryset=Spectacle.objects.none()) + attributions = AttributionModelMultipleChoiceField( + queryset=Attribution.objects.none(), + widget=forms.CheckboxSelectMultiple, + required=False) def __init__(self, participant, *args, **kwargs): super(ResellForm, self).__init__(*args, **kwargs) - self.fields['spectacle'].queryset = participant.attributions.all() \ - .distinct() + self.fields['attributions'].queryset = participant.attribution_set\ + .filter(spectacle__date__gte=timezone.now())\ + .exclude(revente__seller=participant) + + +class AnnulForm(forms.Form): + attributions = AttributionModelMultipleChoiceField( + queryset=Attribution.objects.none(), + widget=forms.CheckboxSelectMultiple, + required=False) + + def __init__(self, participant, *args, **kwargs): + super(AnnulForm, self).__init__(*args, **kwargs) + self.fields['attributions'].queryset = participant.attribution_set\ + .filter(spectacle__date__gte=timezone.now(), + revente__isnull=False, + revente__date__gt=timezone.now()-timedelta(hours=1))\ + .filter(Q(revente__soldTo__isnull=True) | + Q(revente__soldTo=participant)) + + +class InscriptionReventeForm(forms.Form): + spectacles = forms.ModelMultipleChoiceField( + queryset=Spectacle.objects.none(), + widget=forms.CheckboxSelectMultiple, + required=False) + + def __init__(self, tirage, *args, **kwargs): + super(InscriptionReventeForm, self).__init__(*args, **kwargs) + self.fields['spectacles'].queryset = tirage.spectacle_set.filter( + date__gte=timezone.now()) diff --git a/bda/management/commands/manage_reventes.py b/bda/management/commands/manage_reventes.py new file mode 100644 index 00000000..4b90bc57 --- /dev/null +++ b/bda/management/commands/manage_reventes.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +""" +Gestion en ligne de commande des reventes. +""" + +from __future__ import unicode_literals + +from datetime import timedelta +from django.core.management import BaseCommand +from django.utils import timezone +from bda.models import SpectacleRevente + + +class Command(BaseCommand): + help = "Envoie les mails de notification et effectue " \ + "les tirages au sort des reventes" + leave_locale_alone = True + + def handle(self, *args, **options): + now = timezone.now() + reventes = SpectacleRevente.objects.all() + for revente in reventes: + # Check si < 24h + if (revente.attribution.spectacle.date <= + revente.date + timedelta(days=1)) and \ + now >= revente.date + timedelta(minutes=15) and \ + not revente.notif_sent: + self.stdout.write(str(now)) + revente.mail_shotgun() + self.stdout.write("Mail de disponibilité immédiate envoyé") + # Check si délai de retrait dépassé + elif (now >= revente.date + timedelta(hours=1) and + not revente.notif_sent): + self.stdout.write(str(now)) + revente.send_notif() + self.stdout.write("Mail d'inscription à une revente envoyé") + # Check si tirage à faire + elif (now >= revente.expiration_time and + not revente.tirage_done): + self.stdout.write(str(now)) + revente.tirage() + self.stdout.write("Tirage effectué, mails envoyés") diff --git a/bda/management/commands/sendrappels.py b/bda/management/commands/sendrappels.py index 1e8da240..88cf9d5c 100644 --- a/bda/management/commands/sendrappels.py +++ b/bda/management/commands/sendrappels.py @@ -1,16 +1,21 @@ # -*- coding: utf-8 -*- +""" +Gestion en ligne de commande des mails de rappel. +""" + from __future__ import unicode_literals +from datetime import timedelta from django.core.management.base import BaseCommand from django.utils import timezone -from datetime import timedelta from bda.models import Spectacle class Command(BaseCommand): help = 'Envoie les mails de rappel des spectacles dont la date ' \ 'approche.\nNe renvoie pas les mails déjà envoyés.' + leave_locale_alone = True def handle(self, *args, **options): now = timezone.now() diff --git a/bda/migrations/0009_revente.py b/bda/migrations/0009_revente.py new file mode 100644 index 00000000..1cca4e86 --- /dev/null +++ b/bda/migrations/0009_revente.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('bda', '0008_py3'), + ] + + operations = [ + migrations.CreateModel( + name='SpectacleRevente', + fields=[ + ('id', models.AutoField(serialize=False, primary_key=True, + auto_created=True, verbose_name='ID')), + ('date', models.DateTimeField( + verbose_name='Date de mise en vente', + default=django.utils.timezone.now)), + ('notif_sent', models.BooleanField( + verbose_name='Notification envoyée', default=False)), + ('tirage_done', models.BooleanField( + verbose_name='Tirage effectué', default=False)), + ], + options={ + 'verbose_name': 'Revente', + }, + ), + migrations.AddField( + model_name='participant', + name='choicesrevente', + field=models.ManyToManyField(to='bda.Spectacle', + related_name='subscribed', + blank=True), + ), + migrations.AddField( + model_name='spectaclerevente', + name='answered_mail', + field=models.ManyToManyField(to='bda.Participant', + related_name='wanted', + blank=True), + ), + migrations.AddField( + model_name='spectaclerevente', + name='attribution', + field=models.OneToOneField(to='bda.Attribution', + related_name='revente'), + ), + migrations.AddField( + model_name='spectaclerevente', + name='seller', + field=models.ForeignKey(to='bda.Participant', + verbose_name='Vendeur', + related_name='original_shows'), + ), + migrations.AddField( + model_name='spectaclerevente', + name='soldTo', + field=models.ForeignKey(to='bda.Participant', + verbose_name='Vendue à', null=True, + blank=True), + ), + ] diff --git a/bda/models.py b/bda/models.py index 270921be..85c7fa4d 100644 --- a/bda/models.py +++ b/bda/models.py @@ -5,22 +5,19 @@ from __future__ import print_function from __future__ import unicode_literals import calendar +import random +from datetime import timedelta +from django.contrib.sites.models import Site from django.db import models from django.contrib.auth.models import User -from django.template import loader, Context +from django.template import loader from django.core import mail from django.conf import settings -from django.utils import timezone +from django.utils import timezone, formats from django.utils.encoding import python_2_unicode_compatible -def render_template(template_name, data): - tmpl = loader.get_template(template_name) - ctxt = Context(data) - return tmpl.render(ctxt) - - @python_2_unicode_compatible class Tirage(models.Model): title = models.CharField("Titre", max_length=300) @@ -31,12 +28,9 @@ class Tirage(models.Model): enable_do_tirage = models.BooleanField("Le tirage peut être lancé", default=False) - def date_no_seconds(self): - return self.fermeture.astimezone(timezone.get_current_timezone()) \ - .strftime('%d %b %Y %H:%M') - def __str__(self): - return "%s - %s" % (self.title, self.date_no_seconds()) + return "%s - %s" % (self.title, formats.localize( + timezone.template_localtime(self.fermeture))) @python_2_unicode_compatible @@ -83,42 +77,46 @@ class Spectacle(models.Model): verbose_name = "Spectacle" ordering = ("date", "title",) - def __repr__(self): - return "[%s]" % self - def timestamp(self): return "%d" % calendar.timegm(self.date.utctimetuple()) - def date_no_seconds(self): - return self.date.astimezone(timezone.get_current_timezone()) \ - .strftime('%d %b %Y %H:%M') - def __str__(self): - return "%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), - self.location, self.price) + return "%s - %s, %s, %.02f€" % ( + self.title, + formats.localize(timezone.template_localtime(self.date)), + self.location, + self.price + ) def send_rappel(self): + """ + Envoie un mail de rappel à toutes les personnes qui ont une place pour + ce spectacle. + """ # 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 + members[member.id][1] = 2 else: - member.nb_attr = 1 - members[member.id] = member + members[member.id] = [member.first_name, 1, member.email] + # Pour le BdA + members[0] = ['BdA', 1, 'bda@ens.fr'] + members[-1] = ['BdA', 2, 'bda@ens.fr'] # On écrit un mail personnalisé à chaque participant mails_to_send = [] - mail_object = "%s - %s - %s" % (self.title, self.date_no_seconds(), - self.location) + mail_object = str(self) for member in members.values(): - mail_body = render_template('mail-rappel.txt', { - 'member': member, - 'show': self}) + mail_body = loader.render_to_string('bda/mails/rappel.txt', { + 'name': member[0], + 'nb_attr': member[1], + 'show': self}) mail_tot = mail.EmailMessage( - mail_object, mail_body, - settings.RAPPEL_FROM, [member.email], - [], headers={'Reply-To': settings.RAPPEL_REPLY_TO}) + mail_object, mail_body, + settings.MAIL_DATA['rappels']['FROM'], [member[2]], + [], headers={ + 'Reply-To': settings.MAIL_DATA['rappels']['REPLYTO']}) mails_to_send.append(mail_tot) # On envoie les mails connection = mail.get_connection() @@ -158,6 +156,9 @@ class Participant(models.Model): max_length=6, choices=PAYMENT_TYPES, blank=True) tirage = models.ForeignKey(Tirage) + choicesrevente = models.ManyToManyField(Spectacle, + related_name="subscribed", + blank=True) def __str__(self): return "%s - %s" % (self.user, self.tirage.title) @@ -205,4 +206,170 @@ class Attribution(models.Model): given = models.BooleanField("Donnée", default=False) def __str__(self): - return "%s -- %s" % (self.participant, self.spectacle) + return "%s -- %s, %s" % (self.participant.user, self.spectacle.title, + self.spectacle.date) + + +@python_2_unicode_compatible +class SpectacleRevente(models.Model): + attribution = models.OneToOneField(Attribution, + related_name="revente") + date = models.DateTimeField("Date de mise en vente", + default=timezone.now) + answered_mail = models.ManyToManyField(Participant, + related_name="wanted", + blank=True) + seller = models.ForeignKey(Participant, + related_name="original_shows", + verbose_name="Vendeur") + soldTo = models.ForeignKey(Participant, blank=True, null=True, + verbose_name="Vendue à") + + notif_sent = models.BooleanField("Notification envoyée", + default=False) + tirage_done = models.BooleanField("Tirage effectué", + default=False) + + @property + def expiration_time(self): + # L'acheteur doit être connu au plus 12h avant le spectacle + remaining_time = (self.attribution.spectacle.date + - self.date - timedelta(hours=13)) + # Au minimum, on attend 2 jours avant le tirage + delay = min(remaining_time, timedelta(days=2)) + # On a aussi 1h pour changer d'avis + return self.date + delay + timedelta(hours=1) + + def expiration_time_str(self): + return self.expiration_time \ + .astimezone(timezone.get_current_timezone()) \ + .strftime('%d/%m/%y à %H:%M') + + @property + def shotgun(self): + # Soit on a dépassé le délai du tirage, soit il reste peu de + # temps avant le spectacle + # On se laisse 5min de marge pour cron + return (timezone.now() > self.expiration_time + timedelta(minutes=5) or + (self.attribution.spectacle.date <= timezone.now() + + timedelta(days=1))) and (timezone.now() >= self.date + + timedelta(minutes=15)) + + def __str__(self): + return "%s -- %s" % (self.seller, + self.attribution.spectacle.title) + + class Meta: + verbose_name = "Revente" + + def send_notif(self): + inscrits = self.attribution.spectacle.subscribed.select_related('user') + + mails_to_send = [] + mail_object = "%s" % (self.attribution.spectacle) + for participant in inscrits: + mail_body = loader.render_to_string('bda/mails/revente.txt', { + 'user': participant.user, + 'spectacle': self.attribution.spectacle, + 'revente': self, + 'domain': Site.objects.get_current().domain}) + mail_tot = mail.EmailMessage( + mail_object, mail_body, + settings.MAIL_DATA['revente']['FROM'], + [participant.user.email], + [], headers={ + 'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']}) + mails_to_send.append(mail_tot) + + connection = mail.get_connection() + connection.send_messages(mails_to_send) + self.notif_sent = True + self.save() + + def mail_shotgun(self): + """ + Envoie un mail à toutes les personnes intéréssées par le spectacle pour + leur indiquer qu'il est désormais disponible au shotgun. + """ + inscrits = self.attribution.spectacle.subscribed.select_related('user') + + mails_to_send = [] + mail_object = "%s" % (self.attribution.spectacle) + for participant in inscrits: + mail_body = loader.render_to_string('bda/mails/shotgun.txt', { + 'user': participant.user, + 'spectacle': self.attribution.spectacle, + 'domain': Site.objects.get_current(), + 'mail': self.attribution.participant.user.email}) + mail_tot = mail.EmailMessage( + mail_object, mail_body, + settings.MAIL_DATA['revente']['FROM'], + [participant.user.email], + [], headers={ + 'Reply-To': settings.MAIL_DATA['revente']['REPLYTO']}) + mails_to_send.append(mail_tot) + + connection = mail.get_connection() + connection.send_messages(mails_to_send) + self.notif_sent = True + self.save() + + def tirage(self): + """ + Lance le tirage au sort associé à la revente. Un gagnant est choisi + parmis les personnes intéressées par le spectacle. Les personnes sont + ensuites prévenues par mail du résultat du tirage. + """ + inscrits = list(self.answered_mail.all()) + spectacle = self.attribution.spectacle + seller = self.seller + + if inscrits: + mails = [] + mail_subject = "BdA-Revente : {:s}".format(spectacle.title) + + # Envoie un mail au gagnant et au vendeur + winner = random.choice(inscrits) + self.soldTo = winner + context = { + 'acheteur': winner.user, + 'vendeur': seller.user, + 'spectacle': spectacle, + } + mails.append(mail.EmailMessage( + mail_subject, + loader.render_to_string('bda/mails/revente-winner.txt', + context), + from_email=settings.MAIL_DATA['revente']['FROM'], + to=[winner.user.email], + reply_to=[seller.user.email], + )) + mails.append(mail.EmailMessage( + mail_subject, + loader.render_to_string('bda/mails/revente-seller.txt', + context), + from_email=settings.MAIL_DATA['revente']['FROM'], + to=[seller.user.email], + reply_to=[winner.user.email], + )) + + # Envoie un mail aux perdants + for inscrit in inscrits: + if inscrit == winner: + continue + + mail_body = loader.render_to_string( + 'bda/mails/revente-loser.txt', + {'acheteur': inscrit.user, + 'vendeur': seller.user, + 'spectacle': spectacle} + ) + mails.append(mail.EmailMessage( + mail_subject, mail_body, + from_email=settings.MAIL_DATA['revente']['FROM'], + to=[inscrit.user.email], + reply_to=[settings.MAIL_DATA['revente']['REPLYTO']], + )) + mail.get_connection().send_messages(mails) + self.tirage_done = True + self.save() diff --git a/bda/templates/bda-attrib.html b/bda/templates/bda-attrib.html index 5c705a79..5c22d2b3 100644 --- a/bda/templates/bda-attrib.html +++ b/bda/templates/bda-attrib.html @@ -22,7 +22,7 @@ {% for show, members, losers in results %}
{{ show.nrequests }} demandes pour {{ show.slots }} places {{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }}€ de déficit{% endif %} diff --git a/bda/templates/bda-interested.html b/bda/templates/bda-interested.html new file mode 100644 index 00000000..acfb1d1e --- /dev/null +++ b/bda/templates/bda-interested.html @@ -0,0 +1,9 @@ +{% extends "base_title.html" %} +{% load staticfiles %} + +{% block realcontent %} +
Votre inscription pour a bien été enregistrée !
+Le tirage au sort pour cette revente ({{spectacle}}) sera effectué le {{date}}. + +{% endblock %} diff --git a/bda/templates/bda-no-revente.html b/bda/templates/bda-no-revente.html new file mode 100644 index 00000000..eabb3dc7 --- /dev/null +++ b/bda/templates/bda-no-revente.html @@ -0,0 +1,6 @@ +{% extends "base_title.html" %} + +{% block realcontent %} +
Il n'y a plus de places en revente pour ce spectacle, désolé !
+{% endblock %} diff --git a/bda/templates/bda-notpaid.html b/bda/templates/bda-notpaid.html index b25c2ba3..0dd4e4df 100644 --- a/bda/templates/bda-notpaid.html +++ b/bda/templates/bda-notpaid.html @@ -1,6 +1,6 @@ {% extends "base_title.html" %} {% block realcontent %} -Avant de revendre des places, il faut aller les payer !
{% endblock %} diff --git a/bda/templates/bda-revente.html b/bda/templates/bda-revente.html index 10a93d43..569a3f3a 100644 --- a/bda/templates/bda-revente.html +++ b/bda/templates/bda-revente.html @@ -1,26 +1,73 @@ {% extends "base_title.html" %} -{% load staticfiles %} - -{% block extra_head %} - -{% endblock %} +{% load bootstrap %} {% block realcontent %} -Pas de places disponibles immédiatement, désolé !
+ {% endif %} + +{% endblock %} diff --git a/bda/templates/bda-success.html b/bda/templates/bda-success.html index ebcc87a7..5e970eb7 100644 --- a/bda/templates/bda-success.html +++ b/bda/templates/bda-success.html @@ -1,12 +1,8 @@ {% extends "base_title.html" %} {% load staticfiles %} -{% block extra_head %} - -{% endblock %} - {% block realcontent %} -Votre offre de revente de {{ places }} pour {{ show.title }} le {{ show.date_no_seconds }} ({{ show.location }}) à {{ show.price }}€ a bien été envoyée.
+Un mail a bien été envoyé à {{seller.get_full_name}} ({{seller.email}}), pour racheter une place pour {{spectacle.title}} !
{% endblock %} diff --git a/bda/templates/bda-wrongtime.html b/bda/templates/bda-wrongtime.html new file mode 100644 index 00000000..5e17926b --- /dev/null +++ b/bda/templates/bda-wrongtime.html @@ -0,0 +1,6 @@ +{% extends "base_title.html" %} + +{% block realcontent %} +Cette revente n'est pas disponible actuellement, désolé !
+{% endblock %} diff --git a/bda/templates/bda/mails/buy-shotgun.txt b/bda/templates/bda/mails/buy-shotgun.txt new file mode 100644 index 00000000..d7855143 --- /dev/null +++ b/bda/templates/bda/mails/buy-shotgun.txt @@ -0,0 +1,6 @@ +Bonjour {{ vendeur.first_name }} ! + +Je souhaiterais racheter ta place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€. +Contacte-moi si tu es toujours intéressé·e ! + +{{ acheteur.get_full_name }} ({{ acheteur.email }}) diff --git a/bda/templates/mail-rappel.txt b/bda/templates/bda/mails/rappel.txt similarity index 67% rename from bda/templates/mail-rappel.txt rename to bda/templates/bda/mails/rappel.txt index 5152b1db..c6433f8a 100644 --- a/bda/templates/mail-rappel.txt +++ b/bda/templates/bda/mails/rappel.txt @@ -1,14 +1,14 @@ -Bonjour {{ member.get_full_name }}, +Bonjour {{ 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 %} +Nous te rappellons que tu as eu la chance d'obtenir {{ nb_attr|pluralize:"une place,deux places" }} +pour {{ show.title }}, le {{ show.date }} au {{ show.location }}. N'oublie pas de t'y rendre ! +{% if 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" }}. +pour retirer {{ 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 %} diff --git a/bda/templates/bda/mails/revente-loser.txt b/bda/templates/bda/mails/revente-loser.txt new file mode 100644 index 00000000..6b50944d --- /dev/null +++ b/bda/templates/bda/mails/revente-loser.txt @@ -0,0 +1,9 @@ +Bonjour {{ acheteur.first_name }}, + +Tu t'étais inscrit-e pour la revente de la place de {{ vendeur.get_full_name }} +pour {{ spectacle.title }}. +Malheureusement, une autre personne a été tirée au sort pour racheter la place. +Tu pourras certainement retenter ta chance pour une autre revente ! + +À très bientôt, +Le Bureau des Arts diff --git a/bda/templates/bda/mails/revente-new.txt b/bda/templates/bda/mails/revente-new.txt new file mode 100644 index 00000000..ffba3083 --- /dev/null +++ b/bda/templates/bda/mails/revente-new.txt @@ -0,0 +1,13 @@ +Bonjour {{ vendeur.first_name }}, + +Tu t’es bien inscrit-e pour la revente de {{ spectacle.title }}. + +{% with revente.expiration_time as time %} +Le tirage au sort entre tout-e-s les racheteuse-eur-s potentiel-le-s aura lieu +le {{ time|date:"DATE_FORMAT" }} à {{ time|time:"TIME_FORMAT" }} (dans {{time|timeuntil }}). +Si personne ne s’est inscrit pour racheter la place, celle-ci apparaitra parmi +les « Places disponibles immédiatement à la revente » sur GestioCOF. +{% endwith %} + +Bonne revente ! +Le Bureau des Arts diff --git a/bda/templates/bda/mails/revente-seller.txt b/bda/templates/bda/mails/revente-seller.txt new file mode 100644 index 00000000..ec99b98b --- /dev/null +++ b/bda/templates/bda/mails/revente-seller.txt @@ -0,0 +1,7 @@ +Bonjour {{ vendeur.first_name }}, + +La personne tirée au sort pour racheter ta place pour {{ spectacle.title }} est {{ acheteur.get_full_name }}. +Tu peux le/la contacter à l'adresse {{ acheteur.email }}, ou en répondant à ce mail. + +Chaleureusement, +Le BdA diff --git a/bda/templates/bda/mails/revente-winner.txt b/bda/templates/bda/mails/revente-winner.txt new file mode 100644 index 00000000..01ecfb86 --- /dev/null +++ b/bda/templates/bda/mails/revente-winner.txt @@ -0,0 +1,7 @@ +Bonjour {{ acheteur.first_name }}, + +Tu as été tiré-e au sort pour racheter une place pour {{ spectacle.title }} le {{ spectacle.date }} ({{ spectacle.location }}) à {{ spectacle.price|floatformat:2 }}€. +Tu peux contacter le/la vendeur-se à l'adresse {{ vendeur.email }}, ou en répondant à ce mail. + +Chaleureusement, +Le BdA diff --git a/bda/templates/bda/mails/revente.txt b/bda/templates/bda/mails/revente.txt new file mode 100644 index 00000000..397a58d8 --- /dev/null +++ b/bda/templates/bda/mails/revente.txt @@ -0,0 +1,12 @@ +Bonjour {{ user.first_name }} + +Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }}) +a été postée sur BdA-Revente. + +Si ce spectacle t'intéresse toujours, merci de nous le signaler en cliquant +sur ce lien : http://{{ domain }}{% url "bda-revente-interested" revente.id %}. +Dans le cas où plusieurs personnes seraient intéressées, nous procèderons à +un tirage au sort le {{ revente.expiration_time_str }}. + +Chaleureusement, +Le BdA diff --git a/bda/templates/bda/mails/shotgun.txt b/bda/templates/bda/mails/shotgun.txt new file mode 100644 index 00000000..69bc704c --- /dev/null +++ b/bda/templates/bda/mails/shotgun.txt @@ -0,0 +1,11 @@ +Bonjour {{ user.first_name }} + +Une place pour le spectacle {{ spectacle.title }} ({{ spectacle.date }}) +a été postée sur BdA-Revente. + +Puisque ce spectacle a lieu dans moins de 24h, il n'y a pas de tirage au sort pour +cette place : elle est disponible immédiatement à l'adresse +http://{{ domain }}{% url "bda-buy-revente" spectacle.id %}, à la disposition de tous. + +Chaleureusement, +Le BdA diff --git a/bda/templates/etat-places.html b/bda/templates/etat-places.html index ebd15c38..4aa72ba1 100644 --- a/bda/templates/etat-places.html +++ b/bda/templates/etat-places.html @@ -18,7 +18,7 @@ {% for spectacle in spectacles %}Ton inscription a bien été prise en compte !
+ {% endif %} + {% if deja_revente %} +Des reventes existent déjà pour certains de ces spectacles ; vérifie les places disponibles sans tirage !
+ {% endif %} + + + +{% endblock %} diff --git a/bda/templates/resume_places.html b/bda/templates/resume_places.html index 9ca5c78f..614a1656 100644 --- a/bda/templates/resume_places.html +++ b/bda/templates/resume_places.html @@ -11,7 +11,7 @@Note : ce mail sera envoyé à une personne au hasard revendant sa place.
+{%endblock%} diff --git a/bda/templates/spectacle_list.html b/bda/templates/spectacle_list.html index 816461db..c7456f6e 100644 --- a/bda/templates/spectacle_list.html +++ b/bda/templates/spectacle_list.html @@ -19,7 +19,7 @@ {% for spectacle in object_list %}