Initial commit: Django inventory system
This commit is contained in:
160
myproject/docs/README_VARIANTS.md
Normal file
160
myproject/docs/README_VARIANTS.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Система вариантов товаров - Краткое руководство
|
||||
|
||||
## Что реализовано
|
||||
|
||||
Система позволяет создавать букеты с гибкими заменами компонентов. Каждый букет может иметь свои индивидуальные приоритеты для одной и той же группы товаров.
|
||||
|
||||
## Новые модели
|
||||
|
||||
1. **ProductVariantGroup** - группа взаимозаменяемых товаров
|
||||
2. **KitItemPriority** - приоритеты товаров для конкретной позиции букета
|
||||
|
||||
## Изменения в существующих моделях
|
||||
|
||||
1. **Product** - добавлено поле `variant_groups` (M2M)
|
||||
2. **KitItem** - добавлены поля `variant_group`, `notes`
|
||||
3. **ProductKit** - добавлены методы проверки доступности и расчета цен
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
### 1. Запуск демо
|
||||
|
||||
```bash
|
||||
python manage.py demo_variants
|
||||
```
|
||||
|
||||
Это создаст демонстрационные данные и покажет работу системы.
|
||||
|
||||
### 2. Создание группы вариантов через админку
|
||||
|
||||
1. Откройте `/admin/`
|
||||
2. Перейдите в "Группы вариантов"
|
||||
3. Создайте новую группу (например, "Роза красная Freedom")
|
||||
4. Откройте товары и добавьте их в группу через поле "Группы вариантов"
|
||||
|
||||
### 3. Создание букета с вариантами
|
||||
|
||||
1. Создайте новый комплект
|
||||
2. Добавьте позицию:
|
||||
- Либо укажите конкретный товар (без замен)
|
||||
- Либо укажите группу вариантов (с заменами)
|
||||
3. Откройте позицию и настройте приоритеты в разделе "Приоритеты вариантов"
|
||||
|
||||
## API для разработчиков
|
||||
|
||||
### Проверка доступности букета
|
||||
|
||||
```python
|
||||
from products.models import ProductKit
|
||||
from products.utils.stock_manager import StockManager
|
||||
|
||||
kit = ProductKit.objects.get(name="Мой букет")
|
||||
stock_manager = StockManager()
|
||||
|
||||
if kit.check_availability(stock_manager):
|
||||
print("Букет доступен!")
|
||||
price = kit.calculate_price_with_substitutions(stock_manager)
|
||||
print(f"Цена: {price}")
|
||||
```
|
||||
|
||||
### Получение лучшего товара для позиции
|
||||
|
||||
```python
|
||||
from products.models import KitItem
|
||||
from products.utils.stock_manager import StockManager
|
||||
|
||||
kit_item = KitItem.objects.get(id=1)
|
||||
stock_manager = StockManager()
|
||||
|
||||
best_product = kit_item.get_best_available_product(stock_manager)
|
||||
if best_product:
|
||||
print(f"Используем: {best_product.name}")
|
||||
```
|
||||
|
||||
## Файлы документации
|
||||
|
||||
- [product_variants_guide.md](product_variants_guide.md) - подробное руководство
|
||||
- [example_usage.py](example_usage.py) - примеры кода
|
||||
|
||||
## Интеграция со складом
|
||||
|
||||
Текущая версия использует заглушку `StockManager`. Для интеграции с реальной системой складского учета:
|
||||
|
||||
1. Откройте `products/utils/stock_manager.py`
|
||||
2. Реализуйте методы:
|
||||
- `check_stock(product, quantity)` - проверка остатков
|
||||
- `get_available_quantity(product)` - получение доступного количества
|
||||
- `reserve_stock(product, quantity, order_id)` - резервирование
|
||||
- `release_stock(product, quantity, order_id)` - освобождение
|
||||
|
||||
## Основные возможности
|
||||
|
||||
- ✅ Создание групп взаимозаменяемых товаров
|
||||
- ✅ Один товар может быть в нескольких группах
|
||||
- ✅ Индивидуальные приоритеты для каждого букета
|
||||
- ✅ Проверка доступности с учетом замен
|
||||
- ✅ Расчет цены с учетом фактически доступных товаров
|
||||
- ✅ Валидация данных
|
||||
- ✅ Django Admin интерфейс
|
||||
- ✅ Документация и примеры
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### Премиум букет
|
||||
|
||||
```
|
||||
Позиция: Роза Freedom (группа вариантов) - 15 шт
|
||||
Приоритеты:
|
||||
0. Роза 70см (200 руб/шт) - первый выбор
|
||||
1. Роза 60см (150 руб/шт)
|
||||
2. Роза 50см (100 руб/шт)
|
||||
|
||||
Цена: 15 × 200 = 3000 руб
|
||||
```
|
||||
|
||||
### Эконом букет
|
||||
|
||||
```
|
||||
Позиция: Роза Freedom (группа вариантов) - 15 шт
|
||||
Приоритеты:
|
||||
0. Роза 50см (100 руб/шт) - первый выбор
|
||||
1. Роза 60см (150 руб/шт)
|
||||
2. Роза 70см (200 руб/шт)
|
||||
|
||||
Цена: 15 × 100 = 1500 руб
|
||||
```
|
||||
|
||||
Та же группа товаров, но разные приоритеты и разная цена!
|
||||
|
||||
## Структура файлов
|
||||
|
||||
```
|
||||
products/
|
||||
├── models.py # Модели (обновлено)
|
||||
├── admin.py # Админка (обновлено)
|
||||
├── utils/
|
||||
│ └── stock_manager.py # Менеджер остатков (новый)
|
||||
├── management/
|
||||
│ └── commands/
|
||||
│ └── demo_variants.py # Демонстрация (новая)
|
||||
└── migrations/
|
||||
└── 0004_productvariantgroup_... # Миграция (новая)
|
||||
|
||||
docs/
|
||||
├── README_VARIANTS.md # Это руководство
|
||||
├── product_variants_guide.md # Подробная документация
|
||||
└── example_usage.py # Примеры кода
|
||||
```
|
||||
|
||||
## Поддержка
|
||||
|
||||
Для получения помощи:
|
||||
1. Прочитайте [product_variants_guide.md](product_variants_guide.md)
|
||||
2. Изучите примеры в [example_usage.py](example_usage.py)
|
||||
3. Запустите `python manage.py demo_variants`
|
||||
4. Обратитесь к разработчикам
|
||||
|
||||
---
|
||||
|
||||
**Версия**: 1.0
|
||||
**Дата**: 2025-10-21
|
||||
259
myproject/docs/example_usage.py
Normal file
259
myproject/docs/example_usage.py
Normal file
@@ -0,0 +1,259 @@
|
||||
"""
|
||||
Примеры использования системы вариантов товаров.
|
||||
|
||||
Этот файл содержит примеры кода для демонстрации работы с системой.
|
||||
Запускать через Django shell: python manage.py shell < docs/example_usage.py
|
||||
"""
|
||||
|
||||
from decimal import Decimal
|
||||
from products.models import (
|
||||
Product, ProductKit, KitItem, ProductCategory,
|
||||
ProductVariantGroup, KitItemPriority
|
||||
)
|
||||
from products.utils.stock_manager import StockManager
|
||||
|
||||
|
||||
def example_1_create_variant_group():
|
||||
"""Пример 1: Создание группы вариантов"""
|
||||
print("\n" + "="*60)
|
||||
print("ПРИМЕР 1: Создание группы вариантов")
|
||||
print("="*60)
|
||||
|
||||
# Создаём категорию
|
||||
category, _ = ProductCategory.objects.get_or_create(
|
||||
name="Цветы",
|
||||
defaults={'slug': 'cvety'}
|
||||
)
|
||||
|
||||
# Создаём товары - розы разной длины
|
||||
rose_50, _ = Product.objects.get_or_create(
|
||||
name="Роза Freedom 50см красная",
|
||||
defaults={
|
||||
'cost_price': Decimal('80.00'),
|
||||
'sale_price': Decimal('100.00'),
|
||||
'category': category
|
||||
}
|
||||
)
|
||||
|
||||
rose_60, _ = Product.objects.get_or_create(
|
||||
name="Роза Freedom 60см красная",
|
||||
defaults={
|
||||
'cost_price': Decimal('120.00'),
|
||||
'sale_price': Decimal('150.00'),
|
||||
'category': category
|
||||
}
|
||||
)
|
||||
|
||||
rose_70, _ = Product.objects.get_or_create(
|
||||
name="Роза Freedom 70см красная",
|
||||
defaults={
|
||||
'cost_price': Decimal('160.00'),
|
||||
'sale_price': Decimal('200.00'),
|
||||
'category': category
|
||||
}
|
||||
)
|
||||
|
||||
# Создаём группу вариантов
|
||||
group, created = ProductVariantGroup.objects.get_or_create(
|
||||
name="Роза красная Freedom",
|
||||
defaults={
|
||||
'description': 'Красная роза Freedom различной длины (50-70см)'
|
||||
}
|
||||
)
|
||||
|
||||
# Добавляем товары в группу
|
||||
rose_50.variant_groups.add(group)
|
||||
rose_60.variant_groups.add(group)
|
||||
rose_70.variant_groups.add(group)
|
||||
|
||||
print(f"✓ Создана группа: {group.name}")
|
||||
print(f" Товаров в группе: {group.get_products_count()}")
|
||||
print(f" Товары:")
|
||||
for product in group.products.all():
|
||||
print(f" - {product.name} ({product.sale_price} руб.)")
|
||||
|
||||
return group, rose_50, rose_60, rose_70
|
||||
|
||||
|
||||
def example_2_create_premium_bouquet(group, rose_50, rose_60, rose_70):
|
||||
"""Пример 2: Создание премиум букета с приоритетами"""
|
||||
print("\n" + "="*60)
|
||||
print("ПРИМЕР 2: Создание премиум букета")
|
||||
print("="*60)
|
||||
|
||||
# Создаём букет
|
||||
kit, _ = ProductKit.objects.get_or_create(
|
||||
name="Ранчо Виталия Премиум",
|
||||
defaults={
|
||||
'slug': 'rancho-vitaliya-premium',
|
||||
'pricing_method': 'from_sale_prices'
|
||||
}
|
||||
)
|
||||
|
||||
# Создаём позицию с группой вариантов
|
||||
kit_item, _ = KitItem.objects.get_or_create(
|
||||
kit=kit,
|
||||
variant_group=group,
|
||||
defaults={
|
||||
'quantity': Decimal('15.000'),
|
||||
'notes': 'Использовать самые длинные розы'
|
||||
}
|
||||
)
|
||||
|
||||
# Настраиваем приоритеты (для премиум букета - сначала длинные)
|
||||
KitItemPriority.objects.get_or_create(
|
||||
kit_item=kit_item,
|
||||
product=rose_70,
|
||||
defaults={'priority': 0} # Наивысший приоритет
|
||||
)
|
||||
KitItemPriority.objects.get_or_create(
|
||||
kit_item=kit_item,
|
||||
product=rose_60,
|
||||
defaults={'priority': 1}
|
||||
)
|
||||
KitItemPriority.objects.get_or_create(
|
||||
kit_item=kit_item,
|
||||
product=rose_50,
|
||||
defaults={'priority': 2} # Самый низкий приоритет
|
||||
)
|
||||
|
||||
print(f"✓ Создан букет: {kit.name}")
|
||||
print(f" Позиций: {kit.get_total_components_count()}")
|
||||
print(f" С вариантами: {kit.get_components_with_variants_count()}")
|
||||
print(f"\n Приоритеты для позиции '{kit_item.get_display_name()}':")
|
||||
for priority in kit_item.priorities.all().order_by('priority'):
|
||||
print(f" {priority.priority}. {priority.product.name} - {priority.product.sale_price} руб.")
|
||||
|
||||
return kit
|
||||
|
||||
|
||||
def example_3_create_economy_bouquet(group, rose_50, rose_60, rose_70):
|
||||
"""Пример 3: Создание эконом букета"""
|
||||
print("\n" + "="*60)
|
||||
print("ПРИМЕР 3: Создание эконом букета")
|
||||
print("="*60)
|
||||
|
||||
# Создаём эконом букет
|
||||
kit, _ = ProductKit.objects.get_or_create(
|
||||
name="Ранчо Виталия Эконом",
|
||||
defaults={
|
||||
'slug': 'rancho-vitaliya-econom',
|
||||
'pricing_method': 'from_sale_prices'
|
||||
}
|
||||
)
|
||||
|
||||
# Та же группа вариантов, но другие приоритеты
|
||||
kit_item, _ = KitItem.objects.get_or_create(
|
||||
kit=kit,
|
||||
variant_group=group,
|
||||
defaults={
|
||||
'quantity': Decimal('15.000'),
|
||||
'notes': 'Эконом вариант'
|
||||
}
|
||||
)
|
||||
|
||||
# Для эконом букета - сначала короткие (дешевые)
|
||||
KitItemPriority.objects.get_or_create(
|
||||
kit_item=kit_item,
|
||||
product=rose_50,
|
||||
defaults={'priority': 0} # Наивысший приоритет
|
||||
)
|
||||
KitItemPriority.objects.get_or_create(
|
||||
kit_item=kit_item,
|
||||
product=rose_60,
|
||||
defaults={'priority': 1}
|
||||
)
|
||||
KitItemPriority.objects.get_or_create(
|
||||
kit_item=kit_item,
|
||||
product=rose_70,
|
||||
defaults={'priority': 2} # Самый низкий приоритет
|
||||
)
|
||||
|
||||
print(f"✓ Создан букет: {kit.name}")
|
||||
print(f"\n Приоритеты для позиции '{kit_item.get_display_name()}':")
|
||||
for priority in kit_item.priorities.all().order_by('priority'):
|
||||
print(f" {priority.priority}. {priority.product.name} - {priority.product.sale_price} руб.")
|
||||
|
||||
return kit
|
||||
|
||||
|
||||
def example_4_check_availability(premium_kit, economy_kit):
|
||||
"""Пример 4: Проверка доступности"""
|
||||
print("\n" + "="*60)
|
||||
print("ПРИМЕР 4: Проверка доступности букетов")
|
||||
print("="*60)
|
||||
|
||||
stock_manager = StockManager()
|
||||
|
||||
# Проверяем премиум букет
|
||||
print(f"\nПремиум букет: {premium_kit.name}")
|
||||
if premium_kit.check_availability(stock_manager):
|
||||
print(" ✓ Доступен для сборки")
|
||||
price = premium_kit.calculate_price_with_substitutions(stock_manager)
|
||||
print(f" Цена: {price} руб.")
|
||||
else:
|
||||
print(" ✗ Недоступен")
|
||||
|
||||
# Проверяем эконом букет
|
||||
print(f"\nЭконом букет: {economy_kit.name}")
|
||||
if economy_kit.check_availability(stock_manager):
|
||||
print(" ✓ Доступен для сборки")
|
||||
price = economy_kit.calculate_price_with_substitutions(stock_manager)
|
||||
print(f" Цена: {price} руб.")
|
||||
else:
|
||||
print(" ✗ Недоступен")
|
||||
|
||||
|
||||
def example_5_best_product():
|
||||
"""Пример 5: Получение лучшего доступного товара"""
|
||||
print("\n" + "="*60)
|
||||
print("ПРИМЕР 5: Выбор лучшего доступного товара")
|
||||
print("="*60)
|
||||
|
||||
# Получаем премиум букет
|
||||
kit = ProductKit.objects.filter(name="Ранчо Виталия Премиум").first()
|
||||
if not kit:
|
||||
print(" Букет не найден")
|
||||
return
|
||||
|
||||
stock_manager = StockManager()
|
||||
|
||||
for kit_item in kit.kit_items.all():
|
||||
print(f"\nПозиция: {kit_item.get_display_name()}")
|
||||
print(f"Количество: {kit_item.quantity}")
|
||||
|
||||
best_product = kit_item.get_best_available_product(stock_manager)
|
||||
if best_product:
|
||||
print(f"✓ Лучший доступный товар: {best_product.name}")
|
||||
print(f" Цена: {best_product.sale_price} руб.")
|
||||
print(f" Стоимость позиции: {best_product.sale_price * kit_item.quantity} руб.")
|
||||
else:
|
||||
print("✗ Нет доступных товаров")
|
||||
|
||||
|
||||
def main():
|
||||
"""Запуск всех примеров"""
|
||||
print("\n" + "="*60)
|
||||
print("ДЕМОНСТРАЦИЯ СИСТЕМЫ ВАРИАНТОВ ТОВАРОВ")
|
||||
print("="*60)
|
||||
|
||||
# Создаём данные
|
||||
group, rose_50, rose_60, rose_70 = example_1_create_variant_group()
|
||||
|
||||
# Создаём букеты
|
||||
premium_kit = example_2_create_premium_bouquet(group, rose_50, rose_60, rose_70)
|
||||
economy_kit = example_3_create_economy_bouquet(group, rose_50, rose_60, rose_70)
|
||||
|
||||
# Проверяем доступность
|
||||
example_4_check_availability(premium_kit, economy_kit)
|
||||
|
||||
# Получаем лучший товар
|
||||
example_5_best_product()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("ДЕМОНСТРАЦИЯ ЗАВЕРШЕНА")
|
||||
print("="*60 + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
310
myproject/docs/product_variants_guide.md
Normal file
310
myproject/docs/product_variants_guide.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# Руководство по работе с вариантами товаров
|
||||
|
||||
## Введение
|
||||
|
||||
Система вариантов товаров позволяет создавать букеты с гибкими заменами компонентов. Это полезно когда один товар может быть заменен на другой похожий товар (например, роза 50см на розу 70см), и приоритет замены индивидуален для каждого букета.
|
||||
|
||||
## Основные концепции
|
||||
|
||||
### 1. Группа вариантов (ProductVariantGroup)
|
||||
|
||||
**Группа вариантов** - это набор взаимозаменяемых товаров.
|
||||
|
||||
Пример:
|
||||
- Группа: "Роза красная Freedom"
|
||||
- Роза Freedom 50см
|
||||
- Роза Freedom 60см
|
||||
- Роза Freedom 70см
|
||||
|
||||
Один товар может входить в несколько групп вариантов.
|
||||
|
||||
### 2. Позиция в букете (KitItem)
|
||||
|
||||
Каждая позиция в букете может быть:
|
||||
- **Конкретным товаром** - без возможности замены
|
||||
- **Группой вариантов** - с приоритетами замен
|
||||
|
||||
### 3. Приоритеты (KitItemPriority)
|
||||
|
||||
Для каждой позиции с группой вариантов можно настроить индивидуальные приоритеты:
|
||||
- Меньшее число = выше приоритет
|
||||
- Приоритет 0 = наивысший приоритет
|
||||
- Приоритет 1 = второй по важности
|
||||
- И т.д.
|
||||
|
||||
## Как использовать
|
||||
|
||||
### Шаг 1: Создание группы вариантов
|
||||
|
||||
1. Откройте Django Admin
|
||||
2. Перейдите в раздел "Группы вариантов"
|
||||
3. Нажмите "Добавить группу вариантов"
|
||||
4. Заполните:
|
||||
- Название: например, "Роза красная Freedom"
|
||||
- Описание: опционально
|
||||
5. Сохраните
|
||||
|
||||
### Шаг 2: Добавление товаров в группу
|
||||
|
||||
1. Откройте нужный товар в разделе "Товары"
|
||||
2. В поле "Группы вариантов" выберите созданную группу
|
||||
3. Сохраните товар
|
||||
4. Повторите для всех товаров, которые должны быть в этой группе
|
||||
|
||||
Альтернативный способ:
|
||||
- Выберите несколько товаров через filter_horizontal в админке товара
|
||||
|
||||
### Шаг 3: Создание букета с вариантами
|
||||
|
||||
1. Создайте новый комплект (букет) или откройте существующий
|
||||
2. При добавлении позиции в букете:
|
||||
- **Вариант А**: Укажите конкретный товар (если замены не нужны)
|
||||
- **Вариант Б**: Укажите группу вариантов (если нужны замены)
|
||||
|
||||
⚠️ **Важно**: Нельзя указывать одновременно и товар, и группу вариантов!
|
||||
|
||||
3. Укажите количество
|
||||
4. При необходимости добавьте примечание
|
||||
5. Сохраните позицию
|
||||
|
||||
### Шаг 4: Настройка приоритетов
|
||||
|
||||
Если вы выбрали группу вариантов:
|
||||
|
||||
1. Откройте позицию букета (KitItem)
|
||||
2. В разделе "Приоритеты вариантов" добавьте товары из группы
|
||||
3. Для каждого товара укажите приоритет:
|
||||
```
|
||||
Роза Freedom 70см - приоритет 0 (первый выбор)
|
||||
Роза Freedom 60см - приоритет 1 (второй выбор)
|
||||
Роза Freedom 50см - приоритет 2 (третий выбор)
|
||||
```
|
||||
4. Сохраните
|
||||
|
||||
### Шаг 5: Проверка доступности
|
||||
|
||||
Система автоматически проверяет доступность букета:
|
||||
|
||||
```python
|
||||
# В коде или Django shell
|
||||
kit = ProductKit.objects.get(name="Ранчо Виталия")
|
||||
|
||||
# Проверить доступность
|
||||
if kit.check_availability():
|
||||
print("Букет можно собрать!")
|
||||
else:
|
||||
print("Букет недоступен")
|
||||
|
||||
# Рассчитать цену с учетом замен
|
||||
price = kit.calculate_price_with_substitutions()
|
||||
print(f"Цена: {price} руб.")
|
||||
```
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### Пример 1: Премиум букет с розами
|
||||
|
||||
**Задача**: Создать букет "Ранчо Виталия" где нужны длинные розы, но можно заменить на средние.
|
||||
|
||||
**Решение**:
|
||||
1. Создать группу "Роза красная Freedom"
|
||||
2. Добавить в неё розы 50см, 60см, 70см
|
||||
3. В букете создать позицию с группой вариантов
|
||||
4. Настроить приоритеты:
|
||||
- Роза 70см - приоритет 0
|
||||
- Роза 60см - приоритет 1
|
||||
- Роза 50см - приоритет 2
|
||||
|
||||
При проверке доступности система сначала проверит наличие 70см, потом 60см, и только потом 50см.
|
||||
|
||||
### Пример 2: Эконом букет
|
||||
|
||||
**Задача**: Создать эконом-букет где приоритет у коротких роз.
|
||||
|
||||
**Решение**:
|
||||
1. Использовать ту же группу "Роза красная Freedom"
|
||||
2. Создать новый букет с другими приоритетами:
|
||||
- Роза 50см - приоритет 0 (первый выбор)
|
||||
- Роза 60см - приоритет 1
|
||||
- Роза 70см - приоритет 2
|
||||
|
||||
Та же группа товаров, но другой порядок приоритетов!
|
||||
|
||||
### Пример 3: Букет без замен
|
||||
|
||||
**Задача**: Создать букет где конкретные товары без замен.
|
||||
|
||||
**Решение**:
|
||||
1. При создании позиции в букете указать конкретный товар
|
||||
2. Оставить поле "Группа вариантов" пустым
|
||||
3. Приоритеты настраивать не нужно
|
||||
|
||||
### Пример 4: Смешанный букет
|
||||
|
||||
**Задача**: В одном букете часть позиций с заменами, часть без.
|
||||
|
||||
**Решение**:
|
||||
```
|
||||
Позиция 1: Роза Freedom (группа вариантов) - 15 шт
|
||||
Позиция 2: Упаковка крафт (конкретный товар) - 1 шт
|
||||
Позиция 3: Лента атласная (конкретный товар) - 2 м
|
||||
Позиция 4: Эустома белая (группа вариантов) - 5 шт
|
||||
```
|
||||
|
||||
## Как работает система
|
||||
|
||||
### Проверка доступности товара
|
||||
|
||||
Когда вызывается `kit_item.get_best_available_product()`:
|
||||
|
||||
1. Система получает список доступных товаров
|
||||
2. Если настроены приоритеты - сортирует по ним
|
||||
3. Проходит по списку от высшего приоритета к низшему
|
||||
4. Для каждого товара проверяет наличие на складе
|
||||
5. Возвращает первый доступный товар
|
||||
|
||||
### Проверка доступности букета
|
||||
|
||||
Когда вызывается `kit.check_availability()`:
|
||||
|
||||
1. Система проходит по всем позициям букета
|
||||
2. Для каждой позиции ищет доступный товар
|
||||
3. Если хотя бы одна позиция недоступна - весь букет недоступен
|
||||
4. Если все позиции доступны - букет можно собрать
|
||||
|
||||
### Расчет цены
|
||||
|
||||
Система рассчитывает цену на основе фактически доступных товаров:
|
||||
|
||||
```python
|
||||
# Пример
|
||||
Позиция: Роза Freedom - 15 шт
|
||||
Приоритеты:
|
||||
- Роза 70см (200 руб) - нет в наличии
|
||||
- Роза 60см (150 руб) - нет в наличии
|
||||
- Роза 50см (100 руб) - есть в наличии ✓
|
||||
|
||||
Цена позиции: 15 × 100 = 1500 руб
|
||||
```
|
||||
|
||||
## Интеграция со складом
|
||||
|
||||
Текущая версия использует заглушку `StockManager`, которая всегда возвращает `True`.
|
||||
|
||||
В будущем `StockManager` будет интегрирован с реальной системой складского учета:
|
||||
|
||||
```python
|
||||
# Будущая реализация
|
||||
class StockManager:
|
||||
def check_stock(self, product, quantity):
|
||||
# Запрос к складской системе
|
||||
available = get_stock_from_warehouse(product.sku)
|
||||
return available >= quantity
|
||||
```
|
||||
|
||||
## API моделей
|
||||
|
||||
### ProductVariantGroup
|
||||
|
||||
**Методы:**
|
||||
- `get_products_count()` - количество товаров в группе
|
||||
|
||||
**Поля:**
|
||||
- `name` - название группы
|
||||
- `description` - описание
|
||||
- `products` - товары в группе (M2M)
|
||||
|
||||
### KitItem
|
||||
|
||||
**Методы:**
|
||||
- `get_display_name()` - название для отображения
|
||||
- `has_priorities_set()` - настроены ли приоритеты
|
||||
- `get_available_products()` - список доступных товаров
|
||||
- `get_best_available_product(stock_manager)` - лучший доступный товар
|
||||
- `clean()` - валидация
|
||||
|
||||
**Поля:**
|
||||
- `product` - конкретный товар (nullable)
|
||||
- `variant_group` - группа вариантов (nullable)
|
||||
- `quantity` - количество
|
||||
- `notes` - примечание
|
||||
|
||||
### ProductKit
|
||||
|
||||
**Методы:**
|
||||
- `get_total_components_count()` - количество позиций
|
||||
- `get_components_with_variants_count()` - позиций с вариантами
|
||||
- `check_availability(stock_manager)` - проверка доступности
|
||||
- `calculate_price_with_substitutions(stock_manager)` - расчет цены
|
||||
|
||||
### Product
|
||||
|
||||
**Методы:**
|
||||
- `get_variant_groups()` - все группы вариантов
|
||||
- `get_similar_products()` - похожие товары
|
||||
|
||||
**Поля:**
|
||||
- `variant_groups` - группы вариантов (M2M)
|
||||
|
||||
## Советы и лучшие практики
|
||||
|
||||
1. **Именование групп**: Используйте понятные названия, например "Роза красная Freedom" вместо "Группа 1"
|
||||
|
||||
2. **Приоритеты**: Начинайте с 0 и увеличивайте по 1 для простоты
|
||||
|
||||
3. **Проверка**: Всегда проверяйте доступность букета перед оформлением заказа
|
||||
|
||||
4. **Цены**: Учитывайте, что цена может меняться в зависимости от того, какой вариант доступен
|
||||
|
||||
5. **Несколько групп**: Один товар может быть в нескольких группах - это нормально
|
||||
|
||||
6. **Валидация**: Система не даст сохранить позицию, где указаны одновременно товар И группа
|
||||
|
||||
## Часто задаваемые вопросы
|
||||
|
||||
**Q: Можно ли товар добавить в несколько групп вариантов?**
|
||||
A: Да, один товар может быть в любом количестве групп.
|
||||
|
||||
**Q: Что если не настроить приоритеты?**
|
||||
A: Система вернет все товары из группы в произвольном порядке.
|
||||
|
||||
**Q: Можно ли изменить приоритеты после создания букета?**
|
||||
A: Да, приоритеты можно менять в любое время.
|
||||
|
||||
**Q: Как система выбирает товар, если несколько имеют одинаковый приоритет?**
|
||||
A: По ID (первый созданный).
|
||||
|
||||
**Q: Влияет ли порядок товаров в группе на выбор?**
|
||||
A: Нет, только приоритеты имеют значение. Если приоритеты не настроены - порядок не определен.
|
||||
|
||||
## Устранение неполадок
|
||||
|
||||
### Ошибка: "Нельзя указывать одновременно товар и группу вариантов"
|
||||
|
||||
**Причина**: Заполнены оба поля - `product` и `variant_group`
|
||||
|
||||
**Решение**: Очистите одно из полей. Оставьте либо товар, либо группу.
|
||||
|
||||
### Букет показывается как недоступный, хотя товары есть
|
||||
|
||||
**Причина**: Возможно, `StockManager` некорректно работает
|
||||
|
||||
**Решение**: Проверьте реализацию `StockManager.check_stock()`
|
||||
|
||||
### Приоритеты не работают
|
||||
|
||||
**Причина**: Приоритеты не были сохранены для позиции
|
||||
|
||||
**Решение**:
|
||||
1. Откройте позицию букета
|
||||
2. Убедитесь, что в разделе "Приоритеты вариантов" есть записи
|
||||
3. Проверьте значения приоритетов (меньше = выше)
|
||||
|
||||
## Дополнительная информация
|
||||
|
||||
Для получения помощи обратитесь к разработчикам или создайте issue в репозитории проекта.
|
||||
|
||||
---
|
||||
|
||||
**Дата создания**: 2025-10-21
|
||||
**Версия**: 1.0
|
||||
Reference in New Issue
Block a user