Initial commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from apps.bookings.models import Booking
|
||||
|
||||
admin.site.register(Booking)
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BookingsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "apps.bookings"
|
||||
@@ -0,0 +1,32 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
from apps.salons.models import Salon, Service, StaffProfile
|
||||
|
||||
|
||||
class BookingStatus(models.TextChoices):
|
||||
PENDING = "pending", "Pending"
|
||||
CONFIRMED = "confirmed", "Confirmed"
|
||||
CANCELLED = "cancelled", "Cancelled"
|
||||
COMPLETED = "completed", "Completed"
|
||||
|
||||
|
||||
class Booking(models.Model):
|
||||
salon = models.ForeignKey(Salon, on_delete=models.CASCADE, related_name="bookings")
|
||||
customer = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="bookings",
|
||||
)
|
||||
service = models.ForeignKey(Service, on_delete=models.PROTECT)
|
||||
staff = models.ForeignKey(StaffProfile, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
start_time = models.DateTimeField()
|
||||
end_time = models.DateTimeField()
|
||||
status = models.CharField(max_length=20, choices=BookingStatus.choices, default=BookingStatus.PENDING)
|
||||
price_amount = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
currency = models.CharField(max_length=10, default=getattr(settings, "DEFAULT_CURRENCY", "SAR"))
|
||||
notes = models.TextField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.customer.email} - {self.service.name}"
|
||||
@@ -0,0 +1,65 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.bookings.models import Booking
|
||||
from apps.salons.models import Service, StaffProfile
|
||||
|
||||
|
||||
class BookingSerializer(serializers.ModelSerializer):
|
||||
salon_name = serializers.CharField(source="salon.name", read_only=True)
|
||||
service_name = serializers.CharField(source="service.name", read_only=True)
|
||||
staff_name = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Booking
|
||||
fields = [
|
||||
"id",
|
||||
"salon",
|
||||
"salon_name",
|
||||
"service",
|
||||
"service_name",
|
||||
"staff",
|
||||
"staff_name",
|
||||
"start_time",
|
||||
"end_time",
|
||||
"status",
|
||||
"price_amount",
|
||||
"currency",
|
||||
"notes",
|
||||
"created_at",
|
||||
]
|
||||
read_only_fields = ["id", "salon", "status", "price_amount", "currency", "created_at"]
|
||||
|
||||
def get_staff_name(self, obj):
|
||||
if not obj.staff:
|
||||
return None
|
||||
first = obj.staff.user.first_name or ""
|
||||
last = obj.staff.user.last_name or ""
|
||||
return (first + " " + last).strip() or obj.staff.user.email
|
||||
|
||||
|
||||
class BookingCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Booking
|
||||
fields = ["service", "staff", "start_time", "end_time", "notes"]
|
||||
|
||||
def validate(self, attrs):
|
||||
service: Service = attrs["service"]
|
||||
staff = attrs.get("staff")
|
||||
if staff and staff.salon_id != service.salon_id:
|
||||
raise serializers.ValidationError("Selected staff does not belong to this salon")
|
||||
return attrs
|
||||
|
||||
def create(self, validated_data):
|
||||
request = self.context["request"]
|
||||
service = validated_data["service"]
|
||||
return Booking.objects.create(
|
||||
salon=service.salon,
|
||||
customer=request.user,
|
||||
service=service,
|
||||
staff=validated_data.get("staff"),
|
||||
start_time=validated_data["start_time"],
|
||||
end_time=validated_data["end_time"],
|
||||
notes=validated_data.get("notes", ""),
|
||||
price_amount=service.price_amount,
|
||||
currency=service.currency,
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
from django.urls import include, path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from apps.bookings.views import BookingViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r"", BookingViewSet, basename="booking")
|
||||
|
||||
urlpatterns = [
|
||||
path("", include(router.urls)),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from apps.bookings.models import Booking
|
||||
from apps.bookings.serializers import BookingCreateSerializer, BookingSerializer
|
||||
|
||||
|
||||
class BookingViewSet(viewsets.ModelViewSet):
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
if getattr(user, "is_superuser", False) or user.role == "admin":
|
||||
return Booking.objects.all().order_by("-created_at")
|
||||
if user.role == "manager":
|
||||
return Booking.objects.filter(salon__owner=user).order_by("-created_at")
|
||||
if user.role == "staff":
|
||||
return Booking.objects.filter(staff__user=user).order_by("-created_at")
|
||||
return Booking.objects.filter(customer=user).order_by("-created_at")
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "create":
|
||||
return BookingCreateSerializer
|
||||
return BookingSerializer
|
||||
Reference in New Issue
Block a user