311 lines
14 KiB
Markdown
311 lines
14 KiB
Markdown
# Руководство по работе с вариантами товаров
|
||
|
||
## Введение
|
||
|
||
Система вариантов товаров позволяет создавать букеты с гибкими заменами компонентов. Это полезно когда один товар может быть заменен на другой похожий товар (например, роза 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
|