Исправлены 4 проблемы: 1. Расчёт цены первого товара - улучшена валидация в getProductPrice и calculateFinalPrice 2. Отображение actual_price в Select2 вместо обычной цены 3. Количество по умолчанию = 1 для новых форм компонентов 4. Auto-select текста при клике на поле количества для удобства редактирования Изменённые файлы: - products/forms.py: добавлен __init__ в KitItemForm для quantity.initial = 1 - products/templates/includes/select2-product-init.html: обновлена formatSelectResult - products/templates/productkit_create.html: добавлен focus handler для auto-select - products/templates/productkit_edit.html: добавлен focus handler для auto-select 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
103 lines
4.3 KiB
Python
103 lines
4.3 KiB
Python
"""
|
||
Модели для работы с группами вариантов товаров.
|
||
Позволяет группировать взаимозаменяемые товары (например, розы разной длины).
|
||
"""
|
||
from django.db import models
|
||
|
||
|
||
class ProductVariantGroup(models.Model):
|
||
"""
|
||
Группа вариантов товара (взаимозаменяемые товары).
|
||
Например: "Роза красная Freedom" включает розы 50см, 60см, 70см.
|
||
"""
|
||
name = models.CharField(max_length=200, verbose_name="Название")
|
||
description = models.TextField(blank=True, 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 = ['name']
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
def get_products_count(self):
|
||
"""Возвращает количество товаров в группе"""
|
||
return self.items.count()
|
||
|
||
@property
|
||
def in_stock(self):
|
||
"""
|
||
Вариант в наличии, если хотя бы один из его товаров в наличии.
|
||
Товар в наличии, если Product.in_stock = True.
|
||
"""
|
||
return self.items.filter(product__in_stock=True).exists()
|
||
|
||
@property
|
||
def price(self):
|
||
"""
|
||
Цена варианта определяется по приоритету товаров:
|
||
1. Берётся цена товара с приоритетом 1, если он в наличии
|
||
2. Если нет - цена товара с приоритетом 2
|
||
3. И так далее по приоритетам
|
||
4. Если ни один товар не в наличии - берётся самый дорогой товар из группы
|
||
|
||
Возвращает Decimal (цену) или None если группа пуста.
|
||
"""
|
||
items = self.items.all().order_by('priority', 'id')
|
||
|
||
if not items.exists():
|
||
return None
|
||
|
||
# Ищем первый товар в наличии
|
||
for item in items:
|
||
if item.product.in_stock:
|
||
return item.product.sale_price
|
||
|
||
# Если ни один товар не в наличии - берем самый дорогой
|
||
max_price = None
|
||
for item in items:
|
||
if max_price is None or item.product.sale_price > max_price:
|
||
max_price = item.product.sale_price
|
||
|
||
return max_price
|
||
|
||
|
||
class ProductVariantGroupItem(models.Model):
|
||
"""
|
||
Товар в группе вариантов с приоритетом для этой конкретной группы.
|
||
Приоритет определяет порядок выбора товара при использовании группы в комплектах.
|
||
Например: в группе "Роза красная Freedom" - роза 50см имеет приоритет 1, 60см = 2, 70см = 3.
|
||
"""
|
||
variant_group = models.ForeignKey(
|
||
ProductVariantGroup,
|
||
on_delete=models.CASCADE,
|
||
related_name='items',
|
||
verbose_name="Группа вариантов"
|
||
)
|
||
product = models.ForeignKey(
|
||
'Product',
|
||
on_delete=models.CASCADE,
|
||
related_name='variant_group_items',
|
||
verbose_name="Товар"
|
||
)
|
||
priority = models.PositiveIntegerField(
|
||
default=0,
|
||
help_text="Меньше = выше приоритет (1 - наивысший приоритет в этой группе)"
|
||
)
|
||
|
||
class Meta:
|
||
verbose_name = "Товар в группе вариантов"
|
||
verbose_name_plural = "Товары в группах вариантов"
|
||
ordering = ['priority', 'id']
|
||
unique_together = [['variant_group', 'product']]
|
||
indexes = [
|
||
models.Index(fields=['variant_group', 'priority']),
|
||
models.Index(fields=['product']),
|
||
]
|
||
|
||
def __str__(self):
|
||
return f"{self.variant_group.name} - {self.product.name} (приоритет {self.priority})"
|