2016-07-15 00:02:56 +02:00
# -*- coding: utf-8 -*-
2012-07-11 17:39:20 +02:00
2016-07-25 02:52:49 +02:00
import random
2017-01-06 18:19:15 +01:00
import hashlib
import time
2017-03-15 07:37:24 +01:00
import json
2017-01-06 18:19:15 +01:00
from datetime import timedelta
2017-03-15 07:37:24 +01:00
from more_itertools import unique_everseen
2016-12-22 12:28:03 +01:00
from custommail . shortcuts import (
send_mass_custom_mail , send_custom_mail , render_custom_mail
)
2016-07-25 02:52:49 +02:00
2013-09-05 22:20:52 +02:00
from django . shortcuts import render , get_object_or_404
2012-07-11 17:39:20 +02:00
from django . contrib . auth . decorators import login_required
2017-01-29 17:13:01 +01:00
from django . contrib import messages
2016-11-05 22:35:46 +01:00
from django . db import models , transaction
2016-12-22 02:00:10 +01:00
from django . core import serializers
2017-01-07 13:13:12 +01:00
from django . db . models import Count , Q , Sum
2016-06-05 02:18:12 +02:00
from django . forms . models import inlineformset_factory
2017-03-15 07:37:24 +01:00
from django . http import HttpResponseBadRequest , HttpResponseRedirect , HttpResponse
2016-09-21 15:39:01 +02:00
from django . core . urlresolvers import reverse
2016-11-05 22:35:46 +01:00
from django . conf import settings
2017-01-29 17:13:01 +01:00
from django . utils import timezone , formats
2016-06-06 18:43:56 +02:00
from django . views . generic . list import ListView
2013-09-05 22:20:52 +02:00
from gestioncof . decorators import cof_required , buro_required
2016-07-09 22:31:56 +02:00
from bda . models import Spectacle , Participant , ChoixSpectacle , Attribution , \
2017-03-16 05:50:02 +01:00
Tirage , SpectacleRevente , Salle , Quote
2013-09-05 22:20:52 +02:00
from bda . algorithm import Algorithm
2016-07-27 13:08:00 +02:00
from bda . forms import BaseBdaFormSet , TokenForm , ResellForm , AnnulForm , \
2017-02-16 04:52:44 +01:00
InscriptionReventeForm , SoldForm
2012-07-11 17:39:20 +02:00
2016-07-09 21:19:37 +02:00
2013-10-01 15:27:19 +02:00
@cof_required
2016-06-05 02:18:12 +02:00
def etat_places ( request , tirage_id ) :
2017-01-06 18:19:15 +01:00
"""
Résumé des spectacles d ' un tirage avec pour chaque spectacle :
2017-01-07 13:13:12 +01:00
- Le nombre de places en jeu
2017-01-06 18:19:15 +01:00
- Le nombre de demandes
- Le ratio demandes / places
Et le total de toutes les demandes
"""
2016-06-05 02:18:12 +02:00
tirage = get_object_or_404 ( Tirage , id = tirage_id )
2016-06-06 11:11:33 +02:00
spectacles1 = ChoixSpectacle . objects \
. filter ( spectacle__tirage = tirage ) \
. filter ( double_choice = " 1 " ) \
. all ( ) \
2016-07-09 21:19:37 +02:00
. values ( ' spectacle ' , ' spectacle__title ' ) \
2016-06-06 11:11:33 +02:00
. annotate ( total = models . Count ( ' spectacle ' ) )
spectacles2 = ChoixSpectacle . objects \
. filter ( spectacle__tirage = tirage ) \
. exclude ( double_choice = " 1 " ) \
. all ( ) \
2016-07-09 21:19:37 +02:00
. values ( ' spectacle ' , ' spectacle__title ' ) \
2016-06-06 11:11:33 +02:00
. annotate ( total = models . Count ( ' spectacle ' ) )
2016-06-07 22:49:19 +02:00
spectacles = tirage . spectacle_set . all ( )
2013-09-05 22:20:52 +02:00
spectacles_dict = { }
total = 0
for spectacle in spectacles :
spectacle . total = 0
2015-01-06 11:01:15 +01:00
spectacle . ratio = 0.0
2013-09-05 22:20:52 +02:00
spectacles_dict [ spectacle . id ] = spectacle
for spectacle in spectacles1 :
spectacles_dict [ spectacle [ " spectacle " ] ] . total + = spectacle [ " total " ]
2016-06-05 02:18:12 +02:00
spectacles_dict [ spectacle [ " spectacle " ] ] . ratio = \
spectacles_dict [ spectacle [ " spectacle " ] ] . total / \
2016-06-10 15:43:37 +02:00
spectacles_dict [ spectacle [ " spectacle " ] ] . slots
2016-07-09 21:19:37 +02:00
total + = spectacle [ " total " ]
2013-09-05 22:20:52 +02:00
for spectacle in spectacles2 :
2016-05-21 23:57:36 +02:00
spectacles_dict [ spectacle [ " spectacle " ] ] . total + = 2 * spectacle [ " total " ]
2016-06-05 02:18:12 +02:00
spectacles_dict [ spectacle [ " spectacle " ] ] . ratio = \
spectacles_dict [ spectacle [ " spectacle " ] ] . total / \
2016-06-10 15:43:37 +02:00
spectacles_dict [ spectacle [ " spectacle " ] ] . slots
2017-01-06 18:19:15 +01:00
total + = 2 * spectacle [ " total " ]
2017-01-07 13:13:12 +01:00
context = {
" proposed " : tirage . spectacle_set . aggregate ( Sum ( ' slots ' ) ) [ ' slots__sum ' ] ,
" spectacles " : spectacles ,
" total " : total ,
' tirage ' : tirage
}
return render ( request , " bda/etat-places.html " , context )
2013-09-05 22:20:52 +02:00
2014-08-19 12:54:22 +02:00
def _hash_queryset ( queryset ) :
2016-09-24 17:34:15 +02:00
data = serializers . serialize ( " json " , queryset ) . encode ( ' utf-8 ' )
2014-08-19 12:54:22 +02:00
hasher = hashlib . sha256 ( )
hasher . update ( data )
return hasher . hexdigest ( )
2016-07-09 21:19:37 +02:00
2014-08-19 12:54:22 +02:00
@cof_required
2016-06-05 02:18:12 +02:00
def places ( request , tirage_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
participant , created = Participant . objects . get_or_create (
2016-07-09 22:31:56 +02:00
user = request . user , tirage = tirage )
2016-06-05 02:18:12 +02:00
places = participant . attribution_set . order_by (
2016-07-09 22:31:56 +02:00
" spectacle__date " , " spectacle " ) . all ( )
2014-08-19 12:54:22 +02:00
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 )
2017-01-29 22:49:32 +01:00
# On prévient l'utilisateur s'il a deux places à la même date
if warning :
messages . warning ( request , " Attention, vous avez reçu des places pour "
" des spectacles différents à la même date. " )
return render ( request , " bda/resume_places.html " ,
2014-08-19 12:54:22 +02:00
{ " participant " : participant ,
" places " : filtered_places ,
2016-06-05 02:18:12 +02:00
" tirage " : tirage ,
2017-01-29 22:49:32 +01:00
" total " : total } )
2014-08-19 12:54:22 +02:00
2016-07-09 21:19:37 +02:00
2013-09-05 22:20:52 +02:00
@cof_required
2016-06-05 02:18:12 +02:00
def inscription ( request , tirage_id ) :
2017-01-29 17:13:01 +01:00
"""
Vue d ' inscription à un tirage BdA.
- On vérifie qu ' on se situe bien entre la date d ' ouverture et la date de
fermeture des inscriptions .
- On vérifie que l ' inscription n ' a pas été modifiée entre le moment où le
client demande le formulaire et le moment où il soumet son inscription
( autre session par exemple ) .
"""
2016-06-05 02:18:12 +02:00
tirage = get_object_or_404 ( Tirage , id = tirage_id )
2016-06-06 19:22:01 +02:00
if timezone . now ( ) < tirage . ouverture :
2017-01-29 17:13:01 +01:00
# Le tirage n'est pas encore ouvert.
opening = formats . localize (
timezone . template_localtime ( tirage . ouverture ) )
messages . error ( request , " Le tirage n ' est pas encore ouvert : "
" ouverture le {:s} " . format ( opening ) )
return render ( request , ' bda/resume-inscription-tirage.html ' , { } )
2016-06-05 02:18:12 +02:00
if timezone . now ( ) > tirage . fermeture :
2017-01-29 17:13:01 +01:00
# Le tirage est fermé.
2016-06-05 02:18:12 +02:00
participant , created = Participant . objects . get_or_create (
2016-07-09 22:31:56 +02:00
user = request . user , tirage = tirage )
2014-08-19 12:54:22 +02:00
choices = participant . choixspectacle_set . order_by ( " priority " ) . all ( )
2017-01-29 17:13:01 +01:00
messages . error ( request ,
" C ' est fini : tirage au sort dans la journée ! " )
2017-01-08 19:53:31 +01:00
return render ( request , " bda/resume-inscription-tirage.html " ,
2017-01-29 17:13:01 +01:00
{ " choices " : choices } )
2016-07-09 22:31:56 +02:00
2016-06-06 11:19:27 +02:00
def formfield_callback ( f , * * kwargs ) :
2017-01-29 17:13:01 +01:00
"""
Fonction utilisée par inlineformset_factory ci dessous .
Restreint les spectacles proposés aux spectacles du bo tirage .
"""
2016-06-06 11:19:27 +02:00
if f . name == " spectacle " :
2016-06-07 22:49:19 +02:00
kwargs [ ' queryset ' ] = tirage . spectacle_set
2016-06-06 11:19:27 +02:00
return f . formfield ( * * kwargs )
BdaFormSet = inlineformset_factory (
2016-07-09 22:31:56 +02:00
Participant ,
ChoixSpectacle ,
fields = ( " spectacle " , " double_choice " , " priority " ) ,
formset = BaseBdaFormSet ,
formfield_callback = formfield_callback )
2016-06-05 02:18:12 +02:00
participant , created = Participant . objects . get_or_create (
2016-07-09 22:31:56 +02:00
user = request . user , tirage = tirage )
2012-07-11 17:39:20 +02:00
success = False
2014-08-19 12:54:22 +02:00
stateerror = False
2012-07-11 17:39:20 +02:00
if request . method == " POST " :
2014-08-19 12:54:22 +02:00
dbstate = _hash_queryset ( participant . choixspectacle_set . all ( ) )
if " dbstate " in request . POST and dbstate != request . POST [ " dbstate " ] :
stateerror = True
2016-06-04 13:25:35 +02:00
formset = BdaFormSet ( instance = participant )
2014-08-19 12:54:22 +02:00
else :
2016-06-04 13:25:35 +02:00
formset = BdaFormSet ( request . POST , instance = participant )
2014-08-19 12:54:22 +02:00
if formset . is_valid ( ) :
2016-06-05 02:18:12 +02:00
formset . save ( )
2014-08-19 12:54:22 +02:00
success = True
2016-06-04 13:25:35 +02:00
formset = BdaFormSet ( instance = participant )
2012-07-11 17:39:20 +02:00
else :
2016-06-04 13:25:35 +02:00
formset = BdaFormSet ( instance = participant )
2014-08-19 12:54:22 +02:00
dbstate = _hash_queryset ( participant . choixspectacle_set . all ( ) )
2013-09-05 22:20:52 +02:00
total_price = 0
2016-06-05 02:18:12 +02:00
for choice in participant . choixspectacle_set . all ( ) :
2013-09-05 22:20:52 +02:00
total_price + = choice . spectacle . price
2016-07-09 21:19:37 +02:00
if choice . double :
total_price + = choice . spectacle . price
2017-01-29 17:13:01 +01:00
# Messages
if success :
messages . success ( request , " Votre inscription a été mise à jour avec "
" succès ! " )
if stateerror :
messages . error ( request , " Impossible d ' enregistrer vos modifications "
" : vous avez apporté d ' autres modifications "
" entre temps. " )
2017-01-08 19:53:31 +01:00
return render ( request , " bda/inscription-tirage.html " ,
2016-07-09 22:31:56 +02:00
{ " formset " : formset ,
" total_price " : total_price ,
" dbstate " : dbstate ,
2017-01-29 17:13:01 +01:00
' tirage ' : tirage } )
2013-09-05 22:20:52 +02:00
2017-02-03 17:07:50 +01:00
def do_tirage ( tirage_elt , token ) :
"""
Fonction auxiliaire à la vue ` ` tirage ` ` qui lance effectivement le tirage
après qu ' on a vérifié que c ' est légitime et que le token donné en argument
est correct .
Rend les résultats
"""
# Initialisation du dictionnaire data qui va contenir les résultats
2014-08-19 12:54:22 +02:00
start = time . time ( )
2017-02-03 17:07:50 +01:00
data = {
' shows ' : tirage_elt . spectacle_set . select_related ( ) . all ( ) ,
' token ' : token ,
' members ' : tirage_elt . participant_set . all ( ) ,
' total_slots ' : 0 ,
' total_losers ' : 0 ,
' total_sold ' : 0 ,
' total_deficit ' : 0 ,
' opera_deficit ' : 0 ,
}
# On lance le tirage
choices = (
ChoixSpectacle . objects
. filter ( spectacle__tirage = tirage_elt )
. order_by ( ' participant ' , ' priority ' )
. select_related ( ) . all ( )
)
results = Algorithm ( data [ ' shows ' ] , data [ ' members ' ] , choices ) ( token )
# On compte les places attribuées et les déçus
2013-09-05 22:20:52 +02:00
for ( _ , members , losers ) in results :
2017-02-03 17:07:50 +01:00
data [ ' total_slots ' ] + = len ( members )
data [ ' total_losers ' ] + = len ( losers )
# On calcule le déficit et les bénéfices pour le BdA
# FIXME: le traitement de l'opéra est sale
2014-08-19 12:54:22 +02:00
for ( show , members , _ ) in results :
deficit = ( show . slots - len ( members ) ) * show . price
2017-02-03 17:07:50 +01:00
data [ ' total_sold ' ] + = show . slots * show . price
2013-09-05 22:20:52 +02:00
if deficit > = 0 :
2016-05-26 22:44:10 +02:00
if " Opéra " in show . location . name :
2017-02-03 17:07:50 +01:00
data [ ' opera_deficit ' ] + = deficit
data [ ' total_deficit ' ] + = deficit
data [ " total_sold " ] - = data [ ' total_deficit ' ]
# Participant objects are not shared accross spectacle results,
# so assign a single object for each Participant id
members_uniq = { }
members2 = { }
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
# ---
# On suppression les vieilles attributions, on sauvegarde le token et on
# désactive le tirage
Attribution . objects . filter ( spectacle__tirage = tirage_elt ) . delete ( )
tirage_elt . tokens + = ' {:s} \n " " " {:s} " " " \n ' . format (
timezone . now ( ) . strftime ( " % y- % m- %d % H: % M: % S " ) ,
token )
tirage_elt . enable_do_tirage = False
tirage_elt . save ( )
# On enregistre les nouvelles attributions
Attribution . objects . bulk_create ( [
Attribution ( spectacle = show , participant = member )
for show , members , _ in results
for member , _ , _ , _ in members
] )
# On inscrit à BdA-Revente ceux qui n'ont pas eu les places voulues
for ( show , _ , losers ) in results :
for ( loser , _ , _ , _ ) in losers :
loser . choicesrevente . add ( show )
loser . save ( )
2014-08-19 12:54:22 +02:00
data [ " duration " ] = time . time ( ) - start
2017-02-03 17:07:50 +01:00
data [ " results " ] = results
return data
2013-09-05 22:20:52 +02:00
2016-07-09 21:19:37 +02:00
2016-06-05 13:59:24 +02:00
@buro_required
2016-06-05 02:18:12 +02:00
def tirage ( request , tirage_id ) :
2016-07-08 20:33:26 +02:00
tirage_elt = get_object_or_404 ( Tirage , id = tirage_id )
2016-07-15 02:16:53 +02:00
if not ( tirage_elt . enable_do_tirage
and tirage_elt . fermeture < timezone . now ( ) ) :
2016-07-08 20:33:26 +02:00
return render ( request , " tirage-failed.html " , { ' tirage ' : tirage_elt } )
2013-09-05 22:20:52 +02:00
if request . POST :
form = TokenForm ( request . POST )
if form . is_valid ( ) :
2017-02-03 17:07:50 +01:00
results = do_tirage ( tirage_elt , form . cleaned_data [ ' token ' ] )
return render ( request , " bda-attrib-extra.html " , results )
2013-09-05 22:20:52 +02:00
else :
form = TokenForm ( )
return render ( request , " bda-token.html " , { " form " : form } )
2016-07-09 21:19:37 +02:00
2013-09-05 22:20:52 +02:00
@login_required
2016-06-05 02:18:12 +02:00
def revente ( request , tirage_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
participant , created = Participant . objects . get_or_create (
2016-07-09 22:31:56 +02:00
user = request . user , tirage = tirage )
2017-02-16 04:52:44 +01:00
2013-09-05 22:20:52 +02:00
if not participant . paid :
return render ( request , " bda-notpaid.html " , { } )
2017-02-16 04:52:44 +01:00
resellform = ResellForm ( participant , prefix = ' resell ' )
annulform = AnnulForm ( participant , prefix = ' annul ' )
soldform = SoldForm ( participant , prefix = ' sold ' )
2016-07-25 23:03:33 +02:00
if request . method == ' POST ' :
2016-12-20 22:24:07 +01:00
# On met en vente une place
2016-07-27 13:08:00 +02:00
if ' resell ' in request . POST :
resellform = ResellForm ( participant , request . POST , prefix = ' resell ' )
if resellform . is_valid ( ) :
2017-02-16 12:55:19 +01:00
datatuple = [ ]
2016-07-27 13:08:00 +02:00
attributions = resellform . cleaned_data [ " attributions " ]
2016-11-05 22:35:46 +01:00
with transaction . atomic ( ) :
for attribution in attributions :
2016-12-20 22:24:07 +01:00
revente , created = \
SpectacleRevente . objects . get_or_create (
attribution = attribution ,
defaults = { ' seller ' : participant } )
2016-11-05 22:35:46 +01:00
if not created :
revente . seller = participant
revente . date = timezone . now ( )
2016-12-21 03:45:30 +01:00
revente . soldTo = None
2016-11-13 01:45:52 +01:00
revente . notif_sent = False
revente . tirage_done = False
revente . shotgun = False
2017-02-16 12:55:19 +01:00
context = {
' vendeur ' : participant . user ,
' show ' : attribution . spectacle ,
' revente ' : revente
}
datatuple . append ( (
' bda-revente-new ' , context ,
settings . MAIL_DATA [ ' revente ' ] [ ' FROM ' ] ,
[ participant . user . email ]
) )
revente . save ( )
send_mass_custom_mail ( datatuple )
2016-12-20 22:24:07 +01:00
# On annule une revente
2016-07-27 13:08:00 +02:00
elif ' annul ' in request . POST :
annulform = AnnulForm ( participant , request . POST , prefix = ' annul ' )
if annulform . is_valid ( ) :
attributions = annulform . cleaned_data [ " attributions " ]
for attribution in attributions :
attribution . revente . delete ( )
2016-12-20 22:24:07 +01:00
# On confirme une vente en transférant la place à la personne qui a
# gagné le tirage
2016-09-05 02:29:49 +02:00
elif ' transfer ' in request . POST :
2017-02-16 04:52:44 +01:00
soldform = SoldForm ( participant , request . POST , prefix = ' sold ' )
if soldform . is_valid ( ) :
attributions = soldform . cleaned_data [ ' attributions ' ]
for attribution in attributions :
attribution . participant = attribution . revente . soldTo
attribution . save ( )
2016-12-20 22:24:07 +01:00
# On annule la revente après le tirage au sort (par exemple si
# la personne qui a gagné le tirage ne se manifeste pas). La place est
# alors remise en vente
2016-09-05 02:29:49 +02:00
elif ' reinit ' in request . POST :
2017-02-16 04:52:44 +01:00
soldform = SoldForm ( participant , request . POST , prefix = ' sold ' )
if soldform . is_valid ( ) :
attributions = soldform . cleaned_data [ ' attributions ' ]
for attribution in attributions :
if attribution . spectacle . date > timezone . now ( ) :
revente = attribution . revente
revente . date = timezone . now ( ) - timedelta ( minutes = 65 )
revente . soldTo = None
revente . notif_sent = False
revente . tirage_done = False
revente . shotgun = False
if revente . answered_mail :
revente . answered_mail . clear ( )
revente . save ( )
2016-09-05 02:29:49 +02:00
2016-07-27 13:08:00 +02:00
overdue = participant . attribution_set . filter (
2016-12-22 12:28:03 +01:00
spectacle__date__gte = timezone . now ( ) ,
revente__isnull = False ,
revente__seller = participant ,
2017-02-16 05:28:57 +01:00
revente__notif_sent = True ) \
. filter (
2016-09-05 02:29:49 +02:00
Q ( revente__soldTo__isnull = True ) | Q ( revente__soldTo = participant ) )
2016-07-27 13:08:00 +02:00
2017-02-21 23:49:29 +01:00
return render ( request , " bda/reventes.html " ,
2017-02-16 04:52:44 +01:00
{ ' tirage ' : tirage , ' overdue ' : overdue , " soldform " : soldform ,
2016-07-27 13:08:00 +02:00
" annulform " : annulform , " resellform " : resellform } )
2013-09-05 22:20:52 +02:00
2016-09-04 11:14:09 +02:00
@login_required
def revente_interested ( request , revente_id ) :
revente = get_object_or_404 ( SpectacleRevente , id = revente_id )
2016-12-22 12:28:03 +01:00
participant , _ = Participant . objects . get_or_create (
2016-09-04 11:14:09 +02:00
user = request . user , tirage = revente . attribution . spectacle . tirage )
2016-11-13 02:45:14 +01:00
if ( timezone . now ( ) < revente . date + timedelta ( hours = 1 ) ) or revente . shotgun :
return render ( request , " bda-wrongtime.html " ,
{ " revente " : revente } )
2016-09-04 11:14:09 +02:00
2016-09-27 15:44:27 +02:00
revente . answered_mail . add ( participant )
2016-09-04 11:14:09 +02:00
return render ( request , " bda-interested.html " ,
{ " spectacle " : revente . attribution . spectacle ,
2016-11-14 15:52:02 +01:00
" date " : revente . date_tirage } )
2016-09-04 11:14:09 +02:00
2016-07-25 02:52:49 +02:00
@login_required
def list_revente ( request , tirage_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
2016-12-22 12:28:03 +01:00
participant , _ = Participant . objects . get_or_create (
user = request . user , tirage = tirage )
2016-09-05 03:32:29 +02:00
deja_revente = False
2016-09-27 17:35:29 +02:00
success = False
2017-01-29 23:05:59 +01:00
inscrit_revente = [ ]
2016-07-27 13:08:00 +02:00
if request . method == ' POST ' :
form = InscriptionReventeForm ( tirage , request . POST )
if form . is_valid ( ) :
choices = form . cleaned_data [ ' spectacles ' ]
participant . choicesrevente = choices
participant . save ( )
2016-09-05 03:32:29 +02:00
for spectacle in choices :
qset = SpectacleRevente . objects . filter (
2016-12-22 12:28:03 +01:00
attribution__spectacle = spectacle )
2016-12-21 02:15:50 +01:00
if qset . filter ( shotgun = True , soldTo__isnull = True ) . exists ( ) :
# Une place est disponible au shotgun, on suggère à
# l'utilisateur d'aller la récupérer
deja_revente = True
else :
# La place n'est pas disponible au shotgun, si des reventes
# pour ce spectacle existent déjà, on inscrit la personne à
# la revente ayant le moins d'inscrits
min_resell = (
qset . filter ( shotgun = False )
. annotate ( nb_subscribers = Count ( ' answered_mail ' ) )
. order_by ( ' nb_subscribers ' )
. first ( )
)
if min_resell is not None :
min_resell . answered_mail . add ( participant )
min_resell . save ( )
2017-01-29 23:05:59 +01:00
inscrit_revente . append ( spectacle )
2016-09-27 17:35:29 +02:00
success = True
2016-07-27 13:08:00 +02:00
else :
form = InscriptionReventeForm (
2016-12-22 12:28:03 +01:00
tirage ,
2017-02-11 20:55:17 +01:00
initial = { ' spectacles ' : participant . choicesrevente . all ( ) }
)
2017-01-29 23:05:59 +01:00
# Messages
if success :
messages . success ( request , " Ton inscription a bien été prise en compte " )
if deja_revente :
messages . info ( request , " Des reventes existent déjà pour certains de "
" ces spectacles, vérifie les places "
" disponibles sans tirage ! " )
2017-02-04 00:01:15 +01:00
if inscrit_revente :
shows = map ( " <li> {!s} </li> " . format , inscrit_revente )
msg = (
" Tu as été inscrit à des reventes en cours pour les spectacles "
" <ul> {:s} </ul> " . format ( ' \n ' . join ( shows ) )
)
messages . info ( request , msg , extra_tags = " safe " )
2017-01-29 23:05:59 +01:00
return render ( request , " bda/liste-reventes.html " , { " form " : form } )
2016-07-25 02:52:49 +02:00
@login_required
def buy_revente ( request , spectacle_id ) :
spectacle = get_object_or_404 ( Spectacle , id = spectacle_id )
tirage = spectacle . tirage
2016-12-22 12:28:03 +01:00
participant , _ = Participant . objects . get_or_create (
user = request . user , tirage = tirage )
2016-07-25 02:52:49 +02:00
reventes = SpectacleRevente . objects . filter (
2016-12-22 12:28:03 +01:00
attribution__spectacle = spectacle ,
soldTo__isnull = True )
2016-11-13 01:45:52 +01:00
# Si l'utilisateur veut racheter une place qu'il est en train de revendre,
# on supprime la revente en question.
2016-09-21 15:39:01 +02:00
if reventes . filter ( seller = participant ) . exists ( ) :
revente = reventes . filter ( seller = participant ) [ 0 ]
revente . delete ( )
2016-10-13 16:02:52 +02:00
return HttpResponseRedirect ( reverse ( " bda-shotgun " ,
2016-09-21 15:39:01 +02:00
args = [ tirage . id ] ) )
2016-09-03 18:47:38 +02:00
2016-11-13 01:45:52 +01:00
reventes_shotgun = list ( reventes . filter ( shotgun = True ) . all ( ) )
if not reventes_shotgun :
2016-09-03 18:47:38 +02:00
return render ( request , " bda-no-revente.html " , { } )
2016-07-25 02:52:49 +02:00
if request . POST :
2016-11-13 01:45:52 +01:00
revente = random . choice ( reventes_shotgun )
2016-09-19 16:08:12 +02:00
revente . soldTo = participant
revente . save ( )
2016-12-22 02:00:10 +01:00
context = {
' show ' : spectacle ,
2016-11-08 10:01:01 +01:00
' acheteur ' : request . user ,
2016-12-22 02:00:10 +01:00
' vendeur ' : revente . seller . user
}
send_custom_mail (
2017-02-11 20:55:17 +01:00
' bda-buy-shotgun ' ,
2017-02-11 16:15:17 +01:00
' bda@ens.fr ' ,
[ revente . seller . user . email ] ,
2016-12-22 02:00:10 +01:00
context = context ,
)
2016-09-19 16:08:12 +02:00
return render ( request , " bda-success.html " ,
2016-09-25 14:39:18 +02:00
{ " seller " : revente . attribution . participant . user ,
2016-09-19 16:08:12 +02:00
" spectacle " : spectacle } )
2016-07-25 02:52:49 +02:00
return render ( request , " revente-confirm.html " ,
2016-09-03 18:47:38 +02:00
{ " spectacle " : spectacle ,
" user " : request . user } )
2016-07-25 02:52:49 +02:00
2016-10-06 13:46:18 +02:00
@login_required
def revente_shotgun ( request , tirage_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
spectacles = tirage . spectacle_set . filter (
2016-12-22 12:28:03 +01:00
date__gte = timezone . now ( ) )
2016-10-06 13:46:18 +02:00
shotgun = [ ]
for spectacle in spectacles :
2016-12-21 03:35:05 +01:00
reventes = SpectacleRevente . objects . filter (
2016-12-22 12:28:03 +01:00
attribution__spectacle = spectacle ,
shotgun = True ,
soldTo__isnull = True )
2016-12-21 03:35:05 +01:00
if reventes . exists ( ) :
2016-10-06 13:46:18 +02:00
shotgun . append ( spectacle )
2016-10-06 18:51:19 +02:00
return render ( request , " bda-shotgun.html " ,
2016-10-06 13:46:18 +02:00
{ " shotgun " : shotgun } )
2013-09-05 22:20:52 +02:00
@buro_required
2016-06-05 02:18:12 +02:00
def spectacle ( request , tirage_id , spectacle_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
2016-06-15 21:19:39 +02:00
spectacle = get_object_or_404 ( Spectacle , id = spectacle_id , tirage = tirage )
2016-06-12 18:36:21 +02:00
attributions = spectacle . attribues . all ( )
participants = { }
for attrib in attributions :
participant = attrib . participant
2016-07-09 21:19:37 +02:00
participant_info = { ' lastname ' : participant . user . last_name ,
' name ' : participant . user . get_full_name ,
' username ' : participant . user . username ,
' email ' : participant . user . email ,
' given ' : int ( attrib . given ) ,
' paid ' : participant . paid ,
2016-06-15 22:37:23 +02:00
' nb_places ' : 1 }
2016-06-12 19:29:50 +02:00
if participant . id in participants :
2016-07-09 21:19:37 +02:00
participants [ participant . id ] [ ' nb_places ' ] + = 1
2016-06-16 22:55:34 +02:00
participants [ participant . id ] [ ' given ' ] + = attrib . given
2016-06-12 18:36:21 +02:00
else :
2016-06-15 19:34:10 +02:00
participants [ participant . id ] = participant_info
2013-09-05 22:20:52 +02:00
2016-07-09 21:19:37 +02:00
participants_info = sorted ( participants . values ( ) ,
2016-07-09 22:31:56 +02:00
key = lambda part : part [ ' lastname ' ] )
2016-07-09 21:19:37 +02:00
return render ( request , " bda-participants.html " ,
2016-07-09 22:31:56 +02:00
{ " spectacle " : spectacle , " participants " : participants_info } )
2016-06-06 18:43:56 +02:00
class SpectacleListView ( ListView ) :
model = Spectacle
template_name = ' spectacle_list.html '
2016-07-09 21:19:37 +02:00
2016-06-06 18:43:56 +02:00
def get_queryset ( self ) :
self . tirage = get_object_or_404 ( Tirage , id = self . kwargs [ ' tirage_id ' ] )
2016-06-08 18:37:38 +02:00
categories = self . tirage . spectacle_set . all ( )
2016-06-06 18:43:56 +02:00
return categories
2016-07-09 21:19:37 +02:00
2016-06-06 18:43:56 +02:00
def get_context_data ( self , * * kwargs ) :
context = super ( SpectacleListView , self ) . get_context_data ( * * kwargs )
context [ ' tirage_id ' ] = self . tirage . id
2016-06-12 18:36:21 +02:00
context [ ' tirage_name ' ] = self . tirage . title
2016-06-06 18:43:56 +02:00
return context
2016-07-09 21:19:37 +02:00
2013-09-05 22:20:52 +02:00
@buro_required
2016-06-05 02:18:12 +02:00
def unpaid ( request , tirage_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
2016-06-22 02:29:20 +02:00
unpaid = tirage . participant_set \
2016-07-09 22:31:56 +02:00
. annotate ( nb_attributions = Count ( ' attribution ' ) ) \
. filter ( paid = False , nb_attributions__gt = 0 ) . all ( )
2016-06-05 02:18:12 +02:00
return render ( request , " bda-unpaid.html " , { " unpaid " : unpaid } )
2016-05-21 23:57:36 +02:00
2016-07-09 21:19:37 +02:00
2016-06-10 23:53:29 +02:00
@buro_required
def send_rappel ( request , spectacle_id ) :
show = get_object_or_404 ( Spectacle , id = spectacle_id )
# Mails d'exemples
2016-12-22 12:28:03 +01:00
exemple_mail_1place = render_custom_mail ( ' bda-rappel ' , {
2016-12-22 02:00:10 +01:00
' member ' : request . user ,
' show ' : show ,
' nb_attr ' : 1
} )
2016-12-22 12:28:03 +01:00
exemple_mail_2places = render_custom_mail ( ' bda-rappel ' , {
2016-12-22 02:00:10 +01:00
' member ' : request . user ,
' show ' : show ,
' nb_attr ' : 2
} )
2016-07-10 14:19:19 +02:00
# Contexte
ctxt = { ' show ' : show ,
' exemple_mail_1place ' : exemple_mail_1place ,
' exemple_mail_2places ' : exemple_mail_2places }
# Envoi confirmé
if request . method == ' POST ' :
members = show . send_rappel ( )
ctxt [ ' sent ' ] = True
ctxt [ ' members ' ] = members
# Demande de confirmation
else :
ctxt [ ' sent ' ] = False
2016-12-23 10:25:28 +01:00
return render ( request , " bda/mails-rappel.html " , ctxt )
2016-08-23 16:22:06 +02:00
def descriptions_spectacles ( request , tirage_id ) :
tirage = get_object_or_404 ( Tirage , id = tirage_id )
2016-08-26 06:06:45 +02:00
shows_qs = tirage . spectacle_set
category_name = request . GET . get ( ' category ' , ' ' )
location_id = request . GET . get ( ' location ' , ' ' )
if category_name :
shows_qs = shows_qs . filter ( category__name = category_name )
if location_id :
try :
shows_qs = shows_qs . filter ( location__id = int ( location_id ) )
except ValueError :
return HttpResponseBadRequest (
2016-12-22 12:28:03 +01:00
" La variable GET ' location ' doit contenir un entier " )
2016-08-26 06:06:45 +02:00
return render ( request , ' descriptions.html ' , { ' shows ' : shows_qs . all ( ) } )
2017-03-15 07:37:24 +01:00
def catalogue ( request , request_type ) :
"""
Vue destinée à communiquer avec un client AJAX , fournissant soit :
- la liste des tirages
- les catégories et salles d ' un tirage
- les descriptions d ' un tirage (filtrées selon la catégorie et la salle)
"""
if request_type == " list " :
# Dans ce cas on retourne la liste des tirages et de leur id sous forme de JSON
2017-03-16 06:34:49 +01:00
data_return = [ { ' id ' : tirage . id , ' title ' : tirage . title } for tirage in Tirage . objects . filter ( appear_catalogue = True ) . all ( ) ]
2017-03-15 07:37:24 +01:00
return HttpResponse ( json . dumps ( data_return ) )
if request_type == " details " :
# Dans ce cas on retourne une liste des catégories et des salles du tirage
try :
tirage_id = request . GET . get ( ' id ' , ' ' )
tirage = get_object_or_404 ( Tirage , id = tirage_id )
except :
return HttpResponseBadRequest ( )
categories = list ( unique_everseen ( [ str ( spectacle . category ) for spectacle in tirage . spectacle_set . all ( ) ] ) )
categories . remove ( ' None ' )
locations = list ( unique_everseen ( [ str ( spectacle . location ) for spectacle in tirage . spectacle_set . all ( ) ] ) )
data_return = [ { ' categories ' : categories , ' locations ' : locations } ]
return HttpResponse ( json . dumps ( data_return ) )
if request_type == " descriptions " :
# Ici on retourne les descriptions correspondant à la catégorie et à la salle spécifiées
locations = { }
for salle in Salle . objects . all ( ) :
locations [ salle . name ] = salle . id
try :
tirage_id = request . GET . get ( ' id ' , ' ' )
category_name = request . GET . get ( ' category ' , ' ' )
location_name = request . GET . get ( ' location ' , ' ' )
tirage = get_object_or_404 ( Tirage , id = tirage_id )
shows_qs = tirage . spectacle_set
if category_name :
shows_qs = shows_qs . filter ( category__name = category_name )
if location_name :
shows_qs = shows_qs . filter ( location__id = locations [ location_name ] )
except :
return HttpResponseBadRequest ( " Impossible de trouver des résultats correspondant à ces caractéristiques " )
def getImgUrl ( obj ) :
""" Cette fonction permet de gérer les cas où il n ' y a pas d ' image """
try :
return obj . image . url
except :
return ' '
2017-03-16 05:50:02 +01:00
specquotes = lambda spectacle : [ { ' author ' : str ( quote . author ) , ' text ' : str ( quote . text ) } for quote in Quote . objects . filter ( spectacle = spectacle ) . all ( ) ]
2017-03-15 07:37:24 +01:00
# On convertit les descriptions à envoyer en une liste facilement JSONifiable (il devrait y avoir un moyen plus efficace en redéfinissant le serializer de JSON)
2017-03-16 06:22:01 +01:00
data_return = [ { ' title ' : spectacle . title , ' category ' : str ( spectacle . category ) , ' date ' : str ( formats . date_format ( timezone . localtime ( spectacle . date ) , " SHORT_DATETIME_FORMAT " ) ) , ' location ' : str ( spectacle . location ) , ' vips ' : spectacle . vips , ' description ' : spectacle . description , ' slots_description ' : spectacle . slots_description , ' quotes ' : specquotes ( spectacle ) , ' image ' : getImgUrl ( spectacle ) , ' ext_link ' : spectacle . ext_link , ' price ' : spectacle . price , ' slots ' : spectacle . slots } for spectacle in shows_qs . all ( ) ]
2017-03-15 07:37:24 +01:00
return HttpResponse ( json . dumps ( data_return ) )
return HttpResponseBadRequest ( ) # Si la requête n'est pas de la forme attendue, on quitte avec une erreur