Grod commit dégueux avec une tonne de trucs. Berk.
This commit is contained in:
parent
d5b3d3f958
commit
64b8ee4133
17 changed files with 536 additions and 209 deletions
0
apache/django.wsgi
Executable file → Normal file
0
apache/django.wsgi
Executable file → Normal file
68
bda/admin.py
68
bda/admin.py
|
@ -4,7 +4,7 @@ from django.core.mail import send_mail
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum, Count
|
||||||
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution
|
from bda.models import Spectacle, Salle, Participant, ChoixSpectacle, Attribution
|
||||||
|
|
||||||
class ChoixSpectacleInline(admin.TabularInline):
|
class ChoixSpectacleInline(admin.TabularInline):
|
||||||
|
@ -17,13 +17,18 @@ class AttributionInline(admin.TabularInline):
|
||||||
class ParticipantAdmin(admin.ModelAdmin):
|
class ParticipantAdmin(admin.ModelAdmin):
|
||||||
#inlines = [ChoixSpectacleInline]
|
#inlines = [ChoixSpectacleInline]
|
||||||
inlines = [AttributionInline]
|
inlines = [AttributionInline]
|
||||||
|
def queryset(self, request):
|
||||||
|
return Participant.objects.annotate(nb_places = Count('attributions'),
|
||||||
|
total = Sum('attributions__price'))
|
||||||
def nb_places(self, obj):
|
def nb_places(self, obj):
|
||||||
return len(obj.attribution_set.all())
|
return obj.nb_places
|
||||||
|
nb_places.admin_order_field = "nb_places"
|
||||||
nb_places.short_description = "Nombre de places"
|
nb_places.short_description = "Nombre de places"
|
||||||
def total(self, obj):
|
def total(self, obj):
|
||||||
tot = obj.attributions.aggregate(total = Sum('price'))['total']
|
tot = obj.total
|
||||||
if tot: return u"%.02f €" % tot
|
if tot: return u"%.02f €" % tot
|
||||||
else: return u"0 €"
|
else: return u"0 €"
|
||||||
|
total.admin_order_field = "total"
|
||||||
total.short_description = "Total à payer"
|
total.short_description = "Total à payer"
|
||||||
list_display = ("user", "nb_places", "total", "paid", "paymenttype")
|
list_display = ("user", "nb_places", "total", "paid", "paymenttype")
|
||||||
list_filter = ("paid",)
|
list_filter = ("paid",)
|
||||||
|
@ -56,7 +61,7 @@ Voici tes choix de spectacles tels que notre système les a enregistrés :\n\n""
|
||||||
Artistiquement,
|
Artistiquement,
|
||||||
Le BdA"""
|
Le BdA"""
|
||||||
send_mail ("Choix de spectacles (BdA du COF)", mail,
|
send_mail ("Choix de spectacles (BdA du COF)", mail,
|
||||||
"bda@clipper.ens.fr", [member.user.email],
|
"bda@ens.fr", [member.user.email],
|
||||||
fail_silently = True)
|
fail_silently = True)
|
||||||
count = len(queryset.all())
|
count = len(queryset.all())
|
||||||
if count == 1:
|
if count == 1:
|
||||||
|
@ -81,35 +86,48 @@ pour les spectacles suivants :
|
||||||
%s
|
%s
|
||||||
|
|
||||||
*Paiement*
|
*Paiement*
|
||||||
Ces spectacles sont à régler avant le vendredi 19 Octobre, pendant les
|
L'intégralité de ces places de spectacles est à régler à partir du jeudi
|
||||||
heures de permanences du COF (tous les jours de la semaine entre 12h et
|
10 octobre et AVANT le mercredi 23 octobre, au bureau du COF pendant les
|
||||||
14h, et entre 18h et 20h). Des facilités de paiement sont bien évidemment
|
heures de permanences (du lundi au vendredi entre 12h et 14h, et entre 18h
|
||||||
possibles (encaissement échelonné des chèques).
|
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.
|
||||||
|
|
||||||
*Mode de retrait des places*
|
*Mode de retrait des places*
|
||||||
Pour l'Opéra de Paris, le théâtre de la Colline et le théâtre du Châtelet,
|
Au moment du paiement, une enveloppe vous sera remise, contenant les
|
||||||
les places sont à retirer au COF le jour du paiement.
|
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 et la Salle
|
Pour les concerts Radio France, le Théâtre des Champs-Élysées, le théâtre
|
||||||
Pleyel, les places seront nominatives et à retirer au théâtre le soir de
|
du Rond-Point, le théâtre de la Colline, le théâtre de l'Athénée, l'IRCAM,
|
||||||
la représentation au moins une demi-heure avant le début du spectacle.
|
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 Comédie Française, le théâtre de la Ville,
|
Pour le théâtre de l'Odéon, la salle Richelieu le théâtre du Vieux
|
||||||
le théâtre de Chaillot et l'IRCAM, les places seront distribuées dans vos
|
colombier de la Comédie française, certains spectacles du théâtre de la
|
||||||
casiers environ une semaine avant la représentation (un mail vous en
|
Ville et du théâtre de Châtelet ainsi que pour le théâtre de Chaillot, les
|
||||||
avertira).
|
places seront distribuées environ une semaine avant la représentation (un
|
||||||
|
mail vous en avertira).
|
||||||
|
|
||||||
Culturellement vôtre,
|
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.
|
||||||
|
|
||||||
|
En vous souhaitant de très beaux spectacles tout au long de l'année,
|
||||||
--
|
--
|
||||||
Le BdA"""
|
Le Bureau des Arts
|
||||||
|
(Chloé, Emilie, Jaime, Maxime, Olivier)
|
||||||
|
"""
|
||||||
attribs_text = ""
|
attribs_text = ""
|
||||||
name = member.user.get_full_name()
|
name = member.user.get_full_name()
|
||||||
for attrib in attribs:
|
for attrib in attribs:
|
||||||
attribs_text += u"- 1 place pour %s\n" % attrib
|
attribs_text += u"- 1 place pour %s\n" % attrib
|
||||||
mail = mail % (name, attribs_text)
|
mail = mail % (name, attribs_text)
|
||||||
send_mail ("Places de spectacle (BdA du COF)", mail,
|
send_mail ("Résultats du tirage au sort", mail,
|
||||||
"bda@clipper.ens.fr", [member.user.email],
|
"bda@ens.fr", [member.user.email],
|
||||||
fail_silently = True)
|
fail_silently = True)
|
||||||
count = len(queryset.all())
|
count = len(queryset.all())
|
||||||
if count == 1:
|
if count == 1:
|
||||||
|
@ -136,7 +154,13 @@ class ChoixSpectacleAdmin(admin.ModelAdmin):
|
||||||
list_filter = ("double", "autoquit")
|
list_filter = ("double", "autoquit")
|
||||||
search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name')
|
search_fields = ('participant__user__username', 'participant__user__first_name', 'participant__user__last_name')
|
||||||
|
|
||||||
admin.site.register(Spectacle)
|
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(Salle)
|
||||||
admin.site.register(Participant, ParticipantAdmin)
|
admin.site.register(Participant, ParticipantAdmin)
|
||||||
admin.site.register(Attribution, AttributionAdmin)
|
admin.site.register(Attribution, AttributionAdmin)
|
||||||
|
|
|
@ -29,25 +29,24 @@ class Algorithm(object):
|
||||||
self.ranks = {}
|
self.ranks = {}
|
||||||
self.origranks = {}
|
self.origranks = {}
|
||||||
self.choices = {}
|
self.choices = {}
|
||||||
|
next_rank = {}
|
||||||
|
member_shows = {}
|
||||||
for member in members:
|
for member in members:
|
||||||
ranks = {}
|
self.ranks[member] = {}
|
||||||
member_choices = {}
|
self.choices[member] = {}
|
||||||
member_shows = {}
|
next_rank[member] = 1
|
||||||
#next_priority = 1
|
member_shows[member] = {}
|
||||||
next_rank = 1
|
for choice in choices:
|
||||||
for choice in member.choixspectacle_set.order_by('priority').all():
|
member = choice.participant
|
||||||
if choice.spectacle in member_shows: continue
|
if choice.spectacle in member_shows[member]: continue
|
||||||
else: member_shows[choice.spectacle] = True
|
else: member_shows[member][choice.spectacle] = True
|
||||||
#assert choice.priority == next_priority
|
showdict[choice.spectacle].requests.append(member)
|
||||||
#next_priority += 1
|
showdict[choice.spectacle].nrequests += 2 if choice.double else 1
|
||||||
showdict[choice.spectacle].requests.append(member)
|
self.ranks[member][choice.spectacle] = next_rank[member]
|
||||||
showdict[choice.spectacle].nrequests += 2 if choice.double else 1
|
next_rank[member] += 2 if choice.double else 1
|
||||||
ranks[choice.spectacle] = next_rank
|
self.choices[member][choice.spectacle] = choice
|
||||||
next_rank += 2 if choice.double else 1
|
for member in members:
|
||||||
member_choices[choice.spectacle] = choice
|
self.origranks[member] = dict(self.ranks[member])
|
||||||
self.ranks[member] = ranks
|
|
||||||
self.choices[member] = member_choices
|
|
||||||
self.origranks[member] = dict(ranks)
|
|
||||||
|
|
||||||
def IncrementRanks(self, member, currank, increment = 1):
|
def IncrementRanks(self, member, currank, increment = 1):
|
||||||
for show in self.ranks[member]:
|
for show in self.ranks[member]:
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
|
import calendar
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -29,11 +31,14 @@ class Spectacle (models.Model):
|
||||||
def __repr__ (self):
|
def __repr__ (self):
|
||||||
return u"[%s]" % self.__unicode__()
|
return u"[%s]" % self.__unicode__()
|
||||||
|
|
||||||
|
def timestamp(self):
|
||||||
|
return "%d" % calendar.timegm(self.date.utctimetuple())
|
||||||
|
|
||||||
def date_no_seconds(self):
|
def date_no_seconds(self):
|
||||||
return self.date.strftime('%d %b %Y %H:%M')
|
return self.date.strftime('%d %b %Y %H:%M')
|
||||||
|
|
||||||
def __unicode__ (self):
|
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 = (
|
PAYMENT_TYPES = (
|
||||||
("cash",u"Cash"),
|
("cash",u"Cash"),
|
||||||
|
|
106
bda/views.py
106
bda/views.py
|
@ -1,17 +1,22 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.forms.models import inlineformset_factory, BaseInlineFormSet
|
from django.forms.models import inlineformset_factory, BaseInlineFormSet
|
||||||
|
from django.core import serializers
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from gestioncof.decorators import cof_required, buro_required
|
from gestioncof.decorators import cof_required, buro_required
|
||||||
|
from gestioncof.shared import send_custom_mail
|
||||||
from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution
|
from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution
|
||||||
from bda.algorithm import Algorithm
|
from bda.algorithm import Algorithm
|
||||||
|
|
||||||
|
@ -42,47 +47,93 @@ def etat_places(request):
|
||||||
total = 0
|
total = 0
|
||||||
for spectacle in spectacles:
|
for spectacle in spectacles:
|
||||||
spectacle.total = 0
|
spectacle.total = 0
|
||||||
|
spectacle.ratio = -1.0
|
||||||
spectacles_dict[spectacle.id] = spectacle
|
spectacles_dict[spectacle.id] = spectacle
|
||||||
for spectacle in spectacles1:
|
for spectacle in spectacles1:
|
||||||
spectacles_dict[spectacle["spectacle"]].total += spectacle["total"]
|
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"]
|
total += spectacle["total"]
|
||||||
for spectacle in spectacles2:
|
for spectacle in spectacles2:
|
||||||
spectacles_dict[spectacle["spectacle"]].total += spectacle["total"]
|
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"]
|
total += spectacle["total"]
|
||||||
return render(request, "etat-places.html", {"spectacles": spectacles, "total": 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
|
@cof_required
|
||||||
def inscription(request):
|
def inscription(request):
|
||||||
if False and time.time() > 1349474400:
|
if datetime.now() > datetime(2013, 10, 6, 23, 59):
|
||||||
return render(request, "error.html", {"error_title": "C'est fini !", "error_description": u"Tirage au sort le 6 octobre dans la soirée "})
|
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})
|
||||||
BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet)
|
BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle, fields = ("spectacle","double","autoquit","priority",), formset = BaseBdaFormSet)
|
||||||
participant, created = Participant.objects.get_or_create(user = request.user)
|
participant, created = Participant.objects.get_or_create(user = request.user)
|
||||||
success = False
|
success = False
|
||||||
|
stateerror = False
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
formset = BdaFormSet(request.POST, instance = participant)
|
dbstate = _hash_queryset(participant.choixspectacle_set.all())
|
||||||
if formset.is_valid():
|
if "dbstate" in request.POST and dbstate != request.POST["dbstate"]:
|
||||||
#ChoixSpectacle.objects.filter(participant = participant).delete()
|
stateerror = True
|
||||||
formset.save()
|
|
||||||
success = True
|
|
||||||
formset = BdaFormSet(instance = participant)
|
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:
|
else:
|
||||||
formset = BdaFormSet(instance = participant)
|
formset = BdaFormSet(instance = participant)
|
||||||
|
dbstate = _hash_queryset(participant.choixspectacle_set.all())
|
||||||
total_price = 0
|
total_price = 0
|
||||||
for choice in participant.choixspectacle_set.all():
|
for choice in participant.choixspectacle_set.all():
|
||||||
total_price += choice.spectacle.price
|
total_price += choice.spectacle.price
|
||||||
if choice.double: 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})
|
return render(request, "inscription-bda.html", {"formset": formset, "success": success, "total_price": total_price, "dbstate": dbstate, "stateerror": stateerror})
|
||||||
|
|
||||||
Spectacle.deficit = lambda x: (x.slots-x.nrequests)*x.price
|
|
||||||
|
|
||||||
def do_tirage(request):
|
def do_tirage(request):
|
||||||
form = TokenForm(request.POST)
|
form = TokenForm(request.POST)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return tirage(request)
|
return tirage(request)
|
||||||
|
start = time.time()
|
||||||
data = {}
|
data = {}
|
||||||
shows = Spectacle.objects.all()
|
shows = Spectacle.objects.select_related().all()
|
||||||
members = Participant.objects.all()
|
members = Participant.objects.all()
|
||||||
choices = ChoixSpectacle.objects.all()
|
choices = ChoixSpectacle.objects.order_by('participant', 'priority').select_related().all()
|
||||||
algo = Algorithm(shows, members, choices)
|
algo = Algorithm(shows, members, choices)
|
||||||
results = algo(form.cleaned_data["token"])
|
results = algo(form.cleaned_data["token"])
|
||||||
total_slots = 0
|
total_slots = 0
|
||||||
|
@ -99,8 +150,8 @@ def do_tirage(request):
|
||||||
total_sold = 0
|
total_sold = 0
|
||||||
total_deficit = 0
|
total_deficit = 0
|
||||||
opera_deficit = 0
|
opera_deficit = 0
|
||||||
for show in shows:
|
for (show, members, _) in results:
|
||||||
deficit = show.deficit()
|
deficit = (show.slots - len(members)) * show.price
|
||||||
total_sold += show.slots * show.price
|
total_sold += show.slots * show.price
|
||||||
if deficit >= 0:
|
if deficit >= 0:
|
||||||
if u"Opéra" in show.location.name:
|
if u"Opéra" in show.location.name:
|
||||||
|
@ -109,18 +160,23 @@ def do_tirage(request):
|
||||||
data["total_sold"] = total_sold - total_deficit
|
data["total_sold"] = total_sold - total_deficit
|
||||||
data["total_deficit"] = total_deficit
|
data["total_deficit"] = total_deficit
|
||||||
data["opera_deficit"] = opera_deficit
|
data["opera_deficit"] = opera_deficit
|
||||||
|
data["duration"] = time.time() - start
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
members2 = {}
|
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 (show, members, _) in results:
|
||||||
for (member, _, _, _) in members:
|
for (member, _, _, _) in members:
|
||||||
if member not in members2:
|
if member.id not in members_uniq:
|
||||||
|
members_uniq[member.id] = member
|
||||||
members2[member] = []
|
members2[member] = []
|
||||||
member.total = 0
|
member.total = 0
|
||||||
|
member = members_uniq[member.id]
|
||||||
members2[member].append(show)
|
members2[member].append(show)
|
||||||
member.total += show.price
|
member.total += show.price
|
||||||
members2 = members2.items()
|
members2 = members2.items()
|
||||||
data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name)
|
data["members2"] = sorted(members2, key = lambda m: m[0].user.last_name)
|
||||||
if False and request.user.username == "seguin":
|
if False and request.user.username in ["seguin", "harazi"]:
|
||||||
Attribution.objects.all().delete()
|
Attribution.objects.all().delete()
|
||||||
for (show, members, _) in results:
|
for (show, members, _) in results:
|
||||||
for (member, _, _, _) in members:
|
for (member, _, _, _) in members:
|
||||||
|
@ -159,15 +215,27 @@ def do_resell(request, form):
|
||||||
spectacle = form.cleaned_data["spectacle"]
|
spectacle = form.cleaned_data["spectacle"]
|
||||||
count = form.cleaned_data["count"]
|
count = form.cleaned_data["count"]
|
||||||
places = "2 places" if count == "2" else "une place"
|
places = "2 places" if count == "2" else "une place"
|
||||||
|
"""
|
||||||
|
send_custom_mail("bda-revente@lists.ens.fr",
|
||||||
|
"bda-revente",
|
||||||
|
{"places": places,
|
||||||
|
"spectacle": spectacle.title,
|
||||||
|
"date": spectacle.date_no_seconds(),
|
||||||
|
"lieu": spectacle.location,
|
||||||
|
"prix": spectacle.price,
|
||||||
|
"revendeur": request.user.get_full_name(),
|
||||||
|
"revendeur_mail": request.user.email},
|
||||||
|
from_email = request.user.email)
|
||||||
|
"""
|
||||||
mail = u"""Bonjour,
|
mail = u"""Bonjour,
|
||||||
|
|
||||||
Je souhaite revendre %s pour %s le %s (%s) à %.02f€.
|
Je souhaite revendre %s pour %s le %s (%s) à %.02f€.
|
||||||
Contactez moi par email si vous êtes intéressés !
|
Contactez moi par email si vous êtes intéressé·e·s !
|
||||||
|
|
||||||
%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email)
|
%s (%s)""" % (places, spectacle.title, spectacle.date_no_seconds(), spectacle.location, spectacle.price, request.user.get_full_name(), request.user.email)
|
||||||
send_mail("Revente de place: %s" % spectacle, mail,
|
send_mail("%s" % spectacle, mail,
|
||||||
request.user.email, ["bda-revente@lists.ens.fr"],
|
request.user.email, ["bda-revente@lists.ens.fr"],
|
||||||
fail_silently = True)
|
fail_silently = False)
|
||||||
return render(request, "bda-success.html", {"show": spectacle, "places": places})
|
return render(request, "bda-success.html", {"show": spectacle, "places": places})
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -55,6 +55,9 @@ class EventOptionChoiceInline(admin.TabularInline):
|
||||||
class EventOptionInline(admin.TabularInline):
|
class EventOptionInline(admin.TabularInline):
|
||||||
model = EventOption
|
model = EventOption
|
||||||
|
|
||||||
|
class EventCommentFieldInline(admin.TabularInline):
|
||||||
|
model = EventCommentField
|
||||||
|
|
||||||
class EventOptionAdmin(admin.ModelAdmin):
|
class EventOptionAdmin(admin.ModelAdmin):
|
||||||
inlines = [
|
inlines = [
|
||||||
EventOptionChoiceInline,
|
EventOptionChoiceInline,
|
||||||
|
@ -63,6 +66,7 @@ class EventOptionAdmin(admin.ModelAdmin):
|
||||||
class EventAdmin(admin.ModelAdmin):
|
class EventAdmin(admin.ModelAdmin):
|
||||||
inlines = [
|
inlines = [
|
||||||
EventOptionInline,
|
EventOptionInline,
|
||||||
|
EventCommentFieldInline,
|
||||||
]
|
]
|
||||||
|
|
||||||
#from eav.forms import BaseDynamicEntityForm
|
#from eav.forms import BaseDynamicEntityForm
|
||||||
|
@ -253,6 +257,8 @@ admin.site.register(EventOption, EventOptionAdmin)
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.register(User, UserProfileAdmin)
|
admin.site.register(User, UserProfileAdmin)
|
||||||
admin.site.register(CofProfile)
|
admin.site.register(CofProfile)
|
||||||
|
admin.site.register(Club)
|
||||||
|
admin.site.register(CustomMail)
|
||||||
admin.site.register(PetitCoursSubject)
|
admin.site.register(PetitCoursSubject)
|
||||||
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
admin.site.register(PetitCoursAbility, PetitCoursAbilityAdmin)
|
||||||
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
|
admin.site.register(PetitCoursAttribution, PetitCoursAttributionAdmin)
|
||||||
|
|
|
@ -24,6 +24,11 @@ TYPE_COTIZ_CHOICES = (
|
||||||
('exterieur', _(u"Extérieur")),
|
('exterieur', _(u"Extérieur")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
TYPE_COMMENT_FIELD = (
|
||||||
|
('text', _(u"Texte long")),
|
||||||
|
('char', _(u"Texte court")),
|
||||||
|
)
|
||||||
|
|
||||||
def choices_length (choices):
|
def choices_length (choices):
|
||||||
return reduce (lambda m, choice: max (m, len (choice[0])), choices, 0)
|
return reduce (lambda m, choice: max (m, len (choice[0])), choices, 0)
|
||||||
|
|
||||||
|
@ -45,6 +50,7 @@ class CofProfile(models.Model):
|
||||||
mailing_cof = models.BooleanField("Recevoir les mails COF", default = False)
|
mailing_cof = models.BooleanField("Recevoir les mails COF", default = False)
|
||||||
mailing_bda = models.BooleanField("Recevoir les mails BdA", default = False)
|
mailing_bda = models.BooleanField("Recevoir les mails BdA", default = False)
|
||||||
mailing_bda_revente = models.BooleanField("Recevoir les mails de revente de places BdA", default = False)
|
mailing_bda_revente = models.BooleanField("Recevoir les mails de revente de places BdA", default = False)
|
||||||
|
comments = models.TextField("Commentaires visibles uniquement par le Buro", blank = True)
|
||||||
is_buro = models.BooleanField("Membre du Burô", default = False)
|
is_buro = models.BooleanField("Membre du Burô", default = False)
|
||||||
petits_cours_accept = models.BooleanField("Recevoir des petits cours", default = False)
|
petits_cours_accept = models.BooleanField("Recevoir des petits cours", default = False)
|
||||||
petits_cours_remarques = models.TextField(_(u"Remarques et précisions pour les petits cours"),
|
petits_cours_remarques = models.TextField(_(u"Remarques et précisions pour les petits cours"),
|
||||||
|
@ -62,6 +68,24 @@ def create_user_profile(sender, instance, created, **kwargs):
|
||||||
CofProfile.objects.get_or_create(user = instance)
|
CofProfile.objects.get_or_create(user = instance)
|
||||||
post_save.connect(create_user_profile, sender = User)
|
post_save.connect(create_user_profile, sender = User)
|
||||||
|
|
||||||
|
class Club(models.Model):
|
||||||
|
name = models.CharField("Nom", max_length = 200)
|
||||||
|
description = models.TextField("Description")
|
||||||
|
respos = models.ManyToManyField(User, related_name = "clubs_geres")
|
||||||
|
membres = models.ManyToManyField(User, related_name = "clubs")
|
||||||
|
|
||||||
|
class CustomMail(models.Model):
|
||||||
|
shortname = models.SlugField(max_length = 50, blank = False)
|
||||||
|
title = models.CharField("Titre", max_length = 200, blank = False)
|
||||||
|
content = models.TextField("Contenu", blank = False)
|
||||||
|
comments = models.TextField("Informations contextuelles sur le mail", blank = True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Mails personnalisables"
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u"%s: %s" % (self.shortname, self.title)
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
title = models.CharField("Titre", max_length = 200)
|
title = models.CharField("Titre", max_length = 200)
|
||||||
location = models.CharField("Lieu", max_length = 200)
|
location = models.CharField("Lieu", max_length = 200)
|
||||||
|
@ -77,6 +101,23 @@ class Event(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return unicode(self.title)
|
return unicode(self.title)
|
||||||
|
|
||||||
|
class EventCommentField(models.Model):
|
||||||
|
event = models.ForeignKey(Event, related_name = "commentfields")
|
||||||
|
name = models.CharField("Champ", max_length = 200)
|
||||||
|
fieldtype = models.CharField("Type", max_length = 10, choices = TYPE_COMMENT_FIELD, default = "text")
|
||||||
|
default = models.TextField("Valeur par défaut", blank = True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Champ"
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode(self.name)
|
||||||
|
|
||||||
|
class EventCommentValue(models.Model):
|
||||||
|
commentfield = models.ForeignKey(EventCommentField, related_name = "values")
|
||||||
|
registration = models.ForeignKey("EventRegistration", related_name = "comments")
|
||||||
|
content = models.TextField("Contenu", blank = True, null = True)
|
||||||
|
|
||||||
class EventOption(models.Model):
|
class EventOption(models.Model):
|
||||||
event = models.ForeignKey(Event, related_name = "options")
|
event = models.ForeignKey(Event, related_name = "options")
|
||||||
name = models.CharField("Option", max_length = 200)
|
name = models.CharField("Option", max_length = 200)
|
||||||
|
@ -102,6 +143,7 @@ class EventRegistration(models.Model):
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User)
|
||||||
event = models.ForeignKey(Event)
|
event = models.ForeignKey(Event)
|
||||||
options = models.ManyToManyField(EventOptionChoice)
|
options = models.ManyToManyField(EventOptionChoice)
|
||||||
|
filledcomments = models.ManyToManyField(EventCommentField, through = EventCommentValue)
|
||||||
paid = models.BooleanField("A payé", default = False)
|
paid = models.BooleanField("A payé", default = False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -60,38 +60,45 @@ def _get_attrib_counter(user, matiere):
|
||||||
counter.save()
|
counter.save()
|
||||||
return counter
|
return counter
|
||||||
|
|
||||||
|
def _get_demande_candidates(demande, redo = False):
|
||||||
|
|
||||||
@buro_required
|
|
||||||
def traitement(request, demande_id):
|
|
||||||
demande = get_object_or_404(PetitCoursDemande, id = demande_id)
|
|
||||||
if demande.niveau == "other":
|
|
||||||
return _traitement_other(request, demande)
|
|
||||||
if request.method == "POST":
|
|
||||||
return _traitement_post(request, demande)
|
|
||||||
proposals = {}
|
|
||||||
proposed_for = {}
|
|
||||||
unsatisfied = []
|
|
||||||
attribdata = {}
|
|
||||||
for matiere in demande.matieres.all():
|
for matiere in demande.matieres.all():
|
||||||
candidates = PetitCoursAbility.objects.filter(matiere = matiere, niveau = demande.niveau)
|
candidates = PetitCoursAbility.objects.filter(matiere = matiere, niveau = demande.niveau)
|
||||||
candidates = candidates.filter(user__profile__is_cof = True,
|
candidates = candidates.filter(user__profile__is_cof = True,
|
||||||
user__profile__petits_cours_accept = True)
|
user__profile__petits_cours_accept = True)
|
||||||
if demande.agrege_requis:
|
if demande.agrege_requis:
|
||||||
candidates = candidates.filter(agrege = True)
|
candidates = candidates.filter(agrege = True)
|
||||||
candidates = candidates.values_list('user', flat = True).distinct().order_by('?').all()
|
if redo:
|
||||||
tuples = []
|
attributions = PetitCoursAttribution.objects.filter(demande = demande,
|
||||||
for candidate in candidates:
|
matiere = matiere).all()
|
||||||
user = User.objects.get(pk = candidate)
|
for attrib in attributions:
|
||||||
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
candidates = candidates.exclude(user = attrib.user)
|
||||||
if tuples:
|
candidates = candidates.order_by('?').select_related().all()
|
||||||
|
yield (matiere, candidates)
|
||||||
|
|
||||||
|
@buro_required
|
||||||
|
def traitement(request, demande_id, redo = False):
|
||||||
|
demande = get_object_or_404(PetitCoursDemande, id = demande_id)
|
||||||
|
if demande.niveau == "other":
|
||||||
|
return _traitement_other(request, demande, redo)
|
||||||
|
if request.method == "POST":
|
||||||
|
return _traitement_post(request, demande)
|
||||||
|
proposals = {}
|
||||||
|
proposed_for = {}
|
||||||
|
unsatisfied = []
|
||||||
|
attribdata = {}
|
||||||
|
for matiere, candidates in _get_demande_candidates(demande, redo):
|
||||||
|
if candidates:
|
||||||
|
tuples = []
|
||||||
|
for candidate in candidates:
|
||||||
|
user = candidate.user
|
||||||
|
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
||||||
tuples = sorted(tuples, key = lambda c: c[1].count)
|
tuples = sorted(tuples, key = lambda c: c[1].count)
|
||||||
candidates, _ = zip(*tuples)
|
candidates, _ = zip(*tuples)
|
||||||
attribdata[matiere.id] = []
|
|
||||||
candidates = candidates[0:min(3, len(candidates))]
|
candidates = candidates[0:min(3, len(candidates))]
|
||||||
|
attribdata[matiere.id] = []
|
||||||
proposals[matiere] = []
|
proposals[matiere] = []
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
user = User.objects.get(pk = candidate)
|
user = candidate.user
|
||||||
proposals[matiere].append(user)
|
proposals[matiere].append(user)
|
||||||
attribdata[matiere.id].append(user.id)
|
attribdata[matiere.id].append(user.id)
|
||||||
if user not in proposed_for:
|
if user not in proposed_for:
|
||||||
|
@ -100,10 +107,15 @@ def traitement(request, demande_id):
|
||||||
proposed_for[user].append(matiere)
|
proposed_for[user].append(matiere)
|
||||||
else:
|
else:
|
||||||
unsatisfied.append(matiere)
|
unsatisfied.append(matiere)
|
||||||
return _finalize_traitement(request, demande, proposals, proposed_for, unsatisfied, attribdata)
|
return _finalize_traitement(request, demande, proposals,
|
||||||
|
proposed_for, unsatisfied, attribdata, redo)
|
||||||
|
|
||||||
|
@buro_required
|
||||||
|
def retraitement(request, demande_id):
|
||||||
|
return traitement(request, demande_id, redo = True)
|
||||||
|
|
||||||
def _finalize_traitement(request, demande, proposals, proposed_for,
|
def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
unsatisfied, attribdata, redo = False):
|
unsatisfied, attribdata, redo = False, errors = None):
|
||||||
proposals = proposals.items()
|
proposals = proposals.items()
|
||||||
proposed_for = proposed_for.items()
|
proposed_for = proposed_for.items()
|
||||||
attribdata = attribdata.items()
|
attribdata = attribdata.items()
|
||||||
|
@ -121,6 +133,7 @@ def _finalize_traitement(request, demande, proposals, proposed_for,
|
||||||
"mainmail": mainmail,
|
"mainmail": mainmail,
|
||||||
"attribdata": base64.b64encode(simplejson.dumps(attribdata)),
|
"attribdata": base64.b64encode(simplejson.dumps(attribdata)),
|
||||||
"redo": redo,
|
"redo": redo,
|
||||||
|
"errors": errors,
|
||||||
})
|
})
|
||||||
|
|
||||||
def _generate_eleve_email(demande, proposed_for):
|
def _generate_eleve_email(demande, proposed_for):
|
||||||
|
@ -130,15 +143,45 @@ def _generate_eleve_email(demande, proposed_for):
|
||||||
proposed_mails.append((user, msg))
|
proposed_mails.append((user, msg))
|
||||||
return proposed_mails
|
return proposed_mails
|
||||||
|
|
||||||
def _traitement_other_post(request, demande):
|
def _traitement_other_preparing(request, demande):
|
||||||
for matiere in demande.matieres.all():
|
redo = "redo" in request.POST
|
||||||
for choice_id in range(3):
|
unsatisfied = []
|
||||||
choice = request.POST["proposal-%d-%d"] % (matiere.id, choice_id)]:
|
proposals = {}
|
||||||
pass
|
proposed_for = {}
|
||||||
return None
|
attribdata = {}
|
||||||
return _finalize_traitement(request, demande, proposals, proposed_for, unsatisfied, attribdata)
|
errors = []
|
||||||
|
for matiere, candidates in _get_demande_candidates(demande, redo):
|
||||||
|
if candidates:
|
||||||
|
candidates = dict([(candidate.user.id, candidate.user)
|
||||||
|
for candidate in candidates])
|
||||||
|
attribdata[matiere.id] = []
|
||||||
|
proposals[matiere] = []
|
||||||
|
for choice_id in range(min(3, len(candidates))):
|
||||||
|
choice = int(request.POST["proposal-%d-%d" % (matiere.id, choice_id)])
|
||||||
|
if choice == -1:
|
||||||
|
continue
|
||||||
|
if choice not in candidates:
|
||||||
|
errors.append(u"Choix invalide pour la proposition %d en %s" % (choice_id + 1, matiere))
|
||||||
|
continue
|
||||||
|
user = candidates[choice]
|
||||||
|
if user in proposals[matiere]:
|
||||||
|
errors.append(u"La proposition %d en %s est un doublon" % (choice_id + 1, matiere))
|
||||||
|
continue
|
||||||
|
proposals[matiere].append(user)
|
||||||
|
attribdata[matiere.id].append(user.id)
|
||||||
|
if user not in proposed_for:
|
||||||
|
proposed_for[user] = [matiere]
|
||||||
|
else:
|
||||||
|
proposed_for[user].append(matiere)
|
||||||
|
if not proposals[matiere]:
|
||||||
|
errors.append(u"Aucune proposition pour %s" % (matiere,))
|
||||||
|
elif len(proposals[matiere]) < 3:
|
||||||
|
errors.append(u"Seulement %d proposition%s pour %s" % (len(proposals[matiere]), "s" if len(proposals[matiere]) > 1 else "", matiere))
|
||||||
|
else:
|
||||||
|
unsatisfied.append(matiere)
|
||||||
|
return _finalize_traitement(request, demande, proposals, proposed_for, unsatisfied, attribdata, errors = errors)
|
||||||
|
|
||||||
def _traitement_other(request, demande):
|
def _traitement_other(request, demande, redo):
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if "preparing" in request.POST:
|
if "preparing" in request.POST:
|
||||||
return _traitement_other_preparing(request, demande)
|
return _traitement_other_preparing(request, demande)
|
||||||
|
@ -148,13 +191,7 @@ def _traitement_other(request, demande):
|
||||||
proposed_for = {}
|
proposed_for = {}
|
||||||
unsatisfied = []
|
unsatisfied = []
|
||||||
attribdata = {}
|
attribdata = {}
|
||||||
for matiere in demande.matieres.all():
|
for matiere, candidates in _get_demande_candidates(demande, redo):
|
||||||
candidates = PetitCoursAbility.objects.filter(matiere = matiere, niveau = demande.niveau)
|
|
||||||
candidates = candidates.filter(user__profile__is_cof = True,
|
|
||||||
user__profile__petits_cours_accept = True)
|
|
||||||
if demande.agrege_requis:
|
|
||||||
candidates = candidates.filter(agrege = True)
|
|
||||||
candidates = candidates.order_by('?').select_related().all()
|
|
||||||
if candidates:
|
if candidates:
|
||||||
tuples = []
|
tuples = []
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
|
@ -243,49 +280,6 @@ def _traitement_post(request, demande):
|
||||||
"redo": redo,
|
"redo": redo,
|
||||||
})
|
})
|
||||||
|
|
||||||
@buro_required
|
|
||||||
def retraitement(request, demande_id):
|
|
||||||
demande = get_object_or_404(PetitCoursDemande, id = demande_id)
|
|
||||||
if request.method == "POST":
|
|
||||||
return _traitement_post(request, demande)
|
|
||||||
if demande.niveau == "other":
|
|
||||||
return _traitement_other(request, demande)
|
|
||||||
proposals = {}
|
|
||||||
proposed_for = {}
|
|
||||||
unsatisfied = []
|
|
||||||
attribdata = {}
|
|
||||||
for matiere in demande.matieres.all():
|
|
||||||
candidates = PetitCoursAbility.objects.filter(matiere = matiere, niveau = demande.niveau)
|
|
||||||
candidates = candidates.filter(user__profile__is_cof = True,
|
|
||||||
user__profile__petits_cours_accept = True)
|
|
||||||
if demande.agrege_requis:
|
|
||||||
candidates = candidates.filter(agrege = True)
|
|
||||||
attributions = PetitCoursAttribution.objects.filter(demande = demande, matiere = matiere).all()
|
|
||||||
for attrib in attributions:
|
|
||||||
candidates = candidates.exclude(user = attrib.user)
|
|
||||||
candidates = candidates.values_list('user', flat = True).distinct().order_by('?').all()
|
|
||||||
tuples = []
|
|
||||||
for candidate in candidates:
|
|
||||||
user = User.objects.get(pk = candidate)
|
|
||||||
tuples.append((candidate, _get_attrib_counter(user, matiere)))
|
|
||||||
if tuples:
|
|
||||||
tuples = sorted(tuples, key = lambda c: c[1].count)
|
|
||||||
candidates, _ = zip(*tuples)
|
|
||||||
attribdata[matiere.id] = []
|
|
||||||
candidates = candidates[0:min(3, len(candidates))]
|
|
||||||
proposals[matiere] = []
|
|
||||||
for candidate in candidates:
|
|
||||||
user = User.objects.get(pk = candidate)
|
|
||||||
proposals[matiere].append(user)
|
|
||||||
attribdata[matiere.id].append(user.id)
|
|
||||||
if user not in proposed_for:
|
|
||||||
proposed_for[user] = [matiere]
|
|
||||||
else:
|
|
||||||
proposed_for[user].append(matiere)
|
|
||||||
else:
|
|
||||||
unsatisfied.append(matiere)
|
|
||||||
return _finalize_traitement(request, demande, proposals, proposed_for, unsatisfied, attribdata, redo = True)
|
|
||||||
|
|
||||||
class BaseMatieresFormSet(BaseInlineFormSet):
|
class BaseMatieresFormSet(BaseInlineFormSet):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super(BaseMatieresFormSet, self).clean()
|
super(BaseMatieresFormSet, self).clean()
|
||||||
|
|
|
@ -2,9 +2,12 @@ from django.contrib.sites.models import Site
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django_cas.backends import CASBackend, _verify as CASverify
|
from django_cas.backends import CASBackend, _verify as CASverify
|
||||||
from django_cas.models import User
|
from django_cas.models import User
|
||||||
|
from django.contrib.auth.models import User as DjangoUser
|
||||||
from django.db import models, connection
|
from django.db import models, connection
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.template import Template, Context
|
||||||
|
|
||||||
from gestioncof.models import CofProfile
|
from gestioncof.models import CofProfile, CustomMail
|
||||||
|
|
||||||
class COFCASBackend(CASBackend):
|
class COFCASBackend(CASBackend):
|
||||||
def authenticate_cas(self, ticket, service, request):
|
def authenticate_cas(self, ticket, service, request):
|
||||||
|
@ -76,3 +79,16 @@ def unlock_tables(*models):
|
||||||
return row
|
return row
|
||||||
|
|
||||||
unlock_table = unlock_tables
|
unlock_table = unlock_tables
|
||||||
|
|
||||||
|
def send_custom_mail(to, shortname, context = None, from_email = "cof@ens.fr"):
|
||||||
|
if context is None: context = {}
|
||||||
|
if isinstance(to, DjangoUser):
|
||||||
|
context["nom"] = to.get_full_name()
|
||||||
|
context["prenom"] = to.first_name
|
||||||
|
to = to.email
|
||||||
|
mail = CustomMail.objects.get(shortname = shortname)
|
||||||
|
template = Template(mail.content)
|
||||||
|
message = template.render(Context(context))
|
||||||
|
send_mail (mail.title, message,
|
||||||
|
from_email, [to],
|
||||||
|
fail_silently = True)
|
||||||
|
|
|
@ -15,10 +15,11 @@ from django.contrib.auth.views import login as django_login_view
|
||||||
|
|
||||||
from gestioncof.models import Survey, SurveyQuestion, SurveyQuestionAnswer, SurveyAnswer
|
from gestioncof.models import Survey, SurveyQuestion, SurveyQuestionAnswer, SurveyAnswer
|
||||||
from gestioncof.models import Event, EventOption, EventOptionChoice, EventRegistration
|
from gestioncof.models import Event, EventOption, EventOptionChoice, EventRegistration
|
||||||
|
from gestioncof.models import EventCommentField, EventCommentValue
|
||||||
from gestioncof.models import CofProfile, Clipper
|
from gestioncof.models import CofProfile, Clipper
|
||||||
from gestioncof.decorators import buro_required, cof_required
|
from gestioncof.decorators import buro_required, cof_required
|
||||||
from gestioncof.widgets import TriStateCheckbox
|
from gestioncof.widgets import TriStateCheckbox
|
||||||
from gestioncof.shared import lock_table, unlock_table
|
from gestioncof.shared import lock_table, unlock_table, send_custom_mail
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
|
@ -205,6 +206,17 @@ def get_event_form_choices(event, form):
|
||||||
all_choices.append(choice)
|
all_choices.append(choice)
|
||||||
return all_choices
|
return all_choices
|
||||||
|
|
||||||
|
def update_event_form_comments(event, form, registration):
|
||||||
|
for commentfield_id, value in form.comments():
|
||||||
|
field = get_object_or_404(EventCommentField, id = commentfield_id,
|
||||||
|
event = event)
|
||||||
|
if value == field.default:
|
||||||
|
continue
|
||||||
|
(storage, _) = EventCommentValue.objects.get_or_create(commentfield = field,
|
||||||
|
registration = registration)
|
||||||
|
storage.content = value
|
||||||
|
storage.save()
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def event(request, event_id):
|
def event(request, event_id):
|
||||||
event = get_object_or_404(Event, id = event_id)
|
event = get_object_or_404(Event, id = event_id)
|
||||||
|
@ -426,6 +438,7 @@ class RegistrationProfileForm(forms.ModelForm):
|
||||||
'mailing_cof',
|
'mailing_cof',
|
||||||
'mailing_bda',
|
'mailing_bda',
|
||||||
'mailing_bda_revente',
|
'mailing_bda_revente',
|
||||||
|
'comments'
|
||||||
]
|
]
|
||||||
|
|
||||||
def save(self, *args, **kw):
|
def save(self, *args, **kw):
|
||||||
|
@ -445,7 +458,7 @@ class RegistrationProfileForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CofProfile
|
model = CofProfile
|
||||||
fields = ("login_clipper", "num", "phone", "occupation", "departement", "is_cof", "type_cotiz", "mailing_cof", "mailing_bda", "mailing_bda_revente",)
|
fields = ("login_clipper", "num", "phone", "occupation", "departement", "is_cof", "type_cotiz", "mailing_cof", "mailing_bda", "mailing_bda_revente", "comments")
|
||||||
|
|
||||||
def registration_set_ro_fields(user_form, profile_form):
|
def registration_set_ro_fields(user_form, profile_form):
|
||||||
user_form.fields['username'].widget.attrs['readonly'] = True
|
user_form.fields['username'].widget.attrs['readonly'] = True
|
||||||
|
@ -487,15 +500,16 @@ def registration_form(request, login_clipper = None, username = None):
|
||||||
return render(request, "registration_form.html", {"user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper})
|
return render(request, "registration_form.html", {"user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper})
|
||||||
|
|
||||||
STATUS_CHOICES = (('no','Non'),
|
STATUS_CHOICES = (('no','Non'),
|
||||||
('wait','Attente paiement'),
|
('wait','Oui mais attente paiement'),
|
||||||
('paid','Payé'),)
|
('paid','Oui payé'),)
|
||||||
class AdminEventForm(forms.Form):
|
class AdminEventForm(forms.Form):
|
||||||
status = forms.ChoiceField(label = "Inscription", choices = STATUS_CHOICES, widget = RadioSelect)
|
status = forms.ChoiceField(label = "Inscription", choices = STATUS_CHOICES, widget = RadioSelect)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
event = kwargs.pop("event")
|
event = kwargs.pop("event")
|
||||||
self.event = event
|
self.event = event
|
||||||
current_choices = kwargs.pop("current_choices", None)
|
registration = kwargs.pop("current_registration", None)
|
||||||
|
current_choices = registration.options.all() if registration is not None else []
|
||||||
paid = kwargs.pop("paid", None)
|
paid = kwargs.pop("paid", None)
|
||||||
if paid == True:
|
if paid == True:
|
||||||
kwargs["initial"] = {"status":"paid"}
|
kwargs["initial"] = {"status":"paid"}
|
||||||
|
@ -505,12 +519,12 @@ class AdminEventForm(forms.Form):
|
||||||
kwargs["initial"] = {"status":"no"}
|
kwargs["initial"] = {"status":"no"}
|
||||||
super(AdminEventForm, self).__init__(*args, **kwargs)
|
super(AdminEventForm, self).__init__(*args, **kwargs)
|
||||||
choices = {}
|
choices = {}
|
||||||
if current_choices:
|
comments = {}
|
||||||
for choice in current_choices.all():
|
for choice in current_choices:
|
||||||
if choice.event_option.id not in choices:
|
if choice.event_option.id not in choices:
|
||||||
choices[choice.event_option.id] = [choice.id]
|
choices[choice.event_option.id] = [choice.id]
|
||||||
else:
|
else:
|
||||||
choices[choice.event_option.id].append(choice.id)
|
choices[choice.event_option.id].append(choice.id)
|
||||||
all_choices = choices
|
all_choices = choices
|
||||||
for option in event.options.all():
|
for option in event.options.all():
|
||||||
choices = [(choice.id, choice.value) for choice in option.choices.all()]
|
choices = [(choice.id, choice.value) for choice in option.choices.all()]
|
||||||
|
@ -530,12 +544,31 @@ class AdminEventForm(forms.Form):
|
||||||
initial = initial)
|
initial = initial)
|
||||||
field.option_id = option.id
|
field.option_id = option.id
|
||||||
self.fields["option_%d" % option.id] = field
|
self.fields["option_%d" % option.id] = field
|
||||||
|
for commentfield in event.commentfields.all():
|
||||||
|
initial = commentfield.default
|
||||||
|
if registration is not None:
|
||||||
|
try:
|
||||||
|
initial = registration.comments.get(commentfield = commentfield).content
|
||||||
|
except EventCommentValue.DoesNotExist:
|
||||||
|
pass
|
||||||
|
widget = forms.Textarea if commentfield.fieldtype == "text" else forms.TextInput
|
||||||
|
field = forms.CharField(label = commentfield.name,
|
||||||
|
widget = widget,
|
||||||
|
required = False,
|
||||||
|
initial = initial)
|
||||||
|
field.comment_id = commentfield.id
|
||||||
|
self.fields["comment_%d" % commentfield.id] = field
|
||||||
|
|
||||||
def choices(self):
|
def choices(self):
|
||||||
for name, value in self.cleaned_data.items():
|
for name, value in self.cleaned_data.items():
|
||||||
if name.startswith('option_'):
|
if name.startswith('option_'):
|
||||||
yield (self.fields[name].option_id, value)
|
yield (self.fields[name].option_id, value)
|
||||||
|
|
||||||
|
def comments(self):
|
||||||
|
for name, value in self.cleaned_data.items():
|
||||||
|
if name.startswith('comment_'):
|
||||||
|
yield (self.fields[name].comment_id, value)
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def registration_form2(request, login_clipper = None, username = None):
|
def registration_form2(request, login_clipper = None, username = None):
|
||||||
events = Event.objects.filter(old = False).all()
|
events = Event.objects.filter(old = False).all()
|
||||||
|
@ -571,7 +604,7 @@ def registration_form2(request, login_clipper = None, username = None):
|
||||||
for event in events:
|
for event in events:
|
||||||
try:
|
try:
|
||||||
current_registration = EventRegistration.objects.get(user = member, event = event)
|
current_registration = EventRegistration.objects.get(user = member, event = event)
|
||||||
form = AdminEventForm(event = event, current_choices = current_registration.options, paid = current_registration.paid)
|
form = AdminEventForm(event = event, current_registration = current_registration, paid = current_registration.paid)
|
||||||
except EventRegistration.DoesNotExist:
|
except EventRegistration.DoesNotExist:
|
||||||
form = AdminEventForm(event = event)
|
form = AdminEventForm(event = event)
|
||||||
event_forms.append(form)
|
event_forms.append(form)
|
||||||
|
@ -618,10 +651,14 @@ def registration(request):
|
||||||
if user_form.is_valid() and profile_form.is_valid() and not any([not form.is_valid() for form in event_forms]):
|
if user_form.is_valid() and profile_form.is_valid() and not any([not form.is_valid() for form in event_forms]):
|
||||||
member = user_form.save()
|
member = user_form.save()
|
||||||
(profile, _) = CofProfile.objects.get_or_create(user = member)
|
(profile, _) = CofProfile.objects.get_or_create(user = member)
|
||||||
|
was_cof = profile.is_cof
|
||||||
request_dict["num"] = profile.num
|
request_dict["num"] = profile.num
|
||||||
profile_form = RegistrationProfileForm(request_dict, instance = profile)
|
profile_form = RegistrationProfileForm(request_dict, instance = profile)
|
||||||
profile_form.is_valid()
|
profile_form.is_valid()
|
||||||
profile_form.save()
|
profile_form.save()
|
||||||
|
(profile, _) = CofProfile.objects.get_or_create(user = member)
|
||||||
|
if profile.is_cof and not was_cof:
|
||||||
|
send_custom_mail(member, "bienvenue")
|
||||||
for form in event_forms:
|
for form in event_forms:
|
||||||
if form.cleaned_data['status'] == 'no':
|
if form.cleaned_data['status'] == 'no':
|
||||||
try:
|
try:
|
||||||
|
@ -631,10 +668,18 @@ def registration(request):
|
||||||
pass
|
pass
|
||||||
continue
|
continue
|
||||||
all_choices = get_event_form_choices(form.event, form)
|
all_choices = get_event_form_choices(form.event, form)
|
||||||
(current_registration, _) = EventRegistration.objects.get_or_create(user = member, event = form.event)
|
(current_registration, created_reg) = EventRegistration.objects.get_or_create(user = member, event = form.event)
|
||||||
|
update_event_form_comments(event, form, current_registration)
|
||||||
current_registration.options = all_choices
|
current_registration.options = all_choices
|
||||||
current_registration.paid = (form.cleaned_data['status'] == 'paid')
|
current_registration.paid = (form.cleaned_data['status'] == 'paid')
|
||||||
current_registration.save()
|
current_registration.save()
|
||||||
|
if event.title == "Mega 2014" and created_reg:
|
||||||
|
field = EventCommentField.objects.get(event = event, name = "Commentaires")
|
||||||
|
try:
|
||||||
|
comments = EventCommentValue.objects.get(commentfield = field, registration = current_registration).content
|
||||||
|
except EventCommentValue.DoesNotExist:
|
||||||
|
comments = field.default
|
||||||
|
send_custom_mail(member, "mega", {"remarques": comments})
|
||||||
success = True
|
success = True
|
||||||
return render(request, "registration_post.html", {"success": success, "user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper, "event_forms": event_forms})
|
return render(request, "registration_post.html", {"success": success, "user_form": user_form, "profile_form": profile_form, "member": member, "login_clipper": login_clipper, "event_forms": event_forms})
|
||||||
else:
|
else:
|
||||||
|
@ -653,54 +698,76 @@ def export_members(request):
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def csv_export_mega(filename, qs):
|
||||||
|
response = HttpResponse(mimetype = 'text/csv')
|
||||||
|
response['Content-Disposition'] = 'attachment; filename=' + filename
|
||||||
|
writer = unicodecsv.UnicodeWriter(response)
|
||||||
|
|
||||||
|
for reg in qs.all():
|
||||||
|
user = reg.user
|
||||||
|
profile = user.get_profile()
|
||||||
|
comments = "---".join([comment.content for comment in reg.comments.all()])
|
||||||
|
bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num, profile.comments if profile.comments else "", comments]
|
||||||
|
writer.writerow([unicode(bit) for bit in bits])
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
@buro_required
|
||||||
|
def export_mega_remarksonly(request):
|
||||||
|
filename = 'remarques_mega_2014.csv'
|
||||||
|
response = HttpResponse(mimetype = 'text/csv')
|
||||||
|
response['Content-Disposition'] = 'attachment; filename=' + filename
|
||||||
|
writer = unicodecsv.UnicodeWriter(response)
|
||||||
|
|
||||||
|
event = Event.objects.get(title = "Mega 2014")
|
||||||
|
commentfield = event.commentfields.get(name = "Commentaires")
|
||||||
|
for val in commentfield.values.all():
|
||||||
|
reg = val.registration
|
||||||
|
user = reg.user
|
||||||
|
profile = user.get_profile()
|
||||||
|
bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num, profile.comments, val.content]
|
||||||
|
writer.writerow([unicode(bit) for bit in bits])
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
@buro_required
|
||||||
|
def export_mega_bytype(request, type):
|
||||||
|
types = {"orga-actif": "Orga actif",
|
||||||
|
"orga-branleur": "Orga branleur",
|
||||||
|
"conscrit-eleve": "Conscrit élève",
|
||||||
|
"conscrit-etudiant": "Conscrit étudiant"}
|
||||||
|
|
||||||
|
if type not in types:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
event = Event.objects.get(title = "Mega 2014")
|
||||||
|
type_option = event.options.get(name = "Type")
|
||||||
|
participant_type = type_option.choices.get(value = types[type]).id
|
||||||
|
qs = EventRegistration.objects.filter(event = event).filter(options__id__exact = participant_type)
|
||||||
|
return csv_export_mega(type + '_mega_2014.csv', qs)
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_mega_orgas(request):
|
def export_mega_orgas(request):
|
||||||
response = HttpResponse(mimetype = 'text/csv')
|
event = Event.objects.get(title = "Mega 2014")
|
||||||
response['Content-Disposition'] = 'attachment; filename=orgas_mega.csv'
|
|
||||||
|
|
||||||
writer = unicodecsv.UnicodeWriter(response)
|
|
||||||
event = Event.objects.get(title = "MEGA")
|
|
||||||
type_option = event.options.get(name = "Type")
|
type_option = event.options.get(name = "Type")
|
||||||
participant_type = type_option.choices.get(value = "Participant").id
|
participant_type_a = type_option.choices.get(value = "Conscrit étudiant").id
|
||||||
for reg in EventRegistration.objects.filter(event = event).exclude(options__id__exact = participant_type).all():
|
participant_type_b = type_option.choices.get(value = "Conscrit élève").id
|
||||||
user = reg.user
|
qs = EventRegistration.objects.filter(event = event).exclude(options__id__in = (participant_type_a, participant_type_b))
|
||||||
profile = user.get_profile()
|
return csv_export_mega('orgas_mega_2014.csv', qs)
|
||||||
bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num]
|
|
||||||
writer.writerow([unicode(bit) for bit in bits])
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
@buro_required
|
|
||||||
def export_mega_participants(request):
|
def export_mega_participants(request):
|
||||||
response = HttpResponse(mimetype = 'text/csv')
|
event = Event.objects.get(title = "Mega 2014")
|
||||||
response['Content-Disposition'] = 'attachment; filename=participants_mega.csv'
|
|
||||||
|
|
||||||
writer = unicodecsv.UnicodeWriter(response)
|
|
||||||
event = Event.objects.get(title = "MEGA")
|
|
||||||
type_option = event.options.get(name = "Type")
|
type_option = event.options.get(name = "Type")
|
||||||
participant_type = type_option.choices.get(value = "Participant").id
|
participant_type_a = type_option.choices.get(value = "Conscrit étudiant").id
|
||||||
for reg in EventRegistration.objects.filter(event = event).filter(options__id__exact = participant_type).all():
|
participant_type_b = type_option.choices.get(value = "Conscrit élève").id
|
||||||
user = reg.user
|
qs = EventRegistration.objects.filter(event = event).filter(options__id__in = (participant_type_a, participant_type_b))
|
||||||
profile = user.get_profile()
|
return csv_export_mega('participants_mega_2014.csv', qs)
|
||||||
bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num]
|
|
||||||
writer.writerow([unicode(bit) for bit in bits])
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def export_mega(request):
|
def export_mega(request):
|
||||||
response = HttpResponse(mimetype = 'text/csv')
|
event = Event.objects.filter(title = "Mega 2014")
|
||||||
response['Content-Disposition'] = 'attachment; filename=all_mega.csv'
|
qs = EventRegistration.objects.filter(event = event).order_by("user__username")
|
||||||
|
return csv_export_mega('all_mega_2014.csv', qs)
|
||||||
writer = unicodecsv.UnicodeWriter(response)
|
|
||||||
event = Event.objects.filter(title = "MEGA")
|
|
||||||
for reg in EventRegistration.objects.filter(event = event).order_by("user__username").all():
|
|
||||||
user = reg.user
|
|
||||||
profile = user.get_profile()
|
|
||||||
bits = [user.username, user.first_name, user.last_name, user.email, profile.phone, profile.num]
|
|
||||||
writer.writerow([unicode(bit) for bit in bits])
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def utile_cof(request):
|
def utile_cof(request):
|
||||||
|
|
0
manage.py
Executable file → Normal file
0
manage.py
Executable file → Normal file
|
@ -176,8 +176,8 @@ fieldset legend {
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-container {
|
#main-container {
|
||||||
max-width: 90%;
|
max-width: 95%;
|
||||||
width: 800px;
|
width: 1000px;
|
||||||
margin: 7em auto;
|
margin: 7em auto;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -588,3 +588,47 @@ pre code {
|
||||||
max-height: 340px;
|
max-height: 340px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Louis pour etat places*/
|
||||||
|
|
||||||
|
|
||||||
|
.etat-bda td {
|
||||||
|
border:1px solid #666;
|
||||||
|
padding:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.etat-bda tr:nth-child(even) {background: #CCC}
|
||||||
|
|
||||||
|
.greenratio {
|
||||||
|
background-color: #3F3;
|
||||||
|
border: 5px solid #ccc;
|
||||||
|
border: 5px solid rgba(0, 0, 0, 0.15);
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.orangeratio {
|
||||||
|
background-color: #FF3;
|
||||||
|
border: 5px solid #ccc;
|
||||||
|
border: 5px solid rgba(0, 0, 0, 0.15);
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.redratio {
|
||||||
|
background-color: #F33;
|
||||||
|
border: 5px solid #ccc;
|
||||||
|
border: 5px solid rgba(0, 0, 0, 0.15);
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th[data-sort]{
|
||||||
|
cursor:pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.awesome{
|
||||||
|
color: red;
|
||||||
|
}
|
|
@ -10,6 +10,7 @@
|
||||||
<h2>Token : {{ token }}</h2>
|
<h2>Token : {{ token }}</h2>
|
||||||
<h2>Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h2>
|
<h2>Placés : {{ total_slots }} ; Déçus : {{ total_losers }}</h2>
|
||||||
{% if user.get_profile.is_buro %}<h2>Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €</h2>{% endif %}
|
{% if user.get_profile.is_buro %}<h2>Déficit total: {{ total_deficit }} €, Opéra: {{ opera_deficit }} €, Attribué: {{ total_sold }} €</h2>{% endif %}
|
||||||
|
<h2>Temps de calcul : {{ duration|floatformat }}s</h2>
|
||||||
|
|
||||||
{% for show, members, losers in results %}
|
{% for show, members, losers in results %}
|
||||||
<div class="attribresult">
|
<div class="attribresult">
|
||||||
|
|
|
@ -1,11 +1,49 @@
|
||||||
{% extends "base_title.html" %}
|
{% extends "base_title.html" %}
|
||||||
|
|
||||||
{% block realcontent %}
|
{% block realcontent %}
|
||||||
<h2>Etat des inscriptions BDA</h2>
|
<h2>État des inscriptions BdA</h2>
|
||||||
<ul>
|
<table class="etat-bda">
|
||||||
{% for spectacle in spectacles %}
|
<thead>
|
||||||
<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>
|
<tr>
|
||||||
|
<th data-sort="string">Titre</th>
|
||||||
|
<th data-sort="int">Date</th>
|
||||||
|
<th data-sort="string">Lieu</th>
|
||||||
|
<th data-sort="int">Places</th>
|
||||||
|
<th data-sort="int">Demandes</th>
|
||||||
|
<th data-sort="float">Ratio</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for spectacle in spectacles %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ spectacle.title }}</td>
|
||||||
|
<td data-sort-value="{{ spectacle.timestamp }}">{{ spectacle.date_no_seconds }}</td>
|
||||||
|
<td data-sort-value="{{ spectacle.location }}">{{ spectacle.location }}</td>
|
||||||
|
<td data-sort-value="{{ spectacle.slots }}">{{ spectacle.slots }} places</td>
|
||||||
|
<td data-sort-value="{{ spectacle.total }}">{{ spectacle.total }} demandes</td>
|
||||||
|
<td data-sort-value="{{ spectacle.ratio |stringformat:".3f" }}">
|
||||||
|
<div class={% if spectacle.ratio < 1.0 %}
|
||||||
|
"greenratio"
|
||||||
|
{% else %}
|
||||||
|
{% if spectacle.ratio < 2.5 %}
|
||||||
|
"orangeratio"
|
||||||
|
{% else %}
|
||||||
|
"redratio"
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}>
|
||||||
|
{{ spectacle.ratio |floatformat }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</tbody>
|
||||||
|
</table>
|
||||||
<strong>Total : <u>{{ total }} demandes</u></strong>
|
<strong>Total : <u>{{ total }} demandes</u></strong>
|
||||||
|
<script type="text/javascript" src="/gestion/media/js/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/gestion/media/js/joequery-Stupid-Table-Plugin/stupidtable.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function(){
|
||||||
|
$("table.etat-bda").stupidtable();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -91,10 +91,13 @@ var django = {
|
||||||
})(django.jQuery);
|
})(django.jQuery);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h2>Inscription au tirage au sort du BDA</h2>
|
<h2>Inscription au tirage au sort du BdA</h2>
|
||||||
{% if success %}
|
{% if success %}
|
||||||
<p class="success">Votre inscription a été mise à jour avec succès !</p>
|
<p class="success">Votre inscription a été mise à jour avec succès !</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if stateerror %}
|
||||||
|
<p class="error">Impossible d'enregistrer vos modifications: vous avez apporté d'autres modifications entre temps</p>
|
||||||
|
{% endif %}
|
||||||
<form id="bda_form" method="post" action="{% url 'bda-tirage-inscription' %}">
|
<form id="bda_form" method="post" action="{% url 'bda-tirage-inscription' %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% include "inscription-formset.html" %}
|
{% include "inscription-formset.html" %}
|
||||||
|
@ -104,6 +107,7 @@ var django = {
|
||||||
cloneMore('tbody.bda_formset_content tr:last-child', 'choixspectacle_set');
|
cloneMore('tbody.bda_formset_content tr:last-child', 'choixspectacle_set');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<input type="hidden" name="dbstate" value="{{ dbstate }}" />
|
||||||
<input type="submit" class="btn-submit" value="Enregistrer" />
|
<input type="submit" class="btn-submit" value="Enregistrer" />
|
||||||
Prix total actuel : {{ total_price }}€
|
Prix total actuel : {{ total_price }}€
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -22,14 +22,33 @@
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if user.profile.is_cof %}
|
||||||
<h3>BdA</h3>
|
<h3>BdA</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url "bda-tirage-inscription" %}">Inscription au tirage au sort du BdA</a></li>
|
Premier tirage
|
||||||
<li><a href="{% url "bda.views.etat_places" %}">Etat des demandes</a></li>
|
<!-- <li><a href="{% url "bda-tirage-inscription" %}">Inscription au premier tirage au sort du BdA</a></li> -->
|
||||||
<!-- <li><a href="{% url "bda.views.revente" %}">Revente de places BdA (premier tirage)</a></li> -->
|
<li><a href="{% url "bda-etat-places" %}">État des demandes</a></li>
|
||||||
<!-- <li><a href="{% url "bda2.views.revente" %}">Revente de places BdA (second tirage)</a></li> -->
|
<li><a href="{% url "bda-places-attribuees" %}">Mes places du premier tirage</a></li>
|
||||||
|
<li><a href="{% url "bda-revente" %}">Revendre une place du premier tirage</a></li>
|
||||||
|
<br>
|
||||||
|
<!-- Second tirage
|
||||||
|
<li><a href="{% url "bda2-tirage-inscription" %}">Inscription au deuxième tirage au sort du BdA</a></li>
|
||||||
|
<li><a href="{% url "bda2-etat-places" %}">État des demandes</a></li>
|
||||||
|
<li><a href="{% url "bda2-places-attribuees" %}">Mes places du deuxième tirage</a></li>
|
||||||
|
<li><a href="{% url "bda2-revente" %}">Revendre une place du deuxième tirage</a></li>
|
||||||
|
<br>
|
||||||
|
-->
|
||||||
|
Troisième tirage
|
||||||
|
<li><a href="{% url "bda3-tirage-inscription" %}">Inscription au troisième tirage au sort du BdA</a></li>
|
||||||
|
<li><a href="{% url "bda3-etat-places" %}">État des demandes</a></li>
|
||||||
|
<li><a href="{% url "bda3-places-attribuees" %}">Mes places du troisième tirage</a></li>
|
||||||
|
<li><a href="{% url "bda3-revente" %}">Revendre une place du troisième tirage</a></li>
|
||||||
|
<br>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h3>Divers</h3>
|
<h3>Divers</h3>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
<h3>Mega</h3>
|
<h3>Mega</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'gestioncof.views.export_mega_participants' %}">Export des participants</a></li>
|
<li><a href="{% url 'gestioncof.views.export_mega_participants' %}">Export des non-orgas uniquement</a></li>
|
||||||
<li><a href="{% url 'gestioncof.views.export_mega_orgas' %}">Export des orgas</a></li>
|
<li><a href="{% url 'gestioncof.views.export_mega_orgas' %}">Export des orgas uniquement</a></li>
|
||||||
<li><a href="{% url 'gestioncof.views.export_mega' %}">Export de tout le monde</a></li>
|
<li><a href="{% url 'gestioncof.views.export_mega' %}">Export de tout le monde</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue