Only in .: .admin.py.swp
Binary files ../bda/__init__.pyc and ./__init__.pyc differ
diff -p -u -r ../bda/admin.py ./admin.py
--- ../bda/admin.py	2013-12-17 10:19:56.000000000 +0100
+++ ./admin.py	2012-12-08 22:31:46.000000000 +0100
@@ -4,8 +4,8 @@ from django.core.mail import send_mail
 from django.contrib.contenttypes.models import ContentType
 
 from django.contrib import admin
-from django.db.models import Sum, Count
-from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution
+from django.db.models import Sum
+from bda3.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution
 
 class ChoixSpectacleInline(admin.TabularInline):
     model = ChoixSpectacle
@@ -17,18 +17,13 @@ class AttributionInline(admin.TabularInl
 class ParticipantAdmin(admin.ModelAdmin):
     #inlines = [ChoixSpectacleInline]
     inlines = [AttributionInline]
-    def queryset(self, request):
-        return Participant.objects.annotate(nb_places = Count('attributions'),
-                                            total = Sum('attributions__price'))
     def nb_places(self, obj):
-        return obj.nb_places
-    nb_places.admin_order_field = "nb_places"
+        return len(obj.attribution_set.all())
     nb_places.short_description = "Nombre de places"
     def total(self, obj):
-        tot = obj.total
+        tot = obj.attributions.aggregate(total = Sum('price'))['total']
         if tot: return u"%.02f €" % tot
         else: return u"0 €"
-    total.admin_order_field = "total"
     total.short_description = "Total à payer"
     list_display = ("user", "nb_places", "total", "paid", "paymenttype")
     list_filter = ("paid",)
@@ -61,7 +56,7 @@ Voici tes choix de spectacles tels que n
 Artistiquement,
 Le BdA"""
             send_mail ("Choix de spectacles (BdA du COF)", mail,
-                       "bda@ens.fr", [member.user.email],
+                       "bda@clipper.ens.fr", [member.user.email],
                        fail_silently = True)
         count = len(queryset.all())
         if count == 1:
@@ -86,48 +81,41 @@ pour les spectacles suivants :
 %s
 
 *Paiement*
-L'intégralité de ces places de spectacles est à régler à partir du jeudi
-10 octobre et AVANT le mercredi 23 octobre, au bureau du COF pendant les
-heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h
-et 20h). Des facilités de paiement sont bien évidemment possibles : nous
-pouvons ne pas encaisser le chèque immédiatement, ou bien découper votre 
-paiement en deux fois.
+Ces spectacles sont à régler avant le lundi 17 décembre, pendant les
+heures de permanences du COF (tous les jours de la semaine entre 12h et
+14h, et entre 18h et 20h). Des facilités de paiement sont bien évidemment
+possibles (encaissement échelonné des chèques).
 
 *Mode de retrait des places*
-Au moment du paiement, une enveloppe vous sera remise, contenant les
-places pour l'Opéra de Paris, pour les premiers spectacles de la Comédie
-française, certains spectacles du Châtelet et du Théâtre de la Ville.
-
-Pour les concerts Radio France, le Théâtre des Champs-Élysées, le théâtre
-du Rond-Point, le théâtre de la Colline, le théâtre de l'Athénée, l'IRCAM,
-la Cité de la musique et le 104, le Studio-Théâtre de la Comédie
-française, les places seront nominatives et à retirer au théâtre le soir
-de la représentation au moins une demi-heure avant le début du spectacle.
-
-Pour le théâtre de l'Odéon, la salle Richelieu le théâtre du Vieux
-colombier de la Comédie française, certains spectacles du théâtre de la
-Ville et du théâtre de Châtelet ainsi que pour le théâtre de Chaillot, les
-places seront distribuées environ une semaine avant la représentation (un
-mail vous en avertira).
-
-Nous vous rappelons que l'obtention de places du BdA vous engage à
-respecter les règles de fonctionnement :
-http://www.cof.ens.fr/bda/?page_id=1370
-Le système de revente des places via les mails BdA-revente sera très
-prochainement disponible, directement sur votre compte GestioCOF.
+Pour l'Opéra de Paris, le théâtre de la Colline et le théâtre du Châtelet,
+les places sont à retirer au COF le jour du paiement.
+
+Pour les concerts Radio France, le théâtre des Champs-Élysées, l'IRCAM
+et le 104, les places seront nominatives et à retirer à la salle le soir de
+la représentation au moins une demi-heure avant le début du spectacle.
+
+Pour le théâtre de l'Odéon, la Comédie Française, le théâtre de la Ville,
+le théâtre de Chaillot, les places seront distribuées dans vos
+casiers environ une semaine avant la représentation (un mail vous en
+avertira).
+
+Dans tous les cas, n'hésitez pas à nous contacter si vous avez un doute !
+
+Nous profitons aussi de ce message pour vous annoncer qu'un festival de
+courts métrages aura lieu le 21 décembre dans l'école.
+Plus d'informations : http://www.cof.ens.fr/bda/courts.
+
+Culturellement vôtre,
 
-En vous souhaitant de très beaux spectacles tout au long de l'année,
 --
-Le Bureau des Arts
-(Chloé, Emilie, Jaime, Maxime, Olivier)
-"""
+Le BdA"""
             attribs_text = ""
             name = member.user.get_full_name()
             for attrib in attribs:
                 attribs_text += u"- 1 place pour %s\n" % attrib
             mail = mail % (name, attribs_text)
-            send_mail ("Résultats du tirage au sort", mail,
-                       "bda@ens.fr", [member.user.email],
+            send_mail ("Places de spectacle (BdA du COF)", mail,
+                       "bda@clipper.ens.fr", [member.user.email],
                        fail_silently = True)
         count = len(queryset.all())
         if count == 1:
@@ -154,13 +142,7 @@ class ChoixSpectacleAdmin(admin.ModelAdm
     list_filter = ("double", "autoquit")
     search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name')
 
-class SpectacleAdmin(admin.ModelAdmin):
-    model = Spectacle
-    list_display = ("title", "date", "location", "slots", "price")
-    list_filter = ("location",)
-    search_fields = ("title", "location__name")
-
-admin.site.register(Spectacle, SpectacleAdmin)
+admin.site.register(Spectacle)
 admin.site.register(Salle)
 admin.site.register(Participant, ParticipantAdmin)
 admin.site.register(Attribution, AttributionAdmin)
diff -p -u -r ../bda/algorithm.py ./algorithm.py
--- ../bda/algorithm.py	2013-10-07 14:08:44.000000000 +0200
+++ ./algorithm.py	2012-10-31 23:01:48.000000000 +0100
@@ -29,24 +29,25 @@ class Algorithm(object):
         self.ranks = {}
         self.origranks = {}
         self.choices = {}
-        next_rank = {}
-        member_shows = {}
         for member in members:
-            self.ranks[member] = {}
-            self.choices[member] = {}
-            next_rank[member] = 1
-            member_shows[member] = {}
-        for choice in choices:
-            member = choice.participant
-            if choice.spectacle in member_shows[member]: continue
-            else: member_shows[member][choice.spectacle] = True
-            showdict[choice.spectacle].requests.append(member)
-            showdict[choice.spectacle].nrequests += 2 if choice.double else 1
-            self.ranks[member][choice.spectacle] = next_rank[member]
-            next_rank[member] += 2 if choice.double else 1
-            self.choices[member][choice.spectacle] = choice
-        for member in members:
-            self.origranks[member] = dict(self.ranks[member])
+            ranks = {}
+            member_choices = {}
+            member_shows = {}
+            #next_priority = 1
+            next_rank = 1
+            for choice in member.choixspectacle_set.order_by('priority').all():
+                if choice.spectacle in member_shows: continue
+                else: member_shows[choice.spectacle] = True
+                #assert choice.priority == next_priority
+                #next_priority += 1
+                showdict[choice.spectacle].requests.append(member)
+                showdict[choice.spectacle].nrequests += 2 if choice.double else 1
+                ranks[choice.spectacle] = next_rank
+                next_rank += 2 if choice.double else 1
+                member_choices[choice.spectacle] = choice
+            self.ranks[member] = ranks
+            self.choices[member] = member_choices
+            self.origranks[member] = dict(ranks)
 
     def IncrementRanks(self, member, currank, increment = 1):
         for show in self.ranks[member]:
Only in ../bda: algorithm.pyc
Only in .: difftobda
diff -p -u -r ../bda/models.py ./models.py
--- ../bda/models.py	2013-10-10 10:44:43.000000000 +0200
+++ ./models.py	2012-10-31 23:12:56.000000000 +0100
@@ -1,7 +1,5 @@
 # coding: utf-8
 
-import calendar
-
 from django.db import models
 from django.contrib.auth.models import User
 from django.utils.translation import ugettext_lazy as _
@@ -19,7 +17,7 @@ class Spectacle (models.Model):
     date = models.DateTimeField ("Date & heure")
     location = models.ForeignKey(Salle)
     description = models.TextField ("Description", blank = True)
-    slots_description = models.TextField ("Description des places", blank = True)
+    #slots_description = models.TextField ("Description des places", blank = True)
     price = models.FloatField("Prix d'une place", blank = True)
     slots = models.IntegerField ("Places")
     priority = models.IntegerField ("Priorité", default = 1000)
@@ -31,14 +29,11 @@ class Spectacle (models.Model):
     def __repr__ (self):
         return u"[%s]" % self.__unicode__()
 
-    def timestamp(self):
-        return "%d" % calendar.timegm(self.date.utctimetuple())
-
     def date_no_seconds(self):
         return self.date.strftime('%d %b %Y %H:%M')
 
     def __unicode__ (self):
-        return u"%s - %s, %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price)
+        return u"%s - %s @ %s, %.02f€" % (self.title, self.date_no_seconds(), self.location, self.price)
 
 PAYMENT_TYPES = (
 ("cash",u"Cash"),
@@ -48,7 +43,7 @@ PAYMENT_TYPES = (
 )
 
 class Participant (models.Model):
-    user = models.ForeignKey(User, unique = True)
+    user = models.ForeignKey(User, unique = True, related_name = "participants2")
     choices = models.ManyToManyField(Spectacle, through = "ChoixSpectacle", related_name = "chosen_by")
     attributions = models.ManyToManyField(Spectacle, through = "Attribution", related_name = "attributed_to")
     paid = models.BooleanField (u"A payé", default = False)
Binary files ../bda/models.pyc and ./models.pyc differ
diff -p -u -r ../bda/views.py ./views.py
--- ../bda/views.py	2014-01-04 21:37:15.000000000 +0100
+++ ./views.py	2013-02-12 22:03:38.000000000 +0100
@@ -1,23 +1,19 @@
 # coding: utf-8
 
-from django.contrib.auth.models import User
 from django.shortcuts import render, get_object_or_404
 from django.contrib.auth.decorators import login_required
 from django.db import models
 from django.http import Http404
 from django import forms
 from django.forms.models import inlineformset_factory, BaseInlineFormSet
-from django.core import serializers
-import hashlib
 
 from django.core.mail import send_mail                                        
 
-from datetime import datetime
 import time
 
 from gestioncof.decorators import cof_required, buro_required
-from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution
-from bda.algorithm import Algorithm
+from bda3.models import Spectacle, Participant, ChoixSpectacle, Attribution
+from bda3.algorithm import Algorithm
 
 class BaseBdaFormSet(BaseInlineFormSet):
     def clean(self):
@@ -37,7 +33,7 @@ class BaseBdaFormSet(BaseInlineFormSet):
                 raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.")
             spectacles.append(spectacle)
 
-@cof_required
+@buro_required
 def etat_places(request):
     spectacles1 = ChoixSpectacle.objects.all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle'))
     spectacles2 = ChoixSpectacle.objects.filter(double = True).all().values('spectacle','spectacle__title').annotate(total = models.Count('spectacle'))
@@ -46,93 +42,47 @@ def etat_places(request):
     total = 0
     for spectacle in spectacles:
         spectacle.total = 0
-        spectacle.ratio = -1.0
         spectacles_dict[spectacle.id] = spectacle
     for spectacle in spectacles1:
         spectacles_dict[spectacle["spectacle"]].total += spectacle["total"]
-        spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots)
         total += spectacle["total"]  
     for spectacle in spectacles2:
         spectacles_dict[spectacle["spectacle"]].total += spectacle["total"]
-        spectacles_dict[spectacle["spectacle"]].ratio = spectacles_dict[spectacle["spectacle"]].total/float(spectacles_dict[spectacle["spectacle"]].slots)
         total += spectacle["total"]  
     return render(request, "etat-places.html", {"spectacles": spectacles, "total": total})
 
-def _hash_queryset(queryset):
-    data = serializers.serialize("json", queryset)
-    hasher = hashlib.sha256()
-    hasher.update(data)
-    return hasher.hexdigest()
-
-@cof_required
-def places(request):
-    participant, created = Participant.objects.get_or_create(user = request.user)
-    places = participant.attribution_set.order_by("spectacle__date", "spectacle").all()
-    total = sum([place.spectacle.price for place in places])
-    filtered_places = []
-    places_dict = {}
-    spectacles = []
-    dates = []
-    warning = False
-    for place in places:
-        if place.spectacle in spectacles:
-            places_dict[place.spectacle].double = True
-        else:
-            place.double = False
-            places_dict[place.spectacle] = place
-            spectacles.append(place.spectacle)
-            filtered_places.append(place)
-            date = place.spectacle.date.date()
-            if date in dates:
-                warning = True
-            else:
-                dates.append(date)
-    return render(request, "resume_places.html",
-                  {"participant": participant,
-                   "places": filtered_places,
-                   "total": total,
-                   "warning": warning})
-
 @cof_required
 def inscription(request):
-    if datetime.now() > datetime(2013, 10, 6, 23, 59):
-        participant, created = Participant.objects.get_or_create(user = request.user)
-        choices = participant.choixspectacle_set.order_by("priority").all()
-        return render(request, "resume_inscription.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 7 octobre !", "choices": choices})
+    if time.time() > 1354921200:
+        return render(request, "error.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 6 octobre dans la soirée "})
     BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet)
     participant, created = Participant.objects.get_or_create(user = request.user)
     success = False
-    stateerror = False
     if request.method == "POST":
-        dbstate = _hash_queryset(participant.choixspectacle_set.all())
-        if "dbstate" in request.POST and dbstate != request.POST["dbstate"]:
-            stateerror = True
+        formset = BdaFormSet(request.POST, instance = participant)
+        if formset.is_valid():
+            #ChoixSpectacle.objects.filter(participant = participant).delete()
+            formset.save()
+            success = True
             formset = BdaFormSet(instance = participant)
-        else:
-            formset = BdaFormSet(request.POST, instance = participant)
-            if formset.is_valid():
-                #ChoixSpectacle.objects.filter(participant = participant).delete()
-                formset.save()
-                success = True
-                formset = BdaFormSet(instance = participant)
     else:
         formset = BdaFormSet(instance = participant)
-    dbstate = _hash_queryset(participant.choixspectacle_set.all())
     total_price = 0
     for choice in participant.choixspectacle_set.all():
         total_price += choice.spectacle.price
         if choice.double: total_price += choice.spectacle.price
-    return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror})
+    return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price})
+
+Spectacle.deficit = lambda x: (x.slots-x.nrequests)*x.price
 
 def do_tirage(request):
     form = TokenForm(request.POST)
     if not form.is_valid():
         return tirage(request)
-    start = time.time()
     data = {}
-    shows = Spectacle.objects.select_related().all()
+    shows = Spectacle.objects.all()
     members = Participant.objects.all()
-    choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all()
+    choices = ChoixSpectacle.objects.all()
     algo = Algorithm(shows, members, choices)
     results = algo(form.cleaned_data["token"])
     total_slots = 0
@@ -149,8 +99,8 @@ def do_tirage(request):
     total_sold = 0
     total_deficit = 0
     opera_deficit = 0
-    for (show, members, _) in results:
-        deficit = (show.slots - len(members)) * show.price
+    for show in shows:
+        deficit = show.deficit()
         total_sold += show.slots * show.price
         if deficit >= 0:
             if u"Opéra" in show.location.name:
@@ -159,23 +109,18 @@ def do_tirage(request):
     data["total_sold"] = total_sold - total_deficit
     data["total_deficit"] = total_deficit
     data["opera_deficit"] = opera_deficit
-    data["duration"] = time.time() - start
     if request.user.is_authenticated():
         members2 = {}
-        members_uniq = {} # Participant objects are not shared accross spectacle results,
-                          # So assign a single object for each Participant id
         for (show, members, _) in results:
             for (member, _, _, _) in members:
-                if member.id not in members_uniq:
-                    members_uniq[member.id] = member
+                if member not in members2:
                     members2[member] = []
                     member.total = 0
-                member = members_uniq[member.id]
                 members2[member].append(show)
                 member.total += show.price
         members2 = members2.items()
         data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name)
-        if False and request.user.username in ["seguin", "harazi"]:
+        if False and request.user.username == "seguin":
             Attribution.objects.all().delete()
             for (show, members, _) in results:
                 for (member, _, _, _) in members:
@@ -220,7 +165,7 @@ Je souhaite revendre %s pour %s le %s (%
 Contactez moi par email si vous êtes intéressés !
 
 %s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email)
-    send_mail("%s" % spectacle, mail,
+    send_mail("Revente de place: %s" % spectacle, mail,
               request.user.email, ["bda-revente@lists.ens.fr"],
               fail_silently = True)
     return render(request, "bda-success.html", {"show": spectacle, "places": places})
Only in .: views.py~
