from rest_framework import serializers from rest_framework.validators import UniqueValidator from trznice.utils import RoundedDateTimeField from .models import Product, EventProduct from booking.models import Event # from booking.serializers import EventSerializer class ProductSerializer(serializers.ModelSerializer): code = serializers.CharField( required=False, allow_null=True, allow_blank=True, help_text="Unikátní číselný kód produktu (volitelné)", ) events = serializers.SerializerMethodField(help_text="Seznam akcí (eventů), ve kterých se tento produkt prodává.") class Meta: model = Product fields = ["id", "name", "code", "events"] read_only_fields = ["id"] extra_kwargs = { "name": { "help_text": "Název zboží (max. 255 znaků).", "required": True, }, "code": { "help_text": "Unikátní kód zboží (např. 'FOOD-001'). Volitelné; pokud vyplněno, musí být jedinečný.", "required": False, "allow_null": True, "allow_blank": True, }, } def validate_name(self, value): value = value.strip() if not value: raise serializers.ValidationError("Název Zboží (Produktu) nemůže být prázdný.") if len(value) > 255: raise serializers.ValidationError("Název nesmí být delší než 255 znaků.") return value def validate_code(self, value): # Accept empty/null if value in (None, ""): return None # Uniqueness manual check (since we removed built-in validator to permit null/blank) qs = Product.objects.filter(code=value) if self.instance: qs = qs.exclude(pk=self.instance.pk) if qs.exists(): raise serializers.ValidationError("Produkt s tímto kódem už existuje.") return value def get_events(self, obj): # Expect prefetch: event_products__event events = [] # Access prefetched related if available to avoid N+1 event_products = getattr(obj, 'event_products_all', None) if event_products is None: # Fallback query (should be avoided if queryset is optimized) event_products = obj.event_products.select_related('event').all() for ep in event_products: if ep.event_id and hasattr(ep, 'event'): events.append({"id": ep.event_id, "name": ep.event.name}) return events class EventProductSerializer(serializers.ModelSerializer): product = ProductSerializer(read_only=True) product_id = serializers.PrimaryKeyRelatedField( queryset=Product.objects.all(), write_only=True ) start_selling_date = RoundedDateTimeField() end_selling_date = RoundedDateTimeField() class Meta: model = EventProduct fields = [ 'id', 'product', # nested read-only 'product_id', # required in POST/PUT 'event', 'start_selling_date', 'end_selling_date', ] read_only_fields = ["id", "product"] extra_kwargs = { "product": { "help_text": "Detail zboží (jen pro čtení).", "required": False, "read_only": True, }, "product_id": { "help_text": "ID zboží, které je povoleno prodávat na akci.", "required": True, "write_only": True, }, "event": { "help_text": "ID akce (Event), pro kterou je zboží povoleno.", "required": True, }, "start_selling_date": { "help_text": "Začátek prodeje v rámci akce (musí spadat do [event.start, event.end]).", "required": True, }, "end_selling_date": { "help_text": "Konec prodeje v rámci akce (po start_selling_date, také v rámci [event.start, event.end]).", "required": True, }, } def create(self, validated_data): validated_data["product"] = validated_data.pop("product_id") return super().create(validated_data) def validate(self, data): product = data.get("product_id") event = data.get("event") start = data.get("start_selling_date") end = data.get("end_selling_date") if start >= end: raise serializers.ValidationError("Datum začátku prodeje musí být dříve než jeho konec.") if event and (start < event.start or end > event.end): raise serializers.ValidationError("Prodej zboží musí být v rámci trvání akce.") # When updating, exclude self instance instance_id = self.instance.id if self.instance else None # Check for overlapping EventProducts for the same product/event overlapping = EventProduct.objects.exclude(id=instance_id).filter( event=event, product_id=product, start_selling_date__lt=end, end_selling_date__gt=start, ) if overlapping.exists(): raise serializers.ValidationError("Toto zboží už se prodává v tomto období na této akci.") # # Check for duplicate product-event pair # duplicate = EventProduct.objects.exclude(id=instance_id).filter( # event=event, # product_id=product, # ) # if duplicate.exists(): # raise serializers.ValidationError(f"V rámci akce {event} už je {product} zaregistrováno.") return data