Исправлены 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>
280 lines
11 KiB
Python
280 lines
11 KiB
Python
#!/usr/bin/env python
|
||
"""
|
||
Скрипт для тестирования системы наличия товаров и цен вариантов.
|
||
Проверяет:
|
||
1. Обновление Product.in_stock при создании Stock
|
||
2. Свойство ProductVariantGroup.in_stock (вариант в наличии если хотя бы один товар в наличии)
|
||
3. Свойство ProductVariantGroup.price (берётся цена по приоритету)
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import django
|
||
|
||
# Добавляем путь к myproject
|
||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'myproject'))
|
||
os.chdir(os.path.join(os.path.dirname(__file__), 'myproject'))
|
||
|
||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
|
||
django.setup()
|
||
|
||
from decimal import Decimal
|
||
from products.models import Product, ProductVariantGroup, ProductVariantGroupItem
|
||
from inventory.models import Stock, StockBatch, Warehouse, Incoming, IncomingBatch
|
||
from django.utils import timezone
|
||
|
||
def clear_data():
|
||
"""Очищаем тестовые данные"""
|
||
Product.objects.all().delete()
|
||
ProductVariantGroup.objects.all().delete()
|
||
Stock.objects.all().delete()
|
||
StockBatch.objects.all().delete()
|
||
Warehouse.objects.all().delete()
|
||
IncomingBatch.objects.all().delete()
|
||
print("OK Данные очищены")
|
||
|
||
def create_test_data():
|
||
"""Создаём тестовые данные"""
|
||
|
||
# Создаём склад
|
||
warehouse = Warehouse.objects.create(
|
||
name="Основной склад",
|
||
description="Тестовый склад",
|
||
is_active=True,
|
||
is_default=True
|
||
)
|
||
print(f"OK Создан склад: {warehouse.name}")
|
||
|
||
# Создаём товары (розы разной длины)
|
||
products = []
|
||
prices = [Decimal('50.00'), Decimal('60.00'), Decimal('70.00')]
|
||
|
||
for i, price in enumerate(prices, 1):
|
||
product = Product.objects.create(
|
||
name=f"Роза красная Freedom {50 + i*10}см",
|
||
sku=f"ROSE-RED-{50 + i*10}",
|
||
cost_price=Decimal('30.00'),
|
||
sale_price=price,
|
||
unit='шт',
|
||
is_active=True,
|
||
in_stock=False # По умолчанию нет в наличии
|
||
)
|
||
products.append(product)
|
||
print(f"OK Создан товар: {product.name} (цена: {price}, in_stock={product.in_stock})")
|
||
|
||
# Создаём группу вариантов
|
||
variant_group = ProductVariantGroup.objects.create(
|
||
name="Роза красная Freedom",
|
||
description="Розы разной высоты"
|
||
)
|
||
print(f"OK Создана группа вариантов: {variant_group.name}")
|
||
|
||
# Добавляем товары в группу с приоритетами
|
||
items = []
|
||
for priority, product in enumerate(products, 1):
|
||
item = ProductVariantGroupItem.objects.create(
|
||
variant_group=variant_group,
|
||
product=product,
|
||
priority=priority
|
||
)
|
||
items.append(item)
|
||
print(f" - {product.name} (приоритет {priority})")
|
||
|
||
return warehouse, products, variant_group, items
|
||
|
||
def test_scenario_1():
|
||
"""
|
||
Тест 1: Создание товара в наличии и проверка автоматического обновления in_stock
|
||
"""
|
||
print("\n" + "="*80)
|
||
print("ТЕСТ 1: Обновление Product.in_stock при создании Stock")
|
||
print("="*80)
|
||
|
||
warehouse, products, variant_group, items = create_test_data()
|
||
|
||
# Получаем первый товар
|
||
product = products[0]
|
||
print(f"\nПроверяем товар: {product.name}")
|
||
print(f"Текущий статус in_stock: {product.in_stock}")
|
||
|
||
# Создаём приход товара (это должно создать Stock и обновить in_stock)
|
||
incoming_batch = IncomingBatch.objects.create(
|
||
warehouse=warehouse,
|
||
document_number="IN-0001",
|
||
supplier_name="Тестовый поставщик"
|
||
)
|
||
print(f"\nOK Создана партия поступления: {incoming_batch.document_number}")
|
||
|
||
# Добавляем товар в приход
|
||
incoming = Incoming.objects.create(
|
||
batch=incoming_batch,
|
||
product=product,
|
||
quantity=Decimal('100.00'),
|
||
cost_price=product.cost_price
|
||
)
|
||
print(f"OK Добавлен товар в приход: {incoming.quantity} шт")
|
||
|
||
# Проверяем что Stock был создан и in_stock обновлён
|
||
stock = Stock.objects.get(product=product, warehouse=warehouse)
|
||
print(f"\nOK Stock создан:")
|
||
print(f" - quantity_available: {stock.quantity_available}")
|
||
print(f" - quantity_reserved: {stock.quantity_reserved}")
|
||
print(f" - quantity_free: {stock.quantity_free}")
|
||
|
||
# Обновляем товар из БД чтобы получить новое значение
|
||
product.refresh_from_db()
|
||
print(f"\nOK Product.in_stock обновлён: {product.in_stock}")
|
||
|
||
if product.in_stock:
|
||
print("PASS: ТЕСТ 1 ПРОЙДЕН: Product.in_stock = True")
|
||
else:
|
||
print("FAIL: ТЕСТ 1 ПРОВАЛЕН: Product.in_stock должен быть True")
|
||
|
||
return warehouse, products, variant_group, items
|
||
|
||
def test_scenario_2(warehouse, products, variant_group, items):
|
||
"""
|
||
Тест 2: Проверка свойства ProductVariantGroup.in_stock
|
||
"""
|
||
print("\n" + "="*80)
|
||
print("ТЕСТ 2: Свойство ProductVariantGroup.in_stock")
|
||
print("="*80)
|
||
|
||
# Обновляем товары из БД
|
||
for product in products:
|
||
product.refresh_from_db()
|
||
|
||
print(f"\nГруппа вариантов: {variant_group.name}")
|
||
print(f"Товары в группе:")
|
||
for item in variant_group.items.all():
|
||
print(f" - {item.product.name} (приоритет {item.priority}, in_stock={item.product.in_stock})")
|
||
|
||
# Первый товар в наличии, поэтому вариант должен быть в наличии
|
||
print(f"\nСвойство variant_group.in_stock: {variant_group.in_stock}")
|
||
|
||
if variant_group.in_stock:
|
||
print("PASS: ТЕСТ 2 ПРОЙДЕН: Вариант в наличии (хотя бы один товар доступен)")
|
||
else:
|
||
print("FAIL: ТЕСТ 2 ПРОВАЛЕН: Вариант должен быть в наличии")
|
||
|
||
def test_scenario_3(warehouse, products, variant_group, items):
|
||
"""
|
||
Тест 3: Проверка свойства ProductVariantGroup.price
|
||
"""
|
||
print("\n" + "="*80)
|
||
print("ТЕСТ 3: Свойство ProductVariantGroup.price")
|
||
print("="*80)
|
||
|
||
print(f"\nГруппа вариантов: {variant_group.name}")
|
||
|
||
# Обновляем товары из БД
|
||
for product in products:
|
||
product.refresh_from_db()
|
||
|
||
print(f"Товары в приоритете:")
|
||
for item in variant_group.items.all().order_by('priority'):
|
||
status = "OK В наличии" if item.product.in_stock else "NO Нет в наличии"
|
||
print(f" {item.priority}. {item.product.name} - {item.product.sale_price} руб {status}")
|
||
|
||
# Цена должна быть из первого в наличии (приоритет 1, цена 50.00)
|
||
price = variant_group.price
|
||
expected_price = Decimal('50.00')
|
||
|
||
print(f"\nЦена варианта: {price} руб")
|
||
print(f"Ожидаемая цена: {expected_price} руб")
|
||
|
||
if price == expected_price:
|
||
print("PASS: ТЕСТ 3 ПРОЙДЕН: Берётся цена товара с приоритетом 1")
|
||
else:
|
||
print(f"FAIL: ТЕСТ 3 ПРОВАЛЕН: Цена должна быть {expected_price}, получена {price}")
|
||
|
||
def test_scenario_4():
|
||
"""
|
||
Тест 4: Проверка цены когда нет товара в наличии (должна быть максимальная)
|
||
"""
|
||
print("\n" + "="*80)
|
||
print("ТЕСТ 4: Цена варианта когда ни один товар не в наличии")
|
||
print("="*80)
|
||
|
||
# Очищаем данные
|
||
clear_data()
|
||
|
||
# Создаём новые данные без Stock (товары не в наличии)
|
||
warehouse = Warehouse.objects.create(
|
||
name="Тестовый склад",
|
||
is_active=True,
|
||
is_default=True
|
||
)
|
||
|
||
# Создаём товары с разными ценами
|
||
products = []
|
||
prices = [Decimal('100.00'), Decimal('150.00'), Decimal('200.00')]
|
||
|
||
for i, price in enumerate(prices, 1):
|
||
product = Product.objects.create(
|
||
name=f"Товар {i}",
|
||
sku=f"PRODUCT-{i}",
|
||
cost_price=Decimal('50.00'),
|
||
sale_price=price,
|
||
unit='шт',
|
||
is_active=True,
|
||
in_stock=False # Нет в наличии
|
||
)
|
||
products.append(product)
|
||
|
||
# Создаём группу вариантов
|
||
variant_group = ProductVariantGroup.objects.create(
|
||
name="Группа товаров без наличия"
|
||
)
|
||
|
||
# Добавляем товары в группу
|
||
for priority, product in enumerate(products, 1):
|
||
ProductVariantGroupItem.objects.create(
|
||
variant_group=variant_group,
|
||
product=product,
|
||
priority=priority
|
||
)
|
||
|
||
print(f"\nГруппа: {variant_group.name}")
|
||
print(f"Товары (все без наличия):")
|
||
for item in variant_group.items.all().order_by('priority'):
|
||
print(f" {item.priority}. {item.product.name} - {item.product.sale_price} руб (in_stock={item.product.in_stock})")
|
||
|
||
# Цена должна быть максимальная = 200.00
|
||
price = variant_group.price
|
||
expected_price = Decimal('200.00')
|
||
|
||
print(f"\nЦена варианта (максимальная): {price} руб")
|
||
print(f"Ожидаемая цена (максимальная): {expected_price} руб")
|
||
|
||
if price == expected_price:
|
||
print("PASS: ТЕСТ 4 ПРОЙДЕН: Берётся максимальная цена из товаров")
|
||
else:
|
||
print(f"FAIL: ТЕСТ 4 ПРОВАЛЕН: Цена должна быть {expected_price}, получена {price}")
|
||
|
||
if __name__ == '__main__':
|
||
print("\n" + "="*80)
|
||
print("= ТЕСТИРОВАНИЕ СИСТЕМЫ НАЛИЧИЯ ТОВАРОВ И ЦЕН ВАРИАНТОВ")
|
||
print("="*80)
|
||
|
||
try:
|
||
# Очищаем старые данные
|
||
clear_data()
|
||
|
||
# Тесты 1-3
|
||
warehouse, products, variant_group, items = test_scenario_1()
|
||
test_scenario_2(warehouse, products, variant_group, items)
|
||
test_scenario_3(warehouse, products, variant_group, items)
|
||
|
||
# Тест 4
|
||
test_scenario_4()
|
||
|
||
print("\n" + "="*80)
|
||
print("= ТЕСТИРОВАНИЕ ЗАВЕРШЕНО")
|
||
print("="*80 + "\n")
|
||
|
||
except Exception as e:
|
||
print(f"\nОШИБКА: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|