Suppression des vieux dossiers

This commit is contained in:
Martin Pépin 2016-06-01 16:07:19 +02:00
parent ac0346d69f
commit 7c7488f168
35 changed files with 0 additions and 2676 deletions

View file

View file

@ -1,177 +0,0 @@
# coding: utf-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 bda2.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution
class ChoixSpectacleInline(admin.TabularInline):
model = ChoixSpectacle
sortable_field_name = "priority"
class AttributionInline(admin.TabularInline):
model = Attribution
class ParticipantAdmin(admin.ModelAdmin):
#inlines = [ChoixSpectacleInline]
inlines = [AttributionInline]
def get_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"
nb_places.short_description = "Nombre de places"
def total(self, obj):
tot = obj.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",)
search_fields = ('user__username', 'user__first_name', 'user__last_name')
actions = ['send_attribs',]
actions_on_bottom = True
list_per_page = 400
def send_choices(self, request, queryset):
for member in queryset.all():
choices = member.choixspectacle_set.order_by('priority').all()
if len(choices) == 0:
continue
mail = u"""Cher(e) %s,
Voici tes choix de spectacles tels que notre système les a enregistrés :\n\n""" % member.user.get_full_name()
next_rank = 1
member_shows = {}
for choice in choices:
if choice.spectacle in member_shows: continue
else: member_shows[choice.spectacle] = True
extra = ""
if choice.double:
extra += u" ; deux places"
if choice.autoquit:
extra += u" ; désistement automatique"
mail += u"- Choix %d : %s%s\n" % (next_rank, choice.spectacle, extra)
next_rank += 1
mail += u"""\nSi cette liste est incorrecte, merci de nous contacter au plus vite (avant samedi 6 octobre 18h).
Artistiquement,
Le BdA"""
send_mail ("Choix de spectacles (BdA du COF)", mail,
"bda@ens.fr", [member.user.email],
fail_silently = True)
count = len(queryset.all())
if count == 1:
message_bit = u"1 membre a"
plural = ""
else:
message_bit = u"%d membres ont" % count
plural = "s"
self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural))
send_choices.short_description = u"Envoyer les choix par mail"
def send_attribs(self, request, queryset):
for member in queryset.all():
attribs = member.attributions.all()
if len(attribs) == 0:
mail = u"""Cher-e %s,
Tu t'es inscrit-e pour le tirage au sort du BdA. Malheureusement, tu n'as
obtenu aucune place.
Nous sommes conscients que le nombre de places proposées lors de ce tirage
au sort est très restreint, mais nous sommes limités par les quotas que
nous imposent les théâtres.
Nous proposons cependant de nombreuses offres hors-tirage tout au long de
l'année, et nous t'invitons à nous contacter si l'une d'entre elles t'intéresse !
--
Le (nouveau) Bureau des Arts
(Thomas, Caroline, Antonin, Cécile, Hugo)
"""
name = member.user.get_full_name()
mail = mail % name
else:
mail = u"""Cher-e %s,
Tu t'es inscrit-e pour le tirage au sort du BdA. Tu as été sélectionné-e
pour les spectacles suivants :
%s
Nous sommes conscients que le nombre de places proposées lors de ce tirage
au sort est très restreint, mais nous sommes limités par les quotas que
nous imposent les théâtres.
*Paiement*
L'intégralité de ces places de spectacles est à régler à partir du lundi
18 janvier et AVANT le vendredi 22 janvier, 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. Il est possible de payer par carte, chèque ou en espèces.
*Mode de retrait des places*
Lors du paiement, nous vous donnerons les places physiques que nous possédons, et vous indiquerons
quelles places sont sur listing, à retirer le soir même de la représentation. Nous vous enverrons un mail de rappel quelques jours avant les spectacles.
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 est accessible
directement sur votre compte GestioCOF.
En vous souhaitant de belles représentations,
--
Le (nouveau) Bureau des Arts
(Thomas, Caroline, Antonin, Cécile, Hugo)
"""
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 ("[BdA] Résultats du tirage au sort", mail,
"bda@ens.fr", [member.user.email],
fail_silently = True)
count = len(queryset.all())
if count == 1:
message_bit = u"1 membre a"
plural = ""
else:
message_bit = u"%d membres ont" % count
plural = "s"
self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural))
send_attribs.short_description = u"Envoyer les résultats par mail"
class AttributionAdmin(admin.ModelAdmin):
def paid(self, obj):
return obj.participant.paid
paid.short_description = 'A payé'
paid.boolean = True
list_display = ("id", "spectacle", "participant", "given", "paid")
search_fields = ('spectacle__title', 'participant__user__username', 'participant__user__first_name', 'participant__user__last_name')
import autocomplete_light
class ChoixSpectacleAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[])
list_display = ("participant", "spectacle", "priority", "double", "autoquit")
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(Salle)
admin.site.register(Participant, ParticipantAdmin)
admin.site.register(Attribution, AttributionAdmin)
admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin)

View file

@ -1,104 +0,0 @@
# coding: utf-8
from django.conf import settings
from django.db.models import Max
import random
class Algorithm(object):
shows = None
ranks = None
origranks = None
double = None
def __init__(self, shows, members, choices):
"""Initialisation :
- on aggrège toutes les demandes pour chaque spectacle dans
show.requests
- on crée des tables de demandes pour chaque personne, afin de
pouvoir modifier les rankings"""
self.max_group = 2 * choices.aggregate(Max('priority'))['priority__max']
self.shows = []
showdict = {}
for show in shows:
show.nrequests = 0
showdict[show] = show
show.requests = []
self.shows.append(show)
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])
def IncrementRanks(self, member, currank, increment = 1):
for show in self.ranks[member]:
if self.ranks[member][show] > currank:
self.ranks[member][show] -= increment
def appendResult(self, l, member, show):
l.append((member,
self.ranks[member][show],
self.origranks[member][show],
self.choices[member][show].double))
"""
Pour les 2 Walkyries: c'est Sandefer
Pour les 4 places pour l'Oratorio c'est Maxence Arutkin
"""
def __call__(self, seed):
random.seed(seed)
results = []
shows = sorted(self.shows, key = lambda x: float(x.nrequests) / x.slots, reverse = True)
for show in shows:
# On regroupe tous les gens ayant le même rang
groups = dict([(i, []) for i in range(1, self.max_group + 1)])
for member in show.requests:
if self.ranks[member][show] == 0:
raise RuntimeError, (member, show.title)
groups[self.ranks[member][show]].append(member)
# On passe à l'attribution
winners = []
losers = []
for i in range(1, self.max_group + 1):
group = list(groups[i])
random.shuffle(group)
for member in group:
if self.choices[member][show].double: # double
if len(winners) + 1 < show.slots:
self.appendResult(winners, member, show)
self.appendResult(winners, member, show)
elif not self.choices[member][show].autoquit and len(winners) < show.slots:
self.appendResult(winners, member, show)
self.appendResult(losers, member, show)
else:
self.appendResult(losers, member, show)
self.appendResult(losers, member, show)
self.IncrementRanks(member, i, 2)
else: # simple
if len(winners) < show.slots:
self.appendResult(winners, member, show)
else:
self.appendResult(losers, member, show)
self.IncrementRanks(member, i)
results.append((show,winners,losers))
return results

View file

@ -1,9 +0,0 @@
import autocomplete_light
from bda.models import Participant, Spectacle
autocomplete_light.register(Participant, search_fields=('user__username','user__first_name','user__last_name'),
autocomplete_js_attributes={'placeholder': 'participant...'})
autocomplete_light.register(Spectacle, search_fields=('title',),
autocomplete_js_attributes={'placeholder': 'spectacle...'})

View file

@ -1,421 +0,0 @@
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 bda2.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 bda2.models import Spectacle, Participant, ChoixSpectacle, Attribution
+from bda2.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~

View file

@ -1,109 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Attribution',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('given', models.BooleanField(default=False, verbose_name='Donn\xe9e')),
],
),
migrations.CreateModel(
name='ChoixSpectacle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('priority', models.PositiveIntegerField(verbose_name=b'Priorit\xc3\xa9')),
('double', models.BooleanField(default=False, verbose_name=b'Deux places<sup>1</sup>')),
('autoquit', models.BooleanField(default=False, verbose_name=b'Abandon<sup>2</sup>')),
],
options={
'ordering': ('priority',),
'verbose_name': 'voeu',
'verbose_name_plural': 'voeux',
},
),
migrations.CreateModel(
name='Participant',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('paid', models.BooleanField(default=False, verbose_name='A pay\xe9')),
('paymenttype', models.CharField(blank=True, max_length=6, verbose_name='Moyen de paiement', choices=[(b'cash', 'Cash'), (b'cb', b'CB'), (b'cheque', 'Ch\xe8que'), (b'autre', 'Autre')])),
],
),
migrations.CreateModel(
name='Salle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=300, verbose_name=b'Nom')),
('address', models.TextField(verbose_name=b'Adresse')),
],
),
migrations.CreateModel(
name='Spectacle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=300, verbose_name=b'Titre')),
('date', models.DateTimeField(verbose_name=b'Date & heure')),
('description', models.TextField(verbose_name=b'Description', blank=True)),
('slots_description', models.TextField(verbose_name=b'Description des places', blank=True)),
('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)),
('slots', models.IntegerField(verbose_name=b'Places')),
('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')),
('location', models.ForeignKey(to='bda2.Salle')),
],
options={
'ordering': ('priority', 'date', 'title'),
'verbose_name': 'Spectacle',
},
),
migrations.AddField(
model_name='participant',
name='attributions',
field=models.ManyToManyField(related_name='attributed_to', through='bda2.Attribution', to='bda2.Spectacle'),
),
migrations.AddField(
model_name='participant',
name='choices',
field=models.ManyToManyField(related_name='chosen_by', through='bda2.ChoixSpectacle', to='bda2.Spectacle'),
),
migrations.AddField(
model_name='participant',
name='user',
field=models.OneToOneField(related_name='participants2', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='choixspectacle',
name='participant',
field=models.ForeignKey(to='bda2.Participant'),
),
migrations.AddField(
model_name='choixspectacle',
name='spectacle',
field=models.ForeignKey(related_name='participants', to='bda2.Spectacle'),
),
migrations.AddField(
model_name='attribution',
name='participant',
field=models.ForeignKey(to='bda2.Participant'),
),
migrations.AddField(
model_name='attribution',
name='spectacle',
field=models.ForeignKey(related_name='attribues', to='bda2.Spectacle'),
),
migrations.AlterUniqueTogether(
name='choixspectacle',
unique_together=set([('participant', 'spectacle')]),
),
]

View file

@ -1,78 +0,0 @@
# 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 _
from django.db.models.signals import post_save
class Salle (models.Model):
name = models.CharField ("Nom", max_length = 300)
address = models.TextField ("Adresse")
def __unicode__ (self):
return self.name
class Spectacle (models.Model):
title = models.CharField ("Titre", max_length = 300)
date = models.DateTimeField ("Date & heure")
location = models.ForeignKey(Salle)
description = models.TextField ("Description", 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)
class Meta:
verbose_name = "Spectacle"
ordering = ("priority", "date","title",)
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)
PAYMENT_TYPES = (
("cash",u"Cash"),
("cb","CB"),
("cheque",u"Chèque"),
("autre",u"Autre"),
)
class Participant (models.Model):
user = models.OneToOneField(User, 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)
paymenttype = models.CharField(u"Moyen de paiement", max_length = 6, choices = PAYMENT_TYPES, blank = True)
def __unicode__ (self):
return u"%s" % (self.user)
class ChoixSpectacle (models.Model):
participant = models.ForeignKey(Participant)
spectacle = models.ForeignKey(Spectacle, related_name = "participants")
priority = models.PositiveIntegerField("Priorité")
double = models.BooleanField("Deux places<sup>1</sup>",default=False)
autoquit = models.BooleanField("Abandon<sup>2</sup>",default=False)
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(u"Donnée", default = False)
def __unicode__ (self):
return u"%s -- %s" % (self.participant, self.spectacle)

View file

@ -1,10 +0,0 @@
form#tokenform {text-align: center; font-size: 2em;}
label {margin-right: 10px; vertical-align: top;}
form#tokenform textarea {font-size: 2em; width: 350px; height: 200px; font-family: 'Droif Serif', serif;}
input {width: 400px; font-size: 2em;}
ul.losers {display: inline; margin: 0; padding: 0;}
ul.losers li {display: inline;}
span.details {font-size: 0.7em;}
table {border: 1px solid black; border-collapse: collapse;}
td {border: 1px solid black; padding: 2px;}
.attribresult {margin: 10px 0px;}

View file

@ -1,27 +0,0 @@
{% extends "bda-attrib.html" %}
{% block extracontent %}
<h1>Attribution (détails)</h1>
<h2>Token : {{ token }}</h2>
<h2>Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h2>
<table>
{% for member, shows in members2 %}
<tr>
<td>{{ member.user.get_full_name }}</td>
<td>{{ member.user.email }}</td>
<td>Total: {{ member.total }}€</td>
<td style="width: 120px;"></td>
</tr>
{% for show in shows %}
<tr>
<td></td>
<td></td>
<td>{{ show }}</td>
<td></td>
</tr>
{% endfor %}
{% endfor %}
</table>
{% endblock %}

View file

@ -1,41 +0,0 @@
{% extends "base_title.html" %}
{% load staticfiles %}
{% block extra_head %}
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
{% endblock %}
{% block realcontent %}
<h1>Attribution</h1>
<h2>Token : {{ token }}</h2>
<h2>Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h2>
{% if user.profile.is_buro %}<h2>Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €</h2>{% endif %}
{% for show, members, losers in results %}
<div class="attribresult">
<h2>{{ show.title }} - {{ show.date_no_seconds }} @ {{ show.location }}</h2>
<p>
<strong>{{ show.nrequests }} demandes pour {{ show.slots }} places</strong>
{{ show.price }}€ par place{% if user.profile.is_buro and show.nrequests < show.slots %}, {{ show.deficit }} de déficit{% endif %}
</p>
Places :
<ul>
{% for member, rank, origrank, double in members %}
<li>{{ member.user.get_full_name }} <span class="details">(souhait {{ origrank }} &mdash; rang {{ rank }})</span></li>
{% endfor %}
</ul>
Déçus :
{% if not losers %}/{% else %}
<ul class="losers">
{% for member, rank, origrank, double in losers %}
{% if not forloop.first %} ; {% endif %}
<li>{{ member.user.get_full_name }} <span class="details">(souhait {{ origrank }} &mdash; rang {{ rank }})</span></li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
{% block extracontent %}
{% endblock %}
{% endblock %}

View file

@ -1,7 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>{{ spectacle }}</h2>
<textarea style="width: 100%; height: 100px; margin-top: 10px;">
{% for attrib in spectacle.attribues.all %}{{ attrib.participant.user.email }}, {% endfor %}</textarea>
{% endblock %}

View file

@ -1,6 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h1><strong>Nope</strong></h1>
<p>Avant de revendre des places, il faut aller les payer !</p>
{% endblock %}

View file

@ -1,26 +0,0 @@
{% extends "base_title.html" %}
{% load staticfiles %}
{% block extra_head %}
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
{% endblock %}
{% block realcontent %}
<h1>Revente de place</h1>
<form action="" method="post" id="resellform">
{% csrf_token %}
{% if form.spectacle.errors %}<ul class="errorlist"><li>Sélectionnez un spetacle</li></ul>{% endif %}
<p>
<code>
Bonjour,<br />
<br />
Je souhaite revendre {{ form.count }} place(s) pour {{ form.spectacle }}.<br />
Contactez-moi par email si vous êtes intéressé !<br />
<br />
{{ user.get_full_name }} ({{ user.email }})
</code>
</p>
<input type="submit" value="Envoyer" />
</form>
{% endblock %}

View file

@ -1,12 +0,0 @@
{% extends "base_title.html" %}
{% load staticfiles %}
{% block extra_head %}
<link type="text/css" rel="stylesheet" href="{% static "css/bda.css" %}" />
{% endblock %}
{% block realcontent %}
<h1>Revente de place</h1>
<p class="success">Votre offre de revente de {{ places }} pour {{ show.title }} le {{ show.date_no_seconds }} ({{ show.location }}) à {{ show.price }}€ a bien été envoyée.</p>
{% endblock %}

View file

@ -1,13 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>Tirage au sort du BdA</h2>
<form action="" method="post" id="tokenform">
{% csrf_token %}
<strong>La graine :</strong>
<div>
{{ form.token }}
</div>
<input type="submit" value="Go" />
</form>
{% endblock %}

View file

@ -1,7 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>Impayés</h2>
<textarea style="width: 100%; height: 100px; margin-top: 10px;">
{% for participant in unpaid %}{{ participant.user.email }}, {% endfor %}</textarea>
{% endblock %}

View file

@ -1,11 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>Etat des inscriptions BDA</h2>
<ul>
{% for spectacle in spectacles %}
<li>{{ spectacle.title }} (<span style="font-size: 0.5em;">{{ spectacle.date_no_seconds }}, {{ spectacle.location }}</span>, {{ spectacle.slots }} places) : <strong>{{ spectacle.total }} demandes</strong></li>
{% endfor %}
</ul>
<strong>Total : <u>{{ total }} demandes</u></strong>
{% endblock %}

View file

@ -1,116 +0,0 @@
{% extends "base_title.html" %}
{% block extra_head %}
<link href="{{ STATIC_URL }}grappelli/jquery/ui/css/custom-theme/jquery-ui-1.8.custom.css" rel="stylesheet" type="text/css" media="screen" title="no title" charset="utf-8" />
<script src="{{ STATIC_URL }}grappelli/jquery/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="{{ STATIC_URL }}grappelli/jquery/ui/js/jquery-ui-1.8.15.custom.min.js" type="text/javascript"></script>
<link href="{{ STATIC_URL }}grappelli/css/tools.css" rel="stylesheet" type="text/css" />
<link href="{{ STATIC_URL }}grappelli/css/jquery-ui-grappelli-extensions.css" rel="stylesheet" type="text/css" />
{% endblock %}
{% block realcontent %}
<script type="text/javascript">
var django = {
"jQuery": jQuery.noConflict(true)
};
(function($) {
cloneMore = function(selector, type) {
var newElement = $(selector).clone(true);
var total = $('#id_' + type + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
});
newElement.find('label').each(function() {
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
$(this).attr('for', newFor);
});
total++;
$('#id_' + type + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
deleteButtonHandler = function(elem) {
elem.bind("click", function() {
var deleteInput = $(this).prev().prev(),
form = $(this).parents(".dynamic-form").first();
// callback
// toggle options.predeleteCssClass and toggle checkbox
if (form.hasClass("has_original")) {
form.toggleClass("predelete");
if (deleteInput.attr("checked")) {
deleteInput.attr("checked", false);
} else {
deleteInput.attr("checked", true);
}
}
// callback
});
};
$(document).ready(function($) {
deleteButtonHandler($("table#bda_formset tbody.bda_formset_content").find("a.delete-handler"));
$("table#bda_formset tbody.bda_formset_content").sortable({
handle: "a.drag-handler",
items: "tr",
axis: "y",
appendTo: 'body',
forceHelperSize: true,
placeholder: 'ui-sortable-placeholder',
forcePlaceholderSize: true,
containment: 'form#bda_form',
tolerance: 'pointer',
start: function(evt, ui) {
var template = "",
len = ui.item.children("td").length;
for (var i = 0; i < len; i++) {
template += "<td style='height:" + (ui.item.outerHeight() + 12 ) + "px' class='placeholder-cell'>&nbsp;</td>"
}
template += "";
ui.placeholder.html(template);
},
stop: function(evt, ui) {
// Toggle div.table twice to remove webkits border-spacing bug
$("table#bda_formset").toggle().toggle();
},
});
$("#bda_form").bind("submit", function(){
var sortable_field_name = "priority";
var i = 1;
$(".bda_formset_content").find("tr").each(function(){
var fields = $(this).find("td :input[value]"),
select = $(this).find("td select");
if (select.val() && fields.serialize()) {
$(this).find("input[name$='"+sortable_field_name+"']").val(i);
i++;
}
});
});
});
})(django.jQuery);
</script>
<h2>Inscription au tirage au sort du BDA</h2>
{% if success %}
<p class="success">Votre inscription a été mise à jour avec succès !</p>
{% endif %}
<form id="bda_form" method="post" action="{% url 'bda-tirage-inscription' %}">
{% csrf_token %}
{% include "inscription-formset.html" %}
<input type="button" class="btn-addmore" value="Ajouter un autre v&oelig;u" id="add_more">
<script>
django.jQuery('#add_more').click(function() {
cloneMore('tbody.bda_formset_content tr:last-child', 'choixspectacle_set');
});
</script>
<input type="submit" class="btn-submit" value="Enregistrer" />
Prix total actuel : {{ total_price }}€
<hr />
<p class="footnotes">
<sup>1</sup>: demander deux places pour ce spectable<br />
<sup>2</sup>: abandonner une place si impossible d'en obtenir une seconde pour ce spectacle (si vous avez coché l'option <tt>Deux places</tt> pour ce spectacle)<br />
<sup>3</sup>: cette liste de v&oelig;u est ordonnée (du plus important au moins important), pour ajuster la priorité vous pouvez déplacer chaque v&oelig;u<br />
</p>
</form>
{% endblock %}

View file

@ -1,40 +0,0 @@
{{ formset.non_form_errors.as_ul }}
<table id="bda_formset" class="form">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
{% if field.name != "DELETE" and field.name != "priority" %}
<th class="bda-field-{{ field.name }}">{{ field.label|safe|capfirst }}</th>
{% endif %}
{% endfor %}
<th><sup>3</sup></th>
</tr></thead>
<tbody class="bda_formset_content">
{% endif %}
<tr class="{% cycle row1,row2 %} dynamic-form {% if form.instance.pk %}has_original{% endif %}">
{% for field in form.visible_fields %}
{% if field.name != "DELETE" and field.name != "priority" %}
<td class="bda-field-{{ field.name }}">
{% if forloop.first %}
{{ form.non_field_errors }}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endif %}
{% endfor %}
<td class="tools-cell"><div class="tools">
<a href="javascript://" class="icon drag-handler" title="Déplacer"></a>
<input type="checkbox" name="{{ form.DELETE.html_name }}" style="display: none;" />
<input type="hidden" name="{{ form.priority.html_name }}" style="{{ form.priority.value }}" />
<a href="javascript://" class="icon delete-handler" title="Supprimer"></a>
</div>
<div class="spacer"></div>
</td>
</tr>
{% endfor %}
</tbody>
</table>

View file

@ -1,11 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h1><strong>Spectacles</strong></h1>
<ul>
<li><a href="{% url 'bda2-unpaid' %}">Pas payé</a></li>
{% for spectacle in object_list %}
<li><a href="{% url 'bda2-spectacle' spectacle.id %}">{{ spectacle }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -1,16 +0,0 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

View file

@ -1,248 +0,0 @@
# 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 bda2.models import Spectacle, Participant, ChoixSpectacle, Attribution
from bda2.algorithm import Algorithm
class BaseBdaFormSet(BaseInlineFormSet):
def clean(self):
"""Checks that no two articles have the same title."""
super(BaseBdaFormSet, self).clean()
if any(self.errors):
# Don't bother validating the formset unless each form is valid on its own
return
spectacles = []
for i in range(0, self.total_form_count()):
form = self.forms[i]
if not form.cleaned_data:
continue
spectacle = form.cleaned_data['spectacle']
delete = form.cleaned_data['DELETE']
if not delete and spectacle in spectacles:
raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.")
spectacles.append(spectacle)
@cof_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'))
spectacles = Spectacle.objects.all()
spectacles_dict = {}
total = 0
for spectacle in spectacles:
spectacle.total = 0
spectacle.ratio = 0.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(2016, 1, 17, 12, 00):
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 17 janvier !", "choices": choices})
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(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-bda2.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror})
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()
members = Participant.objects.all()
choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all()
algo = Algorithm(shows, members, choices)
results = algo(form.cleaned_data["token"])
total_slots = 0
total_losers = 0
for (_, members, losers) in results:
total_slots += len(members)
total_losers += len(losers)
data["total_slots"] = total_slots
data["total_losers"] = total_losers
data["shows"] = shows
data["token"] = form.cleaned_data["token"]
data["members"] = members
data["results"] = results
total_sold = 0
total_deficit = 0
opera_deficit = 0
for (show, members, _) in results:
deficit = (show.slots - len(members)) * show.price
total_sold += show.slots * show.price
if deficit >= 0:
if u"Opéra" in show.location.name:
opera_deficit += deficit
total_deficit += deficit
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
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", "fromherz", "mpepin"]:
Attribution.objects.all().delete()
for (show, members, _) in results:
for (member, _, _, _) in members:
attrib = Attribution(spectacle = show, participant = member)
attrib.save()
return render(request, "bda-attrib-extra.html", data)
else:
return render(request, "bda-attrib.html", data)
class TokenForm(forms.Form):
token = forms.CharField(widget = forms.widgets.Textarea())
@login_required
def tirage(request):
if request.POST:
form = TokenForm(request.POST)
if form.is_valid():
return do_tirage(request)
else:
form = TokenForm()
return render(request, "bda-token.html", {"form": form})
class SpectacleModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return u"%s le %s (%s) à %.02f" % (obj.title, obj.date_no_seconds(), obj.location, obj.price)
class ResellForm(forms.Form):
count = forms.ChoiceField(choices = (("1","1"),("2","2"),))
spectacle = SpectacleModelChoiceField(queryset = Spectacle.objects.none())
def __init__(self, participant, *args, **kwargs):
super(ResellForm, self).__init__(*args, **kwargs)
self.fields['spectacle'].queryset = participant.attributions.all().distinct()
def do_resell(request, form):
spectacle = form.cleaned_data["spectacle"]
count = form.cleaned_data["count"]
places = "2 places" if count == "2" else "une place"
mail = u"""Bonjour,
Je souhaite revendre %s pour %s le %s (%s) à %.02f.
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,
request.user.email, ["bda-revente@lists.ens.fr"],
fail_silently = True)
return render(request, "bda-success.html", {"show": spectacle, "places": places})
@login_required
def revente(request):
participant, created = Participant.objects.get_or_create(user = request.user)
if not participant.paid:
return render(request, "bda-notpaid.html", {})
if request.POST:
form = ResellForm(participant, request.POST)
if form.is_valid():
return do_resell(request, form)
else:
form = ResellForm(participant)
return render(request, "bda-revente.html", {"form": form})
@buro_required
def spectacle(request, spectacle_id):
spectacle = get_object_or_404(Spectacle, id = spectacle_id)
return render(request, "bda-emails.html", {"spectacle": spectacle})
@buro_required
def unpaid(request):
return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid = False).all()})

View file

View file

@ -1,180 +0,0 @@
# coding: utf-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 bda3.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution
class ChoixSpectacleInline(admin.TabularInline):
model = ChoixSpectacle
sortable_field_name = "priority"
class AttributionInline(admin.TabularInline):
model = Attribution
class ParticipantAdmin(admin.ModelAdmin):
#inlines = [ChoixSpectacleInline]
inlines = [AttributionInline]
def get_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"
nb_places.short_description = "Nombre de places"
def total(self, obj):
tot = obj.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",)
search_fields = ('user__username', 'user__first_name', 'user__last_name')
actions = ['send_attribs',]
actions_on_bottom = True
list_per_page = 400
def send_choices(self, request, queryset):
for member in queryset.all():
choices = member.choixspectacle_set.order_by('priority').all()
if len(choices) == 0:
continue
mail = u"""Cher(e) %s,
Voici tes choix de spectacles tels que notre système les a enregistrés :\n\n""" % member.user.get_full_name()
next_rank = 1
member_shows = {}
for choice in choices:
if choice.spectacle in member_shows: continue
else: member_shows[choice.spectacle] = True
extra = ""
if choice.double:
extra += u" ; deux places"
if choice.autoquit:
extra += u" ; désistement automatique"
mail += u"- Choix %d : %s%s\n" % (next_rank, choice.spectacle, extra)
next_rank += 1
mail += u"""\nSi cette liste est incorrecte, merci de nous contacter au plus vite (avant samedi 6 octobre 18h).
Artistiquement,
Le BdA"""
send_mail ("Choix de spectacles (BdA du COF)", mail,
"bda@ens.fr", [member.user.email],
fail_silently = True)
count = len(queryset.all())
if count == 1:
message_bit = u"1 membre a"
plural = ""
else:
message_bit = u"%d membres ont" % count
plural = "s"
self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural))
send_choices.short_description = u"Envoyer les choix par mail"
def send_attribs(self, request, queryset):
for member in queryset.all():
attribs = member.attributions.all()
if len(attribs) == 0:
mail = u"""Cher-e %s,
Tu t'es inscrit-e pour le troisième tirage au sort du BdA. Nous avons le regret
de t'annoncer que tu n'as pas obtenu de place.
Nous sommes bien conscients que le nombre de places mises en jeu était
très restreint, mais les premier et deuxième tirages au sort comprenaient
déjà un nombre exceptionnel de places, et nous dépendons des limites
fixées par les théâtres partenaires pour l'obtention de places à tarif réduit.
Le système de revente des places via les mails BdA-revente reste disponible,
alors surveille tes mails.
En vous souhaitant une bonne fin de journée,
--
Le Bureau des Arts
"""
name = member.user.get_full_name()
mail = mail % name
else:
mail = u"""Cher-e %s,
Tu t'es inscrit-e pour le troisième tirage au sort du BdA. Tu as été
sélectionné-e pour les spectacles suivants :
%s
Nous sommes bien conscients que le nombre de places mises en jeu était
très restreint, mais les premier et deuxième tirages au sort comprenaient
déjà un nombre exceptionnel de places, et nous dépendons des limites fixées
par les théâtres partenaires pour l'obtention de places à tarif réduit.
*Paiement*
L'intégralité de ces places de spectacles est à régler à partir du lundi
11 avril et AVANT le 16 avril, au bureau du COF pendant les
heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h
et 20h). Si vous n'êtes pas disponible cette semaine, prévenez-nous par mail.
Attention : au-delà de cette date, les places pourront être remises en jeu.
*Mode de retrait des places*
Au moment du paiement, les places pour les spectacles de la Comédie-Française
et pour la Philarmonie vous seront remises.
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 reste disponible,
directement sur votre compte GestioCOF.
En vous souhaitant de très beaux spectacles,
--
Le Bureau des Arts
"""
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 ("[BdA] Résultats du tirage au sort", mail,
"bda@ens.fr", [member.user.email],
fail_silently = True)
count = len(queryset.all())
if count == 1:
message_bit = u"1 membre a"
plural = ""
else:
message_bit = u"%d membres ont" % count
plural = "s"
self.message_user(request, u"%s été informé%s avec succès." % (message_bit, plural))
send_attribs.short_description = u"Envoyer les résultats par mail"
class AttributionAdmin(admin.ModelAdmin):
def paid(self, obj):
return obj.participant.paid
paid.short_description = 'A payé'
paid.boolean = True
list_display = ("id", "spectacle", "participant", "given", "paid")
search_fields = ('spectacle__title', 'participant__user__username', 'participant__user__first_name', 'participant__user__last_name')
import autocomplete_light
class ChoixSpectacleAdmin(admin.ModelAdmin):
form = autocomplete_light.modelform_factory(ChoixSpectacle, exclude=[])
list_display = ("participant", "spectacle", "priority", "double", "autoquit")
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(Salle)
admin.site.register(Participant, ParticipantAdmin)
admin.site.register(Attribution, AttributionAdmin)
admin.site.register(ChoixSpectacle, ChoixSpectacleAdmin)

View file

@ -1,104 +0,0 @@
# coding: utf-8
from django.conf import settings
from django.db.models import Max
import random
class Algorithm(object):
shows = None
ranks = None
origranks = None
double = None
def __init__(self, shows, members, choices):
"""Initialisation :
- on aggrège toutes les demandes pour chaque spectacle dans
show.requests
- on crée des tables de demandes pour chaque personne, afin de
pouvoir modifier les rankings"""
self.max_group = 2 * choices.aggregate(Max('priority'))['priority__max']
self.shows = []
showdict = {}
for show in shows:
show.nrequests = 0
showdict[show] = show
show.requests = []
self.shows.append(show)
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])
def IncrementRanks(self, member, currank, increment = 1):
for show in self.ranks[member]:
if self.ranks[member][show] > currank:
self.ranks[member][show] -= increment
def appendResult(self, l, member, show):
l.append((member,
self.ranks[member][show],
self.origranks[member][show],
self.choices[member][show].double))
"""
Pour les 2 Walkyries: c'est Sandefer
Pour les 4 places pour l'Oratorio c'est Maxence Arutkin
"""
def __call__(self, seed):
random.seed(seed)
results = []
shows = sorted(self.shows, key = lambda x: float(x.nrequests) / x.slots, reverse = True)
for show in shows:
# On regroupe tous les gens ayant le même rang
groups = dict([(i, []) for i in range(1, self.max_group + 1)])
for member in show.requests:
if self.ranks[member][show] == 0:
raise RuntimeError, (member, show.title)
groups[self.ranks[member][show]].append(member)
# On passe à l'attribution
winners = []
losers = []
for i in range(1, self.max_group + 1):
group = list(groups[i])
random.shuffle(group)
for member in group:
if self.choices[member][show].double: # double
if len(winners) + 1 < show.slots:
self.appendResult(winners, member, show)
self.appendResult(winners, member, show)
elif not self.choices[member][show].autoquit and len(winners) < show.slots:
self.appendResult(winners, member, show)
self.appendResult(losers, member, show)
else:
self.appendResult(losers, member, show)
self.appendResult(losers, member, show)
self.IncrementRanks(member, i, 2)
else: # simple
if len(winners) < show.slots:
self.appendResult(winners, member, show)
else:
self.appendResult(losers, member, show)
self.IncrementRanks(member, i)
results.append((show,winners,losers))
return results

View file

@ -1,9 +0,0 @@
import autocomplete_light
from bda.models import Participant, Spectacle
autocomplete_light.register(Participant, search_fields=('user__username','user__first_name','user__last_name'),
autocomplete_js_attributes={'placeholder': 'participant...'})
autocomplete_light.register(Spectacle, search_fields=('title',),
autocomplete_js_attributes={'placeholder': 'spectacle...'})

View file

@ -1,421 +0,0 @@
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~

View file

@ -1,109 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Attribution',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('given', models.BooleanField(default=False, verbose_name='Donn\xe9e')),
],
),
migrations.CreateModel(
name='ChoixSpectacle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('priority', models.PositiveIntegerField(verbose_name=b'Priorit\xc3\xa9')),
('double', models.BooleanField(default=False, verbose_name=b'Deux places<sup>1</sup>')),
('autoquit', models.BooleanField(default=False, verbose_name=b'Abandon<sup>2</sup>')),
],
options={
'ordering': ('priority',),
'verbose_name': 'voeu',
'verbose_name_plural': 'voeux',
},
),
migrations.CreateModel(
name='Participant',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('paid', models.BooleanField(default=False, verbose_name='A pay\xe9')),
('paymenttype', models.CharField(blank=True, max_length=6, verbose_name='Moyen de paiement', choices=[(b'cash', 'Cash'), (b'cb', b'CB'), (b'cheque', 'Ch\xe8que'), (b'autre', 'Autre')])),
],
),
migrations.CreateModel(
name='Salle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=300, verbose_name=b'Nom')),
('address', models.TextField(verbose_name=b'Adresse')),
],
),
migrations.CreateModel(
name='Spectacle',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=300, verbose_name=b'Titre')),
('date', models.DateTimeField(verbose_name=b'Date & heure')),
('description', models.TextField(verbose_name=b'Description', blank=True)),
('slots_description', models.TextField(verbose_name=b'Description des places', blank=True)),
('price', models.FloatField(verbose_name=b"Prix d'une place", blank=True)),
('slots', models.IntegerField(verbose_name=b'Places')),
('priority', models.IntegerField(default=1000, verbose_name=b'Priorit\xc3\xa9')),
('location', models.ForeignKey(to='bda3.Salle')),
],
options={
'ordering': ('priority', 'date', 'title'),
'verbose_name': 'Spectacle',
},
),
migrations.AddField(
model_name='participant',
name='attributions',
field=models.ManyToManyField(related_name='attributed_to', through='bda3.Attribution', to='bda3.Spectacle'),
),
migrations.AddField(
model_name='participant',
name='choices',
field=models.ManyToManyField(related_name='chosen_by', through='bda3.ChoixSpectacle', to='bda3.Spectacle'),
),
migrations.AddField(
model_name='participant',
name='user',
field=models.OneToOneField(related_name='participants3', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='choixspectacle',
name='participant',
field=models.ForeignKey(to='bda3.Participant'),
),
migrations.AddField(
model_name='choixspectacle',
name='spectacle',
field=models.ForeignKey(related_name='participants', to='bda3.Spectacle'),
),
migrations.AddField(
model_name='attribution',
name='participant',
field=models.ForeignKey(to='bda3.Participant'),
),
migrations.AddField(
model_name='attribution',
name='spectacle',
field=models.ForeignKey(related_name='attribues', to='bda3.Spectacle'),
),
migrations.AlterUniqueTogether(
name='choixspectacle',
unique_together=set([('participant', 'spectacle')]),
),
]

View file

@ -1,78 +0,0 @@
# 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 _
from django.db.models.signals import post_save
class Salle (models.Model):
name = models.CharField ("Nom", max_length = 300)
address = models.TextField ("Adresse")
def __unicode__ (self):
return self.name
class Spectacle (models.Model):
title = models.CharField ("Titre", max_length = 300)
date = models.DateTimeField ("Date & heure")
location = models.ForeignKey(Salle)
description = models.TextField ("Description", 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)
class Meta:
verbose_name = "Spectacle"
ordering = ("priority", "date","title",)
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)
PAYMENT_TYPES = (
("cash",u"Cash"),
("cb","CB"),
("cheque",u"Chèque"),
("autre",u"Autre"),
)
class Participant (models.Model):
user = models.OneToOneField(User, related_name = "participants3")
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)
paymenttype = models.CharField(u"Moyen de paiement", max_length = 6, choices = PAYMENT_TYPES, blank = True)
def __unicode__ (self):
return u"%s" % (self.user)
class ChoixSpectacle (models.Model):
participant = models.ForeignKey(Participant)
spectacle = models.ForeignKey(Spectacle, related_name = "participants")
priority = models.PositiveIntegerField("Priorité")
double = models.BooleanField("Deux places<sup>1</sup>",default=False)
autoquit = models.BooleanField("Abandon<sup>2</sup>",default=False)
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(u"Donnée", default = False)
def __unicode__ (self):
return u"%s -- %s" % (self.participant, self.spectacle)

View file

@ -1,10 +0,0 @@
form#tokenform {text-align: center; font-size: 2em;}
label {margin-right: 10px; vertical-align: top;}
form#tokenform textarea {font-size: 2em; width: 350px; height: 200px; font-family: 'Droif Serif', serif;}
input {width: 400px; font-size: 2em;}
ul.losers {display: inline; margin: 0; padding: 0;}
ul.losers li {display: inline;}
span.details {font-size: 0.7em;}
table {border: 1px solid black; border-collapse: collapse;}
td {border: 1px solid black; padding: 2px;}
.attribresult {margin: 10px 0px;}

View file

@ -1,11 +0,0 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h1><strong>Spectacles</strong></h1>
<ul>
<li><a href="{% url 'bda3-unpaid' %}">Pas payé</a></li>
{% for spectacle in object_list %}
<li><a href="{% url 'bda3-spectacle' spectacle.id %}">{{ spectacle }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -1,16 +0,0 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

View file

@ -1,249 +0,0 @@
# 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 bda3.models import Spectacle, Participant, ChoixSpectacle, Attribution
from bda3.algorithm import Algorithm
class BaseBdaFormSet(BaseInlineFormSet):
def clean(self):
"""Checks that no two articles have the same title."""
super(BaseBdaFormSet, self).clean()
if any(self.errors):
# Don't bother validating the formset unless each form is valid on its own
return
spectacles = []
for i in range(0, self.total_form_count()):
form = self.forms[i]
if not form.cleaned_data:
continue
spectacle = form.cleaned_data['spectacle']
delete = form.cleaned_data['DELETE']
if not delete and spectacle in spectacles:
raise forms.ValidationError("Vous ne pouvez pas vous inscrire deux fois pour le même spectacle.")
spectacles.append(spectacle)
@cof_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'))
spectacles = Spectacle.objects.all()
spectacles_dict = {}
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(2016, 4, 10, 11, 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 très bientôt !", "choices": choices})
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(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-bda3.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror})
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()
members = Participant.objects.all()
choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all()
algo = Algorithm(shows, members, choices)
results = algo(form.cleaned_data["token"])
total_slots = 0
total_losers = 0
for (_, members, losers) in results:
total_slots += len(members)
total_losers += len(losers)
data["total_slots"] = total_slots
data["total_losers"] = total_losers
data["shows"] = shows
data["token"] = form.cleaned_data["token"]
data["members"] = members
data["results"] = results
total_sold = 0
total_deficit = 0
opera_deficit = 0
for (show, members, _) in results:
deficit = (show.slots - len(members)) * show.price
total_sold += show.slots * show.price
if deficit >= 0:
if u"Opéra" in show.location.name:
opera_deficit += deficit
total_deficit += deficit
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
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", "fromherz", "mpepin"]:
Attribution.objects.all().delete()
for (show, members, _) in results:
for (member, _, _, _) in members:
attrib = Attribution(spectacle = show, participant = member)
attrib.save()
return render(request, "bda-attrib-extra.html", data)
else:
return render(request, "bda-attrib.html", data)
class TokenForm(forms.Form):
token = forms.CharField(widget = forms.widgets.Textarea())
@login_required
def tirage(request):
if request.POST:
form = TokenForm(request.POST)
if form.is_valid():
return do_tirage(request)
else:
form = TokenForm()
return render(request, "bda-token.html", {"form": form})
class SpectacleModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return u"%s le %s (%s) à %.02f" % (obj.title, obj.date_no_seconds(), obj.location, obj.price)
class ResellForm(forms.Form):
count = forms.ChoiceField(choices = (("1","1"),("2","2"),))
spectacle = SpectacleModelChoiceField(queryset = Spectacle.objects.none())
def __init__(self, participant, *args, **kwargs):
super(ResellForm, self).__init__(*args, **kwargs)
self.fields['spectacle'].queryset = participant.attributions.all().distinct()
def do_resell(request, form):
spectacle = form.cleaned_data["spectacle"]
count = form.cleaned_data["count"]
places = "2 places" if count == "2" else "une place"
mail = u"""Bonjour,
Je souhaite revendre %s pour %s le %s (%s) à %.02f.
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,
request.user.email, ["bda-revente@lists.ens.fr"],
fail_silently = True)
return render(request, "bda-success.html", {"show": spectacle, "places": places})
@login_required
def revente(request):
participant, created = Participant.objects.get_or_create(user = request.user)
if not participant.paid:
return render(request, "bda-notpaid.html", {})
if request.POST:
form = ResellForm(participant, request.POST)
if form.is_valid():
return do_resell(request, form)
else:
form = ResellForm(participant)
return render(request, "bda-revente.html", {"form": form})
@buro_required
def spectacle(request, spectacle_id):
spectacle = get_object_or_404(Spectacle, id = spectacle_id)
return render(request, "bda-emails.html", {"spectacle": spectacle})
@buro_required
def unpaid(request):
return render(request, "bda-unpaid.html", {"unpaid": Participant.objects.filter(paid = False).all()})