Files
e-trznice/backend/product/models.py
2025-10-02 00:54:34 +02:00

77 lines
3.3 KiB
Python

from django.db import models
from django.utils import timezone
from django.core.exceptions import ValidationError
from trznice.models import SoftDeleteModel
from booking.models import Event
from trznice.utils import truncate_to_minutes
class Product(SoftDeleteModel):
name = models.CharField(max_length=255, verbose_name="Název produktu")
code = models.PositiveIntegerField(unique=True, verbose_name="Unitatní kód produktu", null=True, blank=True)
def __str__(self):
return f"{self.name} : {self.code}"
def delete(self, *args, **kwargs):
self.event_products.all().update(is_deleted=True, deleted_at=timezone.now())
return super().delete(*args, **kwargs)
class EventProduct(SoftDeleteModel):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="event_products")
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="event_products")
start_selling_date = models.DateTimeField()
end_selling_date = models.DateTimeField()
def clean(self):
if not (self.start_selling_date and self.end_selling_date):
raise ValidationError("Datum začátku a konce musí být neprázné.")
# Vynecháme sekunky, mikrosecundy atd.
self.start_selling_date = truncate_to_minutes(self.start_selling_date)
self.end_selling_date = truncate_to_minutes(self.end_selling_date)
if not self.product_id or not self.event_id:
raise ValidationError("Zadejte Akci a Produkt.")
# Safely get product and event objects for error messages and validation
try:
product_obj = Product.objects.get(pk=self.product_id)
except Product.DoesNotExist:
raise ValidationError("Neplatné ID Zboží (Produktu).")
try:
event_obj = Event.objects.get(pk=self.event_id)
except Event.DoesNotExist:
raise ValidationError("Neplatné ID Akce (Eventu).")
# Overlapping sales window check
overlapping = EventProduct.objects.exclude(id=self.id).filter(
event_id=self.event_id,
product_id=self.product_id,
start_selling_date__lt=self.end_selling_date,
end_selling_date__gt=self.start_selling_date,
)
if overlapping.exists():
raise ValidationError("Toto zboží už se prodává v tomto období na této akci.")
# Ensure sale window is inside event bounds
# Event has DateFields (date), while these are DateTimeFields -> compare by date component
start_date = self.start_selling_date.date()
end_date = self.end_selling_date.date()
if start_date < event_obj.start or end_date > event_obj.end:
raise ValidationError("Prodej zboží musí být v rámci trvání akce.")
# Ensure product+event pair is unique
if EventProduct.objects.exclude(pk=self.pk).filter(product_id=self.product_id, event_id=self.event_id).exists():
raise ValidationError(f"V rámci akce {event_obj} už je {product_obj} zaregistrováno.")
def save(self, *args, **kwargs):
self.full_clean() # This includes clean_fields() + clean() + validate_unique()
super().save(*args, **kwargs)
def __str__(self):
return f"{self.product} at {self.event}"