forked from DGNum/gestioCOF
299c5f0823
- Liens invalide dans le template pour visualisé les places obtenues - Erreurs dans la vue pour visualiser l'état des demandes
301 lines
12 KiB
Python
301 lines
12 KiB
Python
# 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.core import serializers
|
|
from django.forms.models import inlineformset_factory
|
|
import hashlib
|
|
|
|
from django.core.mail import send_mail
|
|
from django.utils import timezone
|
|
|
|
from datetime import timedelta
|
|
import time
|
|
|
|
from gestioncof.decorators import cof_required, buro_required
|
|
from gestioncof.shared import send_custom_mail
|
|
from bda.models import Spectacle, Participant, ChoixSpectacle, Attribution, Tirage
|
|
from bda.algorithm import Algorithm
|
|
|
|
from bda.forms import BaseBdaFormSet, TokenForm, ResellForm
|
|
|
|
@cof_required
|
|
def etat_places(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
spectacles1 = ChoixSpectacle.objects.filter(spectacle__tirage=tirage
|
|
).filter(double_choice="1"
|
|
).all().values('spectacle','spectacle__title'
|
|
).annotate(total=models.Count('spectacle'))
|
|
spectacles2 = ChoixSpectacle.objects.filter(spectacle__tirage=tirage
|
|
).exclude(double_choice="1"
|
|
).all().values('spectacle','spectacle__title'
|
|
).annotate(total=models.Count('spectacle'))
|
|
spectacles = Spectacle.objects.filter(tirage=tirage).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 += 2*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, 'tirage': tirage})
|
|
|
|
def _hash_queryset(queryset):
|
|
data = serializers.serialize("json", queryset)
|
|
hasher = hashlib.sha256()
|
|
hasher.update(data)
|
|
return hasher.hexdigest()
|
|
|
|
@cof_required
|
|
def places(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
participant, created = Participant.objects.get_or_create(
|
|
user=request.user, tirage=tirage)
|
|
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,
|
|
"tirage": tirage,
|
|
"total": total,
|
|
"warning": warning})
|
|
|
|
@cof_required
|
|
def places_ics(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
participant, created = Participant.objects.get_or_create(
|
|
user=request.user, tirage=tirage)
|
|
places = participant.attribution_set.order_by(
|
|
"spectacle__date", "spectacle").all()
|
|
filtered_places = []
|
|
places_dict = {}
|
|
spectacles = []
|
|
for place in places:
|
|
if place.spectacle in spectacles:
|
|
places_dict[place.spectacle].double = True
|
|
else:
|
|
place.double = False
|
|
place.spectacle.dtend = place.spectacle.date + timedelta(seconds=7200)
|
|
places_dict[place.spectacle] = place
|
|
spectacles.append(place.spectacle)
|
|
filtered_places.append(place)
|
|
date = place.spectacle.date.date()
|
|
return render(request, "resume_places.ics",
|
|
{"participant": participant,
|
|
"places": filtered_places}, content_type="text/calendar")
|
|
|
|
@cof_required
|
|
def inscription(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
if timezone.now() > tirage.fermeture:
|
|
participant, created = Participant.objects.get_or_create(
|
|
user=request.user, tirage=tirage)
|
|
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 dans la journée !",
|
|
"choices": choices})
|
|
BdaFormSet = inlineformset_factory(Participant, ChoixSpectacle,
|
|
fields=("spectacle","double_choice","priority"), formset=BaseBdaFormSet)
|
|
participant, created = Participant.objects.get_or_create(
|
|
user=request.user, tirage=tirage)
|
|
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():
|
|
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,
|
|
'tirage': tirage,
|
|
"stateerror": stateerror})
|
|
|
|
def do_tirage(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
form = TokenForm(request.POST)
|
|
if not form.is_valid():
|
|
return tirage(request)
|
|
start = time.time()
|
|
data = {}
|
|
shows = Spectacle.objects.filter(tirage=tirage).select_related().all()
|
|
members = Participant.objects.filter(tirage=tirage).all()
|
|
choices = ChoixSpectacle.objects.filter(spectacle__tirage=tirage).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)
|
|
# À partir d'ici, le tirage devient effectif
|
|
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)
|
|
|
|
@buro_required
|
|
def tirage(request, tirage_id):
|
|
if request.POST:
|
|
form = TokenForm(request.POST)
|
|
if form.is_valid():
|
|
return do_tirage(request, tirage_id)
|
|
else:
|
|
form = TokenForm()
|
|
return render(request, "bda-token.html", {"form": form})
|
|
|
|
def do_resell(request, form):
|
|
spectacle = form.cleaned_data["spectacle"]
|
|
count = form.cleaned_data["count"]
|
|
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,
|
|
|
|
Je souhaite revendre %s pour %s le %s (%s) à %.02f€.
|
|
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)
|
|
send_mail("%s" % spectacle, mail,
|
|
request.user.email, ["bda-revente@lists.ens.fr"],
|
|
fail_silently = False)
|
|
return render(request, "bda-success.html", {"show": spectacle, "places": places})
|
|
|
|
@login_required
|
|
def revente(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
participant, created = Participant.objects.get_or_create(
|
|
user=request.user, tirage=tirage)
|
|
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, 'tirage': tirage})
|
|
|
|
@buro_required
|
|
def spectacle(request, tirage_id, spectacle_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
spectacle = get_object_or_404(Spectacle, id = spectacle_id, tirage=tirage)
|
|
return render(request, "bda-emails.html", {"spectacle": spectacle})
|
|
|
|
@buro_required
|
|
def unpaid(request, tirage_id):
|
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
unpaid = Participants.objects.filter(tirage=tirage, paid=False).all()
|
|
return render(request, "bda-unpaid.html", {"unpaid": unpaid})
|
|
|
|
@buro_required
|
|
def liste_spectacles_ics(request, tirage_id):
|
|
spectacles = Spectacle.objects.filter(tirage=tirage).order_by("date").all()
|
|
for spectacle in spectacles:
|
|
spectacle.dtend = spectacle.date + timedelta(seconds=7200)
|
|
return render(request, "liste_spectacles.ics",
|
|
{ "spectacles": spectacles, "tirage": tirage},
|
|
content_type="text/calendar")
|
|
|