from django.db import models from django.core.validators import EmailValidator from django.utils import timezone class ContactUs(models.Model): """ Contact Us model for handling contact form submissions. """ CATEGORY_CHOICES = [ ('همکاری', 'همکاری'), ('فروش', 'فروش'), ('پشتیبانی', 'پشتیبانی'), ('درخواست مشاور', 'درخواست مشاور'), ('سایر', 'سایر'), ] name = models.CharField(max_length=200, verbose_name='نام و نام خانوادگی') email_or_phone = models.CharField( max_length=200, verbose_name='ایمیل / شماره تماس', help_text='Can be either email or phone number' ) description = models.TextField(verbose_name='توضیحات') category = models.CharField( max_length=50, choices=CATEGORY_CHOICES, verbose_name='دسته‌بندی' ) created_at = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ایجاد') updated_at = models.DateTimeField(auto_now=True, verbose_name='تاریخ بروزرسانی') class Meta: verbose_name = 'تماس با ما' verbose_name_plural = 'تماس‌های با ما' ordering = ['-created_at'] indexes = [ models.Index(fields=['-created_at']), models.Index(fields=['category']), ] def __str__(self): return f"{self.name} - {self.category}" class Composition(models.Model): """ Composition model for storing composition information. """ name = models.CharField(max_length=200, verbose_name='نام') description = models.TextField(verbose_name='توضیحات') # Legacy single-image field, kept for backward compatibility. # New uploads use the related CompositionImage model below. image = models.ImageField( upload_to='compositions/', verbose_name='تصویر', null=True, blank=True ) created_at = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ایجاد') updated_at = models.DateTimeField(auto_now=True, verbose_name='تاریخ بروزرسانی') class Meta: verbose_name = 'ترکیب' verbose_name_plural = 'ترکیبات' ordering = ['-created_at'] indexes = [ models.Index(fields=['-created_at']), ] def __str__(self): return self.name @property def main_image(self): """Return the image flagged as main, falling back to the first image.""" return self.images.filter(is_main=True).first() or self.images.first() class CompositionImage(models.Model): """ Image belonging to a Composition. A composition can have many images, and at most one of them can be flagged as the main image. """ composition = models.ForeignKey( Composition, on_delete=models.CASCADE, related_name='images', verbose_name='ترکیب' ) image = models.ImageField( upload_to='compositions/', verbose_name='تصویر' ) is_main = models.BooleanField(default=False, verbose_name='تصویر اصلی') created_at = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ایجاد') class Meta: verbose_name = 'تصویر ترکیب' verbose_name_plural = 'تصاویر ترکیب' # Main image first, then newest. ordering = ['-is_main', '-created_at'] constraints = [ # At most one main image per composition. models.UniqueConstraint( fields=['composition'], condition=models.Q(is_main=True), name='unique_main_image_per_composition' ) ] def __str__(self): return f"{self.composition.name} - {'main' if self.is_main else 'image'} #{self.pk}" def save(self, *args, **kwargs): # Ensure only one main image per composition: if this one is being # set as main, unset the flag on the others. if self.is_main: CompositionImage.objects.filter( composition=self.composition, is_main=True ).exclude(pk=self.pk).update(is_main=False) super().save(*args, **kwargs) class Campaign(models.Model): """ Campaign model for storing campaign information. """ name = models.CharField(max_length=200, verbose_name='نام') description = models.TextField(verbose_name='توضیحات') start_time = models.DateTimeField(verbose_name='زمان شروع') end_time = models.DateTimeField(verbose_name='زمان پایان') image = models.ImageField( upload_to='campaigns/', verbose_name='تصویر', null=True, blank=True ) created_at = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ایجاد') updated_at = models.DateTimeField(auto_now=True, verbose_name='تاریخ بروزرسانی') class Meta: verbose_name = 'کمپین' verbose_name_plural = 'کمپین‌ها' ordering = ['-start_time'] indexes = [ models.Index(fields=['-start_time']), models.Index(fields=['end_time']), ] def __str__(self): return self.name def is_active(self): """Check if campaign is currently active.""" now = timezone.now() return self.start_time <= now <= self.end_time def is_upcoming(self): """Check if campaign is upcoming.""" return timezone.now() < self.start_time def is_ended(self): """Check if campaign has ended.""" return timezone.now() > self.end_time