# -*- coding: utf-8 -*- import calendar import random from datetime import timedelta from custommail.shortcuts import send_mass_custom_mail from django.contrib.sites.models import Site from django.db import models from django.contrib.auth.models import User from django.conf import settings from django.utils import timezone, formats class Tirage(models.Model): title = models.CharField("Titre", max_length=300) ouverture = models.DateTimeField("Date et heure d'ouverture du tirage") fermeture = models.DateTimeField("Date et heure de fermerture du tirage") tokens = models.TextField("Graine(s) du tirage", blank=True) active = models.BooleanField("Tirage actif", default=False) appear_catalogue = models.BooleanField( "Tirage à afficher dans le catalogue", default=False ) enable_do_tirage = models.BooleanField("Le tirage peut être lancé", default=False) def __str__(self): return "%s - %s" % (self.title, formats.localize( timezone.template_localtime(self.fermeture))) class Salle(models.Model): name = models.CharField("Nom", max_length=300) address = models.TextField("Adresse") def __str__(self): return self.name class CategorieSpectacle(models.Model): name = models.CharField('Nom', max_length=100, unique=True) def __str__(self): return self.name class Meta: verbose_name = "Catégorie" class Spectacle(models.Model): title = models.CharField("Titre", max_length=300) category = models.ForeignKey(CategorieSpectacle, blank=True, null=True) date = models.DateTimeField("Date & heure") location = models.ForeignKey(Salle) vips = models.TextField('Personnalités', blank=True) description = models.TextField("Description", blank=True) slots_description = models.TextField("Description des places", blank=True) image = models.ImageField('Image', blank=True, null=True, upload_to='imgs/shows/') ext_link = models.CharField('Lien vers le site du spectacle', blank=True, max_length=500) price = models.FloatField("Prix d'une place") slots = models.IntegerField("Places") 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" ordering = ("date", "title",) def timestamp(self): return "%d" % calendar.timegm(self.date.utctimetuple()) def __str__(self): return "%s - %s, %s, %.02f€" % ( self.title, formats.localize(timezone.template_localtime(self.date)), self.location, self.price ) def getImgUrl(self): """ Cette fonction permet d'obtenir l'URL de l'image, si elle existe """ try: return self.image.url except: return None 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][1] = 2 else: members[member.id] = [member, 1] # FIXME : faire quelque chose de ça, un utilisateur bda_generic ? # # Pour le BdA # members[0] = ['BdA', 1, 'bda@ens.fr'] # members[-1] = ['BdA', 2, 'bda@ens.fr'] # On écrit un mail personnalisé à chaque participant datatuple = [( 'bda-rappel', {'member': member[0], 'nb_attr': member[1], 'show': self}, settings.MAIL_DATA['rappels']['FROM'], [member[0].email]) for member in members.values() ] send_mass_custom_mail(datatuple) # 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() @property def is_past(self): return self.date < timezone.now() class Quote(models.Model): spectacle = models.ForeignKey(Spectacle) text = models.TextField('Citation') author = models.CharField('Auteur', max_length=200) PAYMENT_TYPES = ( ("cash", "Cash"), ("cb", "CB"), ("cheque", "Chèque"), ("autre", "Autre"), ) class Participant(models.Model): user = models.ForeignKey(User) choices = models.ManyToManyField(Spectacle, through="ChoixSpectacle", related_name="chosen_by") attributions = models.ManyToManyField(Spectacle, through="Attribution", related_name="attributed_to") paid = models.BooleanField("A payé", default=False) paymenttype = models.CharField("Moyen de paiement", 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) DOUBLE_CHOICES = ( ("1", "1 place"), ("autoquit", "2 places si possible, 1 sinon"), ("double", "2 places sinon rien"), ) class ChoixSpectacle(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="participants") priority = models.PositiveIntegerField("Priorité") double_choice = models.CharField("Nombre de places", default="1", choices=DOUBLE_CHOICES, max_length=10) def get_double(self): return self.double_choice != "1" double = property(get_double) def get_autoquit(self): return self.double_choice == "autoquit" autoquit = property(get_autoquit) def __str__(self): return "Vœux de %s pour %s" % ( self.participant.user.get_full_name(), self.spectacle.title) class Meta: ordering = ("priority",) unique_together = (("participant", "spectacle",),) verbose_name = "voeu" verbose_name_plural = "voeux" class Attribution(models.Model): participant = models.ForeignKey(Participant) spectacle = models.ForeignKey(Spectacle, related_name="attribues") given = models.BooleanField("Donnée", default=False) def __str__(self): return "%s -- %s, %s" % (self.participant.user, self.spectacle.title, self.spectacle.date) 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) shotgun = models.BooleanField("Disponible immédiatement", default=False) @property def date_tirage(self): """Renvoie la date du tirage au sort de la revente.""" # 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)) # Le vendeur a aussi 1h pour changer d'avis return self.date + delay + timedelta(hours=1) def __str__(self): return "%s -- %s" % (self.seller, self.attribution.spectacle.title) class Meta: verbose_name = "Revente" def send_notif(self): """ Envoie une notification pour indiquer la mise en vente d'une place sur BdA-Revente à tous les intéressés. """ inscrits = self.attribution.spectacle.subscribed.select_related('user') datatuple = [( 'bda-revente', { 'member': participant.user, 'show': self.attribution.spectacle, 'revente': self, 'site': Site.objects.get_current() }, settings.MAIL_DATA['revente']['FROM'], [participant.user.email]) for participant in inscrits ] send_mass_custom_mail(datatuple) 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') datatuple = [( 'bda-shotgun', { 'member': participant.user, 'show': self.attribution.spectacle, 'site': Site.objects.get_current(), }, settings.MAIL_DATA['revente']['FROM'], [participant.user.email]) for participant in inscrits ] send_mass_custom_mail(datatuple) self.notif_sent = True # Flag inutile, sauf si l'horloge interne merde self.tirage_done = True self.shotgun = 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: # Envoie un mail au gagnant et au vendeur winner = random.choice(inscrits) self.soldTo = winner datatuple = [] context = { 'acheteur': winner.user, 'vendeur': seller.user, 'show': spectacle, } datatuple.append(( 'bda-revente-winner', context, settings.MAIL_DATA['revente']['FROM'], [winner.user.email], )) datatuple.append(( 'bda-revente-seller', context, settings.MAIL_DATA['revente']['FROM'], [seller.user.email] )) # Envoie un mail aux perdants for inscrit in inscrits: if inscrit != winner: new_context = dict(context) new_context['acheteur'] = inscrit.user datatuple.append(( 'bda-revente-loser', new_context, settings.MAIL_DATA['revente']['FROM'], [inscrit.user.email] )) send_mass_custom_mail(datatuple) # Si personne ne veut de la place, elle part au shotgun else: self.shotgun = True self.tirage_done = True self.save()