Louis Mazin a2fd47369d nice
2026-09-15 20:00:10 +02:00

229 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from django.contrib.auth.models import User
from django.db import transaction
from django.utils import timezone
from datetime import datetime, date, timedelta
from decouple import config
from .models import TimeEntry
from .serializers import (
TimeEntrySerializer,
TimeEntryCreateSerializer,
TimeEntryUpdateSerializer,
WeeklySummarySerializer
)
class TimeEntryListView(generics.ListAPIView):
serializer_class = TimeEntrySerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
user = self.request.user
# Staff members can view all entries, regular users only their own
if user.is_staff or user.is_superuser:
return TimeEntry.objects.all()
return TimeEntry.objects.filter(user=user)
class TimeEntryCreateView(generics.CreateAPIView):
serializer_class = TimeEntryCreateSerializer
permission_classes = [IsAuthenticated]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class TimeEntryScanView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
code = request.data.get('code')
if code == config('SECRET_POINTAGE_ENTER', default=''):
action = 'enter'
elif code == config('SECRET_POINTAGE_EXIT', default=''):
action = 'exit'
else:
return Response({'error': 'QR code de pointage invalide.'}, status=status.HTTP_400_BAD_REQUEST)
now = timezone.localtime()
with transaction.atomic():
open_entry = TimeEntry.objects.select_for_update().filter(
user=request.user,
date=now.date(),
start_time__isnull=False,
end_time__isnull=True,
).order_by('-start_time').first()
if action == 'enter':
if open_entry:
return Response({'error': 'Une entrée est déjà ouverte pour aujourd’hui.'}, status=status.HTTP_400_BAD_REQUEST)
entry = TimeEntry.objects.create(user=request.user, date=now.date(), start_time=now.time())
message = 'Entrée enregistrée.'
elif open_entry:
open_entry.end_time = now.time()
open_entry.save(update_fields=['end_time', 'updated_at'])
entry = open_entry
message = 'Sortie enregistrée.'
else:
entry = TimeEntry.objects.create(user=request.user, date=now.date(), end_time=now.time())
message = 'Sortie enregistrée sans entrée correspondante.'
return Response({'action': action, 'message': message, 'entry': TimeEntrySerializer(entry).data})
class TimeEntryDetailView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = TimeEntrySerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
user = self.request.user
# Staff members can view all entries, regular users only their own
if user.is_staff or user.is_superuser:
return TimeEntry.objects.all()
return TimeEntry.objects.filter(user=user)
class TimeEntryUpdateView(APIView):
permission_classes = [IsAuthenticated]
def put(self, request, entry_id):
try:
entry = TimeEntry.objects.get(id=entry_id)
# Check if user is authorized to update this entry
if not (request.user.is_staff or request.user.is_superuser or entry.user == request.user):
return Response(
{'error': 'Accès refusé'},
status=status.HTTP_403_FORBIDDEN
)
serializer = TimeEntryUpdateSerializer(entry, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except TimeEntry.DoesNotExist:
return Response(
{'error': 'Pointage non trouvé'},
status=status.HTTP_404_NOT_FOUND
)
class WeeklySummaryView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, user_id=None):
# If user_id is provided and user is staff, get that user's summary
# Otherwise, get current user's summary
if user_id and (request.user.is_staff or request.user.is_superuser):
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return Response(
{'error': 'Utilisateur non trouvé'},
status=status.HTTP_404_NOT_FOUND
)
else:
user = request.user
# Get current week (Monday to Sunday)
today = timezone.now().date()
start_of_week = today - timedelta(days=today.weekday())
end_of_week = start_of_week + timedelta(days=6)
# Get all time entries for the current week for this user
entries = TimeEntry.objects.filter(
user=user,
date__gte=start_of_week,
date__lte=end_of_week
).order_by('date')
# Group entries by day
days_data = []
for i in range(7):
current_day = start_of_week + timedelta(days=i)
day_entries = entries.filter(date=current_day)
if day_entries.exists():
# Get the first entry for this day (assuming one entry per day)
entry = day_entries.first()
days_data.append({
'date': entry.date.isoformat(),
'day': entry.date.strftime('%A'),
'start_time': str(entry.start_time) if entry.start_time else None,
'end_time': str(entry.end_time) if entry.end_time else None,
'duration': entry.duration
})
else:
days_data.append({
'date': current_day.isoformat(),
'day': current_day.strftime('%A'),
'start_time': None,
'end_time': None,
'duration': 0
})
total_hours = sum(entry.duration or 0 for entry in entries)
summary = {
'user': user.username,
'username': user.username,
'total_hours': round(total_hours, 2),
'days': days_data
}
serializer = WeeklySummarySerializer(summary)
return Response(serializer.data)
class UserWeeklySummaryView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
# Get current user's weekly summary
user = request.user
# Get current week (Monday to Sunday)
today = timezone.now().date()
start_of_week = today - timedelta(days=today.weekday())
end_of_week = start_of_week + timedelta(days=6)
# Get all time entries for the current week for this user
entries = TimeEntry.objects.filter(
user=user,
date__gte=start_of_week,
date__lte=end_of_week
).order_by('date')
# Group entries by day
days_data = []
for i in range(7):
current_day = start_of_week + timedelta(days=i)
day_entries = entries.filter(date=current_day)
if day_entries.exists():
# Get the first entry for this day (assuming one entry per day)
entry = day_entries.first()
days_data.append({
'date': entry.date.isoformat(),
'day': entry.date.strftime('%A'),
'start_time': str(entry.start_time) if entry.start_time else None,
'end_time': str(entry.end_time) if entry.end_time else None,
'duration': entry.duration
})
else:
days_data.append({
'date': current_day.isoformat(),
'day': current_day.strftime('%A'),
'start_time': None,
'end_time': None,
'duration': 0
})
total_hours = sum(entry.duration or 0 for entry in entries)
summary = {
'user': user.username,
'username': user.username,
'total_hours': round(total_hours, 2),
'days': days_data
}
serializer = WeeklySummarySerializer(summary)
return Response(serializer.data)