Files
octopus/myproject/COST_PRICE_QUICK_GUIDE.md
Andrey Smakotin 6c8af5ab2c 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>
2025-11-02 19:04:03 +03:00

7.7 KiB
Raw Blame History

Быстрый гид: Динамическая себестоимость товаров

Как это работает

Себестоимость товара теперь автоматически рассчитывается на основе партий товара (StockBatch) по формуле средневзвешенной стоимости:

cost_price = Σ(количество × стоимость) / Σ(количество)

Автоматическое обновление

Себестоимость обновляется автоматически при:

  • Создании новой партии (поступление товара)
  • Изменении количества в партии
  • Изменении стоимости партии
  • Удалении партии

Никаких дополнительных действий не требуется!

Просмотр деталей

На странице товара

  1. Откройте страницу товара: http://grach.localhost:8000/products/1/
  2. Найдите строку "Себестоимость"
  3. Нажмите кнопку "Детали расчета"
  4. Увидите:
    • Кешированную стоимость (из БД)
    • Рассчитанную стоимость (из партий)
    • Таблицу с разбивкой по партиям
    • Дату создания каждой партии

Примеры сценариев

Сценарий 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.00
  • ERROR: Ошибка при расчете себестоимости для товара 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

Контакты и поддержка

При возникновении проблем проверьте:

  1. Логи Django (ошибки при расчете)
  2. Страницу товара (секция "Детали расчета")
  3. Запустите команду с --dry-run для проверки

Версия: 1.0 Дата: 2025-01-01