77 lines
3.3 KiB
Python
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}" |