fix: Улучшения системы ценообразования комплектов

Исправлены 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>
This commit is contained in:
2025-11-02 19:04:03 +03:00
parent c84a372f98
commit 6c8af5ab2c
120 changed files with 9035 additions and 3036 deletions

View File

@@ -386,3 +386,126 @@ def update_product_in_stock_on_stock_delete(sender, instance, **kwargs):
"""
product_id = instance.product_id
_update_product_in_stock(product_id)
# ============================================================================
# Сигналы для автоматического обновления себестоимости товара (cost_price)
# ============================================================================
@receiver(post_save, sender=StockBatch)
def update_product_cost_on_batch_change(sender, instance, created, **kwargs):
"""
Сигнал: При создании или изменении партии (StockBatch) автоматически
обновляется себестоимость товара (Product.cost_price).
Процесс:
1. Проверяем, есть ли связанный товар
2. Вызываем ProductCostCalculator для пересчета средневзвешенной стоимости
3. Обновляем поле cost_price в БД
Триггеры:
- Создание новой партии (поступление товара)
- Изменение количества в партии
- Изменение стоимости партии
"""
if not instance.product:
return
# Импортируем здесь чтобы избежать circular import
from products.services.cost_calculator import ProductCostCalculator
try:
# Пересчитываем и обновляем себестоимость товара
ProductCostCalculator.update_product_cost(instance.product, save=True)
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(
f"Ошибка при обновлении себестоимости товара {instance.product.sku} "
f"после изменения партии {instance.id}: {e}",
exc_info=True
)
@receiver(post_delete, sender=StockBatch)
def update_product_cost_on_batch_delete(sender, instance, **kwargs):
"""
Сигнал: При удалении партии (StockBatch) автоматически
обновляется себестоимость товара.
Процесс:
1. После удаления партии пересчитываем себестоимость
2. Если партий не осталось - cost_price становится 0.00
"""
if not instance.product:
return
# Импортируем здесь чтобы избежать circular import
from products.services.cost_calculator import ProductCostCalculator
try:
# Пересчитываем и обновляем себестоимость товара
ProductCostCalculator.update_product_cost(instance.product, save=True)
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(
f"Ошибка при обновлении себестоимости товара после удаления партии: {e}",
exc_info=True
)
# ============================================================================
# Сигналы для динамического пересчета цен комплектов
# ============================================================================
@receiver(post_save, sender='products.Product')
def update_kit_prices_on_product_change(sender, instance, created, **kwargs):
"""
Сигнал: При изменении цены товара (price или sale_price)
автоматически пересчитываются цены всех комплектов, где используется этот товар.
Процесс:
1. Находим все KitItem с этим товаром
2. Для каждого комплекта вызываем recalculate_base_price()
3. base_price и price обновляются в БД
Триггеры:
- Изменение price (основная цена товара)
- Изменение sale_price (цена со скидкой товара)
"""
from products.models import KitItem
# Если это создание товара (не обновление), нет комплектов для пересчета
if created:
return
# Находим все KitItem с этим товаром
kit_items = KitItem.objects.filter(product=instance)
if not kit_items.exists():
return # Товар не используется в комплектах
# Для каждого комплекта пересчитываем цены
kits_to_update = set()
for item in kit_items:
kits_to_update.add(item.kit_id)
# Обновляем цены каждого комплекта
from products.models import ProductKit
for kit_id in kits_to_update:
try:
kit = ProductKit.objects.get(id=kit_id)
kit.recalculate_base_price()
except ProductKit.DoesNotExist:
pass
except Exception as e:
import logging
logger = logging.getLogger(__name__)
logger.error(
f"Ошибка при пересчете цены комплекта {kit_id} "
f"после изменения цены товара {instance.sku}: {e}",
exc_info=True
)