from django.db import models from django.utils.text import slugify from account.models import User from django.urls import reverse import requests from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from home.models import ShowCaseSlider class MainCategoryModel(models.Model): name = models.CharField(max_length=50, verbose_name='نام دسته بندی') slug = models.SlugField(max_length=50, unique=True, help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید") icon = models.ImageField(upload_to='category_model/',verbose_name='آیکون', blank=True, null=True) image = models.ImageField(upload_to='category_model/',verbose_name='عکس', blank=True, null=True) meta_title = models.CharField(max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True) meta_description = models.TextField(max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True) video = models.FileField(upload_to='category_videos/', blank=True, null=True, verbose_name='ویدیو') class Meta: verbose_name = "دسته‌بندی اصلی" verbose_name_plural = "دسته‌بندی‌هااصلی" def __str__(self): return self.name def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name, allow_unicode=True) super().save(*args, **kwargs) class SubCategoryModel(models.Model): name = models.CharField(max_length=50, verbose_name='نام دسته بندی') slug = models.SlugField(max_length=50, unique=True, help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید") image = models.ImageField(upload_to='category_model/',verbose_name='عکس', blank=True, null=True) icon = models.ImageField(upload_to='category_model/',verbose_name='آیکون', blank=True, null=True) meta_title = models.CharField(max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True) meta_description = models.TextField(max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True) parent = models.ForeignKey(MainCategoryModel, on_delete=models.CASCADE, related_name='subcategorys', verbose_name='دسته‌بندی والد') class Meta: verbose_name = "زیر دسته‌بندی" verbose_name_plural = "زیر دسته‌بندی‌ها" def __str__(self): return self.name def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name, allow_unicode=True) super().save(*args, **kwargs) class DollorModel(models.Model): price = models.FloatField(null=True, blank=True, verbose_name='قیمت دلار') defualt_price = models.FloatField(null=True, blank=True, default=80000.0, verbose_name='قیمت دستی') # these fields will avoid dublicate of this model unique = (('unique', 'unique'),) unique_filed = models.CharField(max_length=20, choices=unique, unique=True, default='unique') def __str__(self): return str(self.price) def save(self, *args, **kwargs): if not self.price: self.update_price() super().save(*args, **kwargs) def update_price(self): self.price = self.get_usd_price() def get_usd_price(self): try: api_usd = "https://api.nobitex.ir/v2/orderbook/USDTIRT" response = requests.get(api_usd) data = response.json() price = int(data["lastTradePrice"]) price_in_usd = price / 10.0 print('\n\nprice from api \n\n') except: if self.price: print('\n\nprice from last price \n\n') return self.price else: print('\n\nprice from defualt price \n\n') return self.defualt_price return price_in_usd class Meta: verbose_name = 'مدل دلار' verbose_name_plural = 'مدل دلار' class InPackItems(models.Model): item_title = models.CharField(max_length=50) cover = models.ImageField(upload_to='product_items/', verbose_name='کاور ایتم') class Meta: verbose_name = 'ایتم داخل پک' verbose_name_plural = 'ایتم های داخل پک' def __str__(self): return self.item_title class ProductModel(models.Model): name = models.CharField(max_length=255, verbose_name='نام') description = models.TextField(verbose_name='توضیحات') rating = models.PositiveIntegerField(default=0, verbose_name='امتیاز') show = models.BooleanField(default=False, verbose_name='نمایش در خانه') view = models.IntegerField(default=0, verbose_name='بازدید') slug = models.SlugField(max_length=50, unique=True, blank=True, null=True, allow_unicode=True, verbose_name='نام یکتا', help_text="این فیلد را خالی بگذارید") meta_description = models.CharField(max_length=300, blank=True, null=True, help_text='این فیلد را حتما پر کنید', verbose_name='متا دیسکریپشن') meta_keywords = models.CharField(max_length=300, blank=True, null=True, help_text='این فیلد را حتما پر کنید', verbose_name='متا کیورد') meta_rating = models.FloatField(default=5, help_text='امتیاز محصول', verbose_name='متا ریتینگ') created_at = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت محصول') category = models.ForeignKey(SubCategoryModel, null=True, on_delete=models.SET_NULL, related_name='products', verbose_name='دسته بندی محصول') related_products = models.ManyToManyField('self', blank=True, verbose_name='محصولات مرتبط') def __str__(self): return self.name def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name, allow_unicode=True) super().save(*args, **kwargs) class Meta: verbose_name = 'محصول' verbose_name_plural = 'محصولات' class ProductDetailCategory(models.Model): title = models.CharField(max_length=40, verbose_name='عنوان') def __str__(self): return self.title class Meta: verbose_name = 'دسته بندی جزيات' verbose_name_plural = 'دسته بندی های جزيیات' class CommentModel(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='comments', verbose_name='محصول') title = models.CharField(max_length=50) content = models.TextField(verbose_name='محتوای نظر') user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='کاربر') timestamp = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت کامنت') status_types = ( ('reviewed_and_confirmed', 'بررسی و تایید شده'), ('reviewed_and_rejected', 'بررسی شده و رد شده'), ('not_reviwed', 'بررسی نشده'), ) review_status = models.CharField(default='not_reviwed', verbose_name='نشان دادن کامنت', max_length=30, choices=status_types) class Meta: verbose_name = 'نظر' verbose_name_plural = 'نظرات' def __str__(self): return f"{self.user}-{self.content[:30]}" class AttributeType(models.Model): name = models.CharField(verbose_name='نام نوع متغییر', max_length=100) def __str__(self): return self.name class Meta: verbose_name = 'نوع متغییر محصول' verbose_name_plural = 'نوع های متغییر محصول' class AttributeValue(models.Model): attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE, blank=True, null=True) value = models.CharField(verbose_name='مقدار نوع اتربیوت', max_length=100, blank=True, null=True) class Meta: unique_together = ('attribute_type', 'value') verbose_name = 'مقدار متغییر محصول' verbose_name_plural = 'مقدار های متغییر محصول' def __str__(self): return f"{self.attribute_type}: {self.value}" class ProductImageModel(models.Model): name = models.CharField(max_length=30, verbose_name='نام عکس') image = models.ImageField(upload_to='product_images/') def __str__(self): return self.name class Meta: verbose_name = 'عکس محصولات' verbose_name_plural = 'عکس های محصولات' class ProductDetailModel(models.Model): name = models.CharField(max_length=50, verbose_name='نام جزيیات', help_text='این متن فقط برای راحتی در استفاده از پنل ادمین میباشد') detail_category = models.ForeignKey(ProductDetailCategory, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات') class Meta: verbose_name = 'جزیات محصول' verbose_name_plural = 'جزیات محصول ها' def __str__(self): return f'جزيیات محصول {self.detail_category.title} - {self.name}' class DetailModel(models.Model): title = models.CharField(max_length=50, verbose_name='عنوان') detail_text1 = models.CharField(max_length=150 , verbose_name='متن جزیات ۱') detail_text2 = models.CharField(max_length=150 , verbose_name='متن جزیات ۲', blank=True, null=True) detail_text3 = models.CharField(max_length=150 , verbose_name='متن جزیات ۳', blank=True, null=True) detail_text4 = models.CharField(max_length=150 , verbose_name='متن جزیات ۴', blank=True, null=True) detail_model = models.ForeignKey(ProductDetailModel, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات', related_name='details') def __str__(self): return f'{self.title}' class Meta: verbose_name = 'مدل جزیات' verbose_name_plural = 'مدل های جزیات' class ProductVariant(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول') product_attributes = models.ManyToManyField(AttributeValue, verbose_name='ویژگی‌ها', related_name='variant') in_stock = models.PositiveIntegerField(default=0, verbose_name='تعداد موجود') price = models.PositiveIntegerField(verbose_name='قیمت محاسبه شده', blank=True, null=True) input_price = models.PositiveIntegerField(default=0, verbose_name='قیمت ورودی') min_price = models.PositiveIntegerField(verbose_name='قیمت کف', help_text='این قیمت برای کف قیمتی محصول در نظر گرفته میشود') currency_type = ( ('dollor', 'دلار'), ('toman', 'تومان'), ('derham', 'درهم') ) in_pack_items = models.ManyToManyField(InPackItems, blank=True, verbose_name='ایتم های داخل پک') sell = models.IntegerField(default=0, verbose_name='فروش') currency = models.CharField(verbose_name='نوع ارز', max_length=20, choices=currency_type) discount = models.SmallIntegerField(default=0, verbose_name='تخفیف') color = models.CharField(verbose_name='رنگ', max_length=7, blank=True, null=True) images = models.ManyToManyField(ProductImageModel, verbose_name='عکس ها') video = models.FileField(upload_to='product_videos/', blank=True, null=True, verbose_name='ویدیو') details = models.ManyToManyField(ProductDetailModel, verbose_name='جزییات محصول', related_name='product') slider_category = models.ForeignKey(ShowCaseSlider, verbose_name='دسته بندی پورسانتی', blank=True, null=True, on_delete=models.CASCADE) class Meta: verbose_name = 'تنوع محصول' verbose_name_plural = 'تنوع‌های محصول' def __str__(self): return f"{self.product.name} - {', '.join(str(attr) for attr in self.product_attributes.all())}" def set_or_update_price(self, dollor_price=None): if not dollor_price: dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') dollor_price = dollor_object.price if dollor_price is None: raise ValidationError({"dollor_price": "The 'dollor_price' must be provided in the context for dollar pricing."}) dollar_to_dirham = 0.27 if self.currency == 'toman': toman_price = self.input_price elif self.currency == 'dollor': toman_price = self.input_price * dollor_price elif self.currency == 'derham': toman_price = self.input_price * dollor_price * dollar_to_dirham else: toman_price = self.input_price self.price = max(toman_price, self.min_price) def save(self, *args, **kwargs): self.set_or_update_price() super().save(*args, **kwargs)