forked from DGNum/gestioCOF
422 lines
19 KiB
Text
422 lines
19 KiB
Text
|
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~
|