This commit is contained in:
2025-10-02 00:54:34 +02:00
commit 84b34c9615
200 changed files with 42048 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
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