Исправлены 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>
7.7 KiB
Быстрый гид: Динамическая себестоимость товаров
Как это работает
Себестоимость товара теперь автоматически рассчитывается на основе партий товара (StockBatch) по формуле средневзвешенной стоимости:
cost_price = Σ(количество × стоимость) / Σ(количество)
Автоматическое обновление
Себестоимость обновляется автоматически при:
- ✅ Создании новой партии (поступление товара)
- ✅ Изменении количества в партии
- ✅ Изменении стоимости партии
- ✅ Удалении партии
Никаких дополнительных действий не требуется!
Просмотр деталей
На странице товара
- Откройте страницу товара:
http://grach.localhost:8000/products/1/ - Найдите строку "Себестоимость"
- Нажмите кнопку "Детали расчета"
- Увидите:
- Кешированную стоимость (из БД)
- Рассчитанную стоимость (из партий)
- Таблицу с разбивкой по партиям
- Дату создания каждой партии
Примеры сценариев
Сценарий 1: Новый товар
Товар создан → cost_price = 0.00 (нет партий)
Сценарий 2: Первая поставка
Поступление: 10 шт по 100 руб
→ Автоматически: cost_price = 100.00
Сценарий 3: Вторая поставка
Текущее: 10 шт по 100 руб (cost_price = 100.00)
Поступление: 10 шт по 120 руб
→ Автоматически: cost_price = 110.00
Расчет: (10×100 + 10×120) / 20 = 110.00
Сценарий 4: Товар закончился
Продажа: весь товар продан
→ Автоматически: cost_price = 0.00
Сценарий 5: Новая поставка после опустошения
Поступление: 15 шт по 130 руб
→ Автоматически: cost_price = 130.00
Ручной пересчет (если нужно)
Если по какой-то причине себестоимость "слетела", можно пересчитать вручную:
# Пересчитать для тенанта grach
python manage.py recalculate_product_costs --schema=grach
# С подробным выводом
python manage.py recalculate_product_costs --schema=grach --verbose
# Предварительный просмотр без сохранения
python manage.py recalculate_product_costs --schema=grach --dry-run --verbose
# Показать только изменившиеся товары
python manage.py recalculate_product_costs --schema=grach --only-changed
Влияние на комплекты (ProductKit)
Стоимость комплектов теперь автоматически учитывает актуальную себестоимость компонентов!
# Раньше: использовалась статическая стоимость
# Теперь: использует динамическую стоимость из партий
kit_cost = sum(component.cost_price × quantity)
Проверка синхронизации
На странице товара в секции "Детали расчета":
- 🟢 Зеленый статус - все синхронизировано
- 🟡 Желтый статус - требуется синхронизация (запустите команду пересчета)
API для разработчиков
Получить детали расчета
from products.models import Product
product = Product.objects.get(id=1)
# Получить детали
details = product.cost_price_details
print(f"Кешированная стоимость: {details['cached_cost']}")
print(f"Рассчитанная стоимость: {details['calculated_cost']}")
print(f"Синхронизировано: {details['is_synced']}")
print(f"Всего в партиях: {details['total_quantity']}")
# Перебрать партии
for batch in details['batches']:
print(f"Склад: {batch['warehouse_name']}")
print(f"Количество: {batch['quantity']}")
print(f"Стоимость: {batch['cost_price']}")
Ручное обновление стоимости
from products.services.cost_calculator import ProductCostCalculator
# Рассчитать новую стоимость
new_cost = ProductCostCalculator.calculate_weighted_average_cost(product)
# Обновить в БД
old_cost, new_cost, was_updated = ProductCostCalculator.update_product_cost(product)
if was_updated:
print(f"Стоимость обновлена: {old_cost} → {new_cost}")
Логирование
Все операции логируются в стандартный Django logger:
import logging
logger = logging.getLogger('products.services.cost_calculator')
Примеры сообщений:
INFO: Обновлена себестоимость товара SKU-001: 100.00 -> 110.00ERROR: Ошибка при расчете себестоимости для товара SKU-001: ...
Производительность
Чтение cost_price
- 0 дополнительных запросов - значение читается из БД
Создание/изменение партии
- 1 дополнительный UPDATE - автоматическое обновление cost_price
Просмотр деталей (cost_price_details)
- 1 SELECT - запрос партий товара
FAQ
Q: Нужно ли что-то делать после создания партии? A: Нет! Себестоимость обновляется автоматически через Django signals.
Q: Что если у товара нет партий? A: cost_price = 0.00 (автоматически)
Q: Можно ли вручную установить себестоимость? A: Можно, но при следующем изменении партий значение пересчитается автоматически.
Q: Как проверить правильность расчета? A: Откройте "Детали расчета" на странице товара - там видна вся математика.
Q: Влияет ли это на ProductKit? A: Да! Стоимость комплектов теперь использует актуальную себестоимость компонентов.
Q: Что если синхронизация нарушилась?
A: Запустите python manage.py recalculate_product_costs --schema=grach
Техническая документация
Подробная техническая документация доступна в файле:
DYNAMIC_COST_PRICE_IMPLEMENTATION.md
Контакты и поддержка
При возникновении проблем проверьте:
- Логи Django (ошибки при расчете)
- Страницу товара (секция "Детали расчета")
- Запустите команду с --dry-run для проверки
Версия: 1.0 Дата: 2025-01-01