|
|
|
|
@ -273,7 +273,6 @@ def scan_view(request):
@@ -273,7 +273,6 @@ def scan_view(request):
|
|
|
|
|
error = None |
|
|
|
|
course = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if request.method == 'POST' and request.headers.get('x-requested-with') == 'XMLHttpRequest': |
|
|
|
|
course_id = request.POST.get('course_id') |
|
|
|
|
qrcode = request.POST.get('qrcode') |
|
|
|
|
@ -282,74 +281,72 @@ def scan_view(request):
@@ -282,74 +281,72 @@ def scan_view(request):
|
|
|
|
|
else: |
|
|
|
|
# S'assurer que l'utilisateur scanne uniquement ses propres courses |
|
|
|
|
course = get_object_or_404(Course, id=course_id, owner=request.user) |
|
|
|
|
if course.fin: |
|
|
|
|
error = "Cette course est terminée. Le scan n'est plus possible." |
|
|
|
|
else: |
|
|
|
|
# Le QR code contient maintenant l'identifiant unique du Coureur |
|
|
|
|
coureur = None |
|
|
|
|
try: |
|
|
|
|
coureur = Coureur.objects.get(id=qrcode.strip()) |
|
|
|
|
except Coureur.DoesNotExist: |
|
|
|
|
error = "Coureur introuvable pour ce code QR." |
|
|
|
|
|
|
|
|
|
if coureur: |
|
|
|
|
# Si la course est de type unique : comportement existant (1 arrivée par coureur) |
|
|
|
|
if course.type == Course.TYPE_UNIQUE: |
|
|
|
|
if Arrivee.objects.filter(course=course, coureur=coureur).exists(): |
|
|
|
|
error = "Ce coureur a déjà été scanné." |
|
|
|
|
else: |
|
|
|
|
temps = timezone.now() - course.depart |
|
|
|
|
rang = Arrivee.objects.filter(course=course).count() + 1 |
|
|
|
|
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=temps, rang=rang, tour=1) |
|
|
|
|
temps_str = seconds_to_hms(temps) |
|
|
|
|
# nombre total de scans pour cette course |
|
|
|
|
scan_count = Arrivee.objects.filter(course=course).count() |
|
|
|
|
result = { |
|
|
|
|
'nom': coureur.nom, |
|
|
|
|
'prenom': coureur.prenom, |
|
|
|
|
'classe': coureur.classe, |
|
|
|
|
'rang': arr.rang, |
|
|
|
|
'temps': temps_str, |
|
|
|
|
'tour': arr.tour, |
|
|
|
|
'scan_count': scan_count |
|
|
|
|
} |
|
|
|
|
# Pour les courses multi, autoriser plusieurs scans par coureur et calculer le tour/temps de tour |
|
|
|
|
|
|
|
|
|
# Le QR code contient maintenant l'identifiant unique du Coureur |
|
|
|
|
coureur = None |
|
|
|
|
try: |
|
|
|
|
coureur = Coureur.objects.get(id=qrcode.strip()) |
|
|
|
|
except Coureur.DoesNotExist: |
|
|
|
|
error = "Coureur introuvable pour ce code QR." |
|
|
|
|
|
|
|
|
|
if coureur: |
|
|
|
|
# Si la course est de type unique : comportement existant (1 arrivée par coureur) |
|
|
|
|
if course.type == Course.TYPE_UNIQUE: |
|
|
|
|
if Arrivee.objects.filter(course=course, coureur=coureur).exists(): |
|
|
|
|
error = "Ce coureur a déjà été scanné." |
|
|
|
|
else: |
|
|
|
|
# Compter les arrivées précédentes pour ce coureur sur cette course |
|
|
|
|
previous = Arrivee.objects.filter(course=course, coureur=coureur).order_by('tour', 'date_arrivee') |
|
|
|
|
last_arr = previous.last() |
|
|
|
|
if last_arr: |
|
|
|
|
# prochain tour = dernier tour + 1 |
|
|
|
|
next_tour = last_arr.tour + 1 |
|
|
|
|
lap_time = timezone.now() - last_arr.date_arrivee |
|
|
|
|
else: |
|
|
|
|
# premier scan pour ce coureur : tour 1, temps depuis le départ de la course |
|
|
|
|
next_tour = 1 |
|
|
|
|
lap_time = timezone.now() - course.depart |
|
|
|
|
# rang = nombre d'arrivées global + 1 |
|
|
|
|
temps = timezone.now() - course.depart |
|
|
|
|
rang = Arrivee.objects.filter(course=course).count() + 1 |
|
|
|
|
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=lap_time, rang=rang, tour=next_tour) |
|
|
|
|
lap_str = seconds_to_hms(lap_time) |
|
|
|
|
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=temps, rang=rang, tour=1) |
|
|
|
|
temps_str = seconds_to_hms(temps) |
|
|
|
|
# nombre total de scans pour cette course |
|
|
|
|
scan_count = Arrivee.objects.filter(course=course).count() |
|
|
|
|
result = { |
|
|
|
|
'nom': coureur.nom, |
|
|
|
|
'prenom': coureur.prenom, |
|
|
|
|
'classe': coureur.classe, |
|
|
|
|
'rang': arr.rang, |
|
|
|
|
'temps': lap_str, |
|
|
|
|
'temps': temps_str, |
|
|
|
|
'tour': arr.tour, |
|
|
|
|
'lap_seconds': int(lap_time.total_seconds()), |
|
|
|
|
'scan_count': scan_count |
|
|
|
|
} |
|
|
|
|
# Diffuser via le canal websocket |
|
|
|
|
channel_layer = get_channel_layer() |
|
|
|
|
async_to_sync(channel_layer.group_send)( |
|
|
|
|
f'course_{course.id}', |
|
|
|
|
{ |
|
|
|
|
'type': 'send_arrivee', |
|
|
|
|
'data': result |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
# Pour les courses multi, autoriser plusieurs scans par coureur et calculer le tour/temps de tour |
|
|
|
|
else: |
|
|
|
|
# Compter les arrivées précédentes pour ce coureur sur cette course |
|
|
|
|
previous = Arrivee.objects.filter(course=course, coureur=coureur).order_by('tour', 'date_arrivee') |
|
|
|
|
last_arr = previous.last() |
|
|
|
|
if last_arr: |
|
|
|
|
# prochain tour = dernier tour + 1 |
|
|
|
|
next_tour = last_arr.tour + 1 |
|
|
|
|
lap_time = timezone.now() - last_arr.date_arrivee |
|
|
|
|
else: |
|
|
|
|
# premier scan pour ce coureur : tour 1, temps depuis le départ de la course |
|
|
|
|
next_tour = 1 |
|
|
|
|
lap_time = timezone.now() - course.depart |
|
|
|
|
# rang = nombre d'arrivées global + 1 |
|
|
|
|
rang = Arrivee.objects.filter(course=course).count() + 1 |
|
|
|
|
arr = Arrivee.objects.create(course=course, coureur=coureur, temps=lap_time, rang=rang, tour=next_tour) |
|
|
|
|
lap_str = seconds_to_hms(lap_time) |
|
|
|
|
scan_count = Arrivee.objects.filter(course=course).count() |
|
|
|
|
result = { |
|
|
|
|
'nom': coureur.nom, |
|
|
|
|
'prenom': coureur.prenom, |
|
|
|
|
'classe': coureur.classe, |
|
|
|
|
'rang': arr.rang, |
|
|
|
|
'temps': lap_str, |
|
|
|
|
'tour': arr.tour, |
|
|
|
|
'lap_seconds': int(lap_time.total_seconds()), |
|
|
|
|
'scan_count': scan_count |
|
|
|
|
} |
|
|
|
|
# Diffuser via le canal websocket |
|
|
|
|
channel_layer = get_channel_layer() |
|
|
|
|
async_to_sync(channel_layer.group_send)( |
|
|
|
|
f'course_{course.id}', |
|
|
|
|
{ |
|
|
|
|
'type': 'send_arrivee', |
|
|
|
|
'data': result |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if result: |
|
|
|
|
return render(request, 'scan_result.html', {'result': result, 'course_type': course.type if course else None}) |
|
|
|
|
@ -360,19 +357,17 @@ def scan_view(request):
@@ -360,19 +357,17 @@ def scan_view(request):
|
|
|
|
|
course_id = request.GET.get('course_id') |
|
|
|
|
if course_id: |
|
|
|
|
course = get_object_or_404(Course, id=course_id, owner=request.user) |
|
|
|
|
if course.fin: |
|
|
|
|
error = "Cette course est terminée. Le scan n'est plus possible." |
|
|
|
|
|
|
|
|
|
# Formatage de la date pour affichage JJ/MM/AAAA |
|
|
|
|
date_str = format_date(course.date) if course_id and 'course' in locals() else '' |
|
|
|
|
date_str = format_date(course.date) if course else '' |
|
|
|
|
# nombre actuel de scans pour cette course |
|
|
|
|
scan_count = Arrivee.objects.filter(course=course).count() if course_id and 'course' in locals() else 0 |
|
|
|
|
scan_count = Arrivee.objects.filter(course=course).count() if course else 0 |
|
|
|
|
return render(request, 'scan.html', { |
|
|
|
|
'title': f'Scan course : {course.nom} ({date_str})' if course_id and 'course' in locals() else '', |
|
|
|
|
'title': f'Scan course : {course.nom} ({date_str})' if course else '', |
|
|
|
|
'courses': courses, |
|
|
|
|
'result': result, |
|
|
|
|
'error': error, |
|
|
|
|
'course': course if course_id and 'course' in locals() else None, |
|
|
|
|
'course': course, |
|
|
|
|
'scan_count': scan_count |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|