""" Снапшоты комплектов для сохранения истории заказов. При добавлении комплекта (ProductKit) в заказ создается снимок его состояния, чтобы изменения в комплекте не влияли на историю заказов. """ from django.db import models from decimal import Decimal class KitSnapshot(models.Model): """ Снимок комплекта на момент заказа. Сохраняет название, цены и состав комплекта. """ # Связь с оригинальным комплектом (для аналитики) original_kit = models.ForeignKey( 'products.ProductKit', on_delete=models.SET_NULL, null=True, blank=True, related_name='snapshots', verbose_name="Оригинальный комплект", help_text="Ссылка на комплект, с которого создан снимок" ) # Копия основных данных комплекта name = models.CharField(max_length=200, verbose_name="Название") sku = models.CharField(max_length=100, blank=True, verbose_name="Артикул") description = models.TextField(blank=True, verbose_name="Описание") # Цены на момент заказа base_price = models.DecimalField( max_digits=10, decimal_places=2, default=Decimal('0'), verbose_name="Базовая цена" ) price = models.DecimalField( max_digits=10, decimal_places=2, default=Decimal('0'), verbose_name="Итоговая цена" ) sale_price = models.DecimalField( max_digits=10, decimal_places=2, null=True, blank=True, verbose_name="Цена со скидкой" ) # Корректировки цены price_adjustment_type = models.CharField( max_length=20, default='none', verbose_name="Тип корректировки" ) price_adjustment_value = models.DecimalField( max_digits=10, decimal_places=2, default=Decimal('0'), verbose_name="Значение корректировки" ) is_temporary = models.BooleanField(default=False, verbose_name="Временный комплект") created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") class Meta: verbose_name = "Снимок комплекта" verbose_name_plural = "Снимки комплектов" ordering = ['-created_at'] indexes = [ models.Index(fields=['original_kit']), models.Index(fields=['created_at']), ] def __str__(self): date_str = self.created_at.strftime('%d.%m.%Y %H:%M') if self.created_at else '' return f"Снимок: {self.name} ({date_str})" @property def actual_price(self): """Финальная цена (sale_price или price)""" if self.sale_price: return self.sale_price return self.price def get_total_components_count(self): """Количество компонентов в комплекте""" return self.items.count() class KitItemSnapshot(models.Model): """ Снимок компонента комплекта. Сохраняет информацию о товаре и его количестве в комплекте. """ kit_snapshot = models.ForeignKey( KitSnapshot, on_delete=models.CASCADE, related_name='items', verbose_name="Снимок комплекта" ) # Ссылка на оригинальный товар (для резервирования) original_product = models.ForeignKey( 'products.Product', on_delete=models.SET_NULL, null=True, blank=True, related_name='kit_item_snapshots', verbose_name="Оригинальный товар", help_text="Ссылка на товар для резервирования на складе" ) # Данные о товаре product_name = models.CharField( max_length=200, blank=True, verbose_name="Название товара" ) product_sku = models.CharField( max_length=100, blank=True, verbose_name="Артикул товара" ) product_price = models.DecimalField( max_digits=10, decimal_places=2, default=Decimal('0'), verbose_name="Цена товара" ) # Если был выбран из группы вариантов variant_group_name = models.CharField( max_length=200, blank=True, verbose_name="Группа вариантов" ) original_sales_unit = models.ForeignKey( 'products.ProductSalesUnit', on_delete=models.SET_NULL, null=True, blank=True, related_name='kit_item_snapshots', verbose_name="Единица продажи", help_text="Единица продажи на момент создания снимка" ) conversion_factor = models.DecimalField( max_digits=15, decimal_places=6, null=True, blank=True, verbose_name="Коэффициент конверсии", help_text="Сколько единиц продажи в 1 базовой единице товара" ) quantity = models.DecimalField( max_digits=10, decimal_places=3, verbose_name="Количество" ) class Meta: verbose_name = "Снимок компонента" verbose_name_plural = "Снимки компонентов" indexes = [ models.Index(fields=['kit_snapshot']), ] def __str__(self): name = self.product_name or self.variant_group_name or "Неизвестный товар" return f"{name} x{self.quantity}" @property def total_price(self): """Стоимость компонента (цена * количество)""" return self.product_price * self.quantity