From eaa0b5bd3c147402a393efe9cc9f6eaa50adeee8 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Tue, 2 Dec 2025 15:13:51 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D1=87=D0=B8=D1=81=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=8F:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=B8=20=D1=81?= =?UTF-8?q?=D0=BB=D1=83=D0=B6=D0=B5=D0=B1=D0=BD=D1=8B=D0=B5=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Удалены из git: - Скрипты активации и диагностики тенантов - Тестовые файлы (test_*.py, test_*.txt) - SQL скрипты для отладки - Backup файлы (*.backup, *.old) - Дубликат .gitignore из myproject/ Файлы остались на диске, но теперь игнорируются git. В репозитории остались только: - myproject/ (основной код проекта) - requirements.txt - .gitignore 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- add_payment_methods_to_buba.py | 40 - assign_owner_role.py | 48 - check_order.py | 167 --- cleanup_media.py | 72 -- myproject/.gitignore | 79 -- myproject/activate_mixflowers.py | 97 -- myproject/activate_tenant.py | 176 --- myproject/check_order_101.py | 74 -- myproject/check_orders.py | 53 - myproject/check_stock.py | 34 - myproject/check_stock_103.py | 95 -- myproject/cleanup_duplicate_reservations.py | 192 ---- myproject/create_demo_orders.sql | 186 ---- myproject/create_wallet_payment_method.py | 18 - myproject/diagnose_reservation_issue.py | 171 --- myproject/fix_order_119.py | 60 -- myproject/fix_reservations.sql | 59 - myproject/inventory/views.py.old | 10 - myproject/myproject/urls.py.backup | 33 - myproject/myproject/views.py.backup | 12 - myproject/refresh_stock_reservations.py | 39 - myproject/run_demo_orders.py | 24 - myproject/switch_to_tenant.py | 70 -- myproject/test_card_interface.py | 145 --- myproject/test_configurable_json.py | 177 --- myproject/test_configurable_simple.py | 131 --- myproject/test_encoding.txt | 3 - myproject/test_kit_binding.py | 236 ---- myproject/test_order_status_default.py | 125 --- myproject/test_output.txt | 1066 ------------------- myproject/test_rollback_fix.py | 232 ---- myproject/test_smart_quantity_filter.py | 51 - myproject/test_template_syntax.py | 32 - myproject/test_wallet_system.py | 73 -- myproject/test_workflow.py | 172 --- run_status_tests.bat | 10 - test_simple.py | 2 - ГИД ПО ЗАПУСКУ | 44 - 38 files changed, 4308 deletions(-) delete mode 100644 add_payment_methods_to_buba.py delete mode 100644 assign_owner_role.py delete mode 100644 check_order.py delete mode 100644 cleanup_media.py delete mode 100644 myproject/.gitignore delete mode 100644 myproject/activate_mixflowers.py delete mode 100644 myproject/activate_tenant.py delete mode 100644 myproject/check_order_101.py delete mode 100644 myproject/check_orders.py delete mode 100644 myproject/check_stock.py delete mode 100644 myproject/check_stock_103.py delete mode 100644 myproject/cleanup_duplicate_reservations.py delete mode 100644 myproject/create_demo_orders.sql delete mode 100644 myproject/create_wallet_payment_method.py delete mode 100644 myproject/diagnose_reservation_issue.py delete mode 100644 myproject/fix_order_119.py delete mode 100644 myproject/fix_reservations.sql delete mode 100644 myproject/inventory/views.py.old delete mode 100644 myproject/myproject/urls.py.backup delete mode 100644 myproject/myproject/views.py.backup delete mode 100644 myproject/refresh_stock_reservations.py delete mode 100644 myproject/run_demo_orders.py delete mode 100644 myproject/switch_to_tenant.py delete mode 100644 myproject/test_card_interface.py delete mode 100644 myproject/test_configurable_json.py delete mode 100644 myproject/test_configurable_simple.py delete mode 100644 myproject/test_encoding.txt delete mode 100644 myproject/test_kit_binding.py delete mode 100644 myproject/test_order_status_default.py delete mode 100644 myproject/test_output.txt delete mode 100644 myproject/test_rollback_fix.py delete mode 100644 myproject/test_smart_quantity_filter.py delete mode 100644 myproject/test_template_syntax.py delete mode 100644 myproject/test_wallet_system.py delete mode 100644 myproject/test_workflow.py delete mode 100644 run_status_tests.bat delete mode 100644 test_simple.py delete mode 100644 ГИД ПО ЗАПУСКУ diff --git a/add_payment_methods_to_buba.py b/add_payment_methods_to_buba.py deleted file mode 100644 index a9cf52e..0000000 --- a/add_payment_methods_to_buba.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Скрипт для добавления способов оплаты в тенант buba -""" -import os -import sys -import django - -# Добавляем путь к проекту -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'myproject')) - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django_tenants.utils import schema_context -from django.core.management import call_command - -print("=" * 70) -print("Добавление способов оплаты в тенант 'buba'") -print("=" * 70) - -# Переключаемся на схему buba и создаём способы оплаты -with schema_context('buba'): - print("\n1. Создание способов оплаты...") - call_command('create_payment_methods') - - # Проверяем что создалось - from orders.models import PaymentMethod - methods = PaymentMethod.objects.all().order_by('order') - - print(f"\n2. Проверка созданных способов оплаты:") - print(f" Всего: {methods.count()}") - for method in methods: - status = "✓" if method.is_active else "✗" - print(f" {status} [{method.order}] {method.name} ({method.code})") - -print("\n" + "=" * 70) -print("✓ Готово!") -print("=" * 70) diff --git a/assign_owner_role.py b/assign_owner_role.py deleted file mode 100644 index 8144571..0000000 --- a/assign_owner_role.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import sys -import django - -# Добавляем путь к проекту -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'myproject')) - -# Настраиваем Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.contrib.auth import get_user_model -from django_tenants.utils import schema_context -from user_roles.services import RoleService - -User = get_user_model() - -# Схема тенанта -schema_name = 'buba' - -# Email пользователя -user_email = 'admin@localhost' - -print(f"Назначение роли Owner для пользователя {user_email} в тенанте {schema_name}...") - -# Переключаемся на схему тенанта -with schema_context(schema_name): - try: - # Находим пользователя - user = User.objects.get(email=user_email) - print(f"Пользователь найден: {user.email} (ID: {user.id})") - - # Назначаем роль Owner - user_role = RoleService.assign_role_to_user(user, 'owner') - print(f"✓ Роль '{user_role.role.name}' успешно назначена!") - print(f" - Email: {user_role.user.email}") - print(f" - Имя: {user_role.user.name}") - print(f" - Роль: {user_role.role.name} ({user_role.role.code})") - print(f" - Активен: {user_role.is_active}") - - except User.DoesNotExist: - print(f"✗ Ошибка: Пользователь с email '{user_email}' не найден") - except Exception as e: - print(f"✗ Ошибка при назначении роли: {e}") - import traceback - traceback.print_exc() - -print("\nГотово!") diff --git a/check_order.py b/check_order.py deleted file mode 100644 index 7222045..0000000 --- a/check_order.py +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env python -""" -Скрипт для проверки заказа и его складских операций -""" -import os -import sys -import django - -# Настройка Django -sys.path.insert(0, '/c/Users/team_/Desktop/test_qwen/myproject') -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection -from orders.models import Order -from inventory.models import Reservation, Sale, Stock, StockBatch, Warehouse - -# Устанавливаем схему тенанта -connection.set_schema('buba') - -# Получаем заказ -try: - order = Order.objects.get(order_number='101') - - print("=" * 60) - print(f"ЗАКАЗ: {order.order_number}") - print("=" * 60) - print(f"ID: {order.id}") - print(f"Статус: {order.status}") - print(f"Склад самовывоза: {order.pickup_warehouse}") - print(f"Создан: {order.created_at}") - print(f"Обновлен: {order.updated_at}") - - print("\n" + "=" * 60) - print("ТОВАРЫ В ЗАКАЗЕ (OrderItem)") - print("=" * 60) - items = order.items.all() - if items: - for item in items: - product = item.product or item.product_kit - print(f" ID: {item.id}") - print(f" Товар: {product.name if product else 'НЕТ ТОВАРА!'}") - print(f" Количество: {item.quantity}") - print(f" Цена: {item.price}") - print() - else: - print(" ⚠️ НЕТ ТОВАРОВ В ЗАКАЗЕ!") - - print("=" * 60) - print("РЕЗЕРВЫ (Reservation)") - print("=" * 60) - reservations = Reservation.objects.filter(order_item__order=order) - if reservations: - for res in reservations: - print(f" ID: {res.id}") - print(f" Товар: {res.product.name}") - print(f" Склад: {res.warehouse.name}") - print(f" Количество: {res.quantity}") - print(f" Статус: {res.status}") - print(f" Создан: {res.reserved_at}") - if res.converted_at: - print(f" Конвертирован: {res.converted_at}") - print() - else: - print(" ⚠️ НЕТ РЕЗЕРВОВ!") - - print("=" * 60) - print("ПРОДАЖИ (Sale)") - print("=" * 60) - sales = Sale.objects.filter(order=order) - if sales: - for sale in sales: - print(f" ID: {sale.id}") - print(f" Товар: {sale.product.name}") - print(f" Склад: {sale.warehouse.name}") - print(f" Количество: {sale.quantity}") - print(f" Цена продажи: {sale.sale_price}") - print(f" Обработано: {sale.processed}") - print(f" Дата: {sale.date}") - print() - else: - print(" ⚠️ НЕТ ПРОДАЖ (Sale не созданы!)") - - print("=" * 60) - print("СКЛАДЫ") - print("=" * 60) - warehouse = order.pickup_warehouse or Warehouse.objects.filter(is_active=True).first() - if warehouse: - print(f" Используется склад: {warehouse.name} (ID: {warehouse.id})") - print(f" Активен: {warehouse.is_active}") - else: - print(" ⚠️ НЕТ ДОСТУПНЫХ СКЛАДОВ!") - - print("\n" + "=" * 60) - print("ОСТАТКИ НА СКЛАДЕ (StockBatch)") - print("=" * 60) - if warehouse and items: - for item in items: - product = item.product or item.product_kit - if product: - print(f"\nТовар: {product.name}") - batches = StockBatch.objects.filter( - product=product, - warehouse=warehouse, - is_active=True - ) - if batches: - total = sum(b.quantity for b in batches) - print(f" Всего доступно: {total}") - for batch in batches: - print(f" Партия ID {batch.id}: {batch.quantity} шт (себестоимость: {batch.cost_price})") - else: - print(f" ⚠️ НЕТ ПАРТИЙ НА СКЛАДЕ!") - - # Проверяем Stock - try: - stock = Stock.objects.get(product=product, warehouse=warehouse) - print(f" Stock.quantity_available: {stock.quantity_available}") - print(f" Stock.quantity_reserved: {stock.quantity_reserved}") - print(f" Stock.quantity_free: {stock.quantity_free}") - except Stock.DoesNotExist: - print(f" ⚠️ Stock запись не существует!") - - print("\n" + "=" * 60) - print("ДИАГНОСТИКА") - print("=" * 60) - - # Проверка условий для срабатывания сигнала - if order.status != 'completed': - print(" ⚠️ СТАТУС НЕ 'completed'! Сигнал НЕ СРАБОТАЕТ") - print(f" Текущий статус: {order.status}") - else: - print(" ✅ Статус 'completed' - условие выполнено") - - if not warehouse: - print(" ⚠️ НЕТ СКЛАДА! Сигнал выйдет на строке 76-77") - else: - print(f" ✅ Склад есть: {warehouse.name}") - - if not items: - print(" ⚠️ НЕТ ТОВАРОВ! Сигнал ничего не сделает") - else: - print(f" ✅ Товаров в заказе: {items.count()}") - - # Проверка наличия товара на складе - if warehouse and items: - for item in items: - product = item.product or item.product_kit - if product: - batches = StockBatch.objects.filter( - product=product, - warehouse=warehouse, - is_active=True - ) - total = sum(b.quantity for b in batches) - if total < item.quantity: - print(f" ⚠️ НЕДОСТАТОЧНО ТОВАРА '{product.name}'!") - print(f" Нужно: {item.quantity}, доступно: {total}") - else: - print(f" ✅ Товара '{product.name}' достаточно: {total} >= {item.quantity}") - -except Order.DoesNotExist: - print(f"⚠️ ЗАКАЗ С НОМЕРОМ '101' НЕ НАЙДЕН В ТЕНАНТЕ 'buba'!") -except Exception as e: - print(f"❌ ОШИБКА: {e}") - import traceback - traceback.print_exc() diff --git a/cleanup_media.py b/cleanup_media.py deleted file mode 100644 index 3353f34..0000000 --- a/cleanup_media.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Script to cleanup old photo files with collision suffixes. -Deletes files like: original_b374WLW.jpg, large_lmCnBYn.webp etc. -""" -import os -import sys -from pathlib import Path - -# Determine media directory -media_dir = Path(__file__).parent / 'myproject' / 'media' - -if not media_dir.exists(): - print(f"ERROR: media directory not found: {media_dir}") - sys.exit(1) - -print(f"Cleaning old photo files in: {media_dir}") -print("=" * 60) - -deleted_count = 0 -errors = [] - -# Walk through all files in media -for root, dirs, files in os.walk(str(media_dir)): - for filename in files: - # Look for files with suffix (pattern: name_XXXXX.extension) - # where XXXXX is a random suffix added by Django on collision - parts = filename.rsplit('.', 1) # Split name and extension - - if len(parts) != 2: - continue - - name, ext = parts - - # Check if there's a suffix (8 chars after last underscore) - # Django adds suffixes like: _b374WLW, _lmCnBYn etc. - # Also match patterns like testovyi_17613999927705342_original - if '_' in name: - # Get the last part after underscore - parts_by_underscore = name.split('_') - last_part = parts_by_underscore[-1] - - # Check for collision suffix (8 alphanumeric chars) - # or timestamp-like suffix (14+ digits) - is_collision_suffix = (len(last_part) == 8 and last_part.isalnum()) - is_timestamp_suffix = (len(last_part) >= 14 and last_part.isdigit()) - - if is_collision_suffix or is_timestamp_suffix: - file_path = os.path.join(root, filename) - rel_path = os.path.relpath(file_path, str(media_dir)) - - try: - os.remove(file_path) - deleted_count += 1 - print(f"[OK] Deleted: {rel_path}") - except Exception as e: - errors.append(f"[FAIL] Error deleting {rel_path}: {str(e)}") - print(f"[FAIL] Error deleting {rel_path}: {str(e)}") - -print("=" * 60) -print(f"\nResults:") -print(f" [OK] Successfully deleted: {deleted_count} files") - -if errors: - print(f" [FAIL] Deletion errors: {len(errors)}") - for error in errors: - print(f" {error}") -else: - print(f" [OK] No errors") - -print("\n[DONE] Cleanup completed!") diff --git a/myproject/.gitignore b/myproject/.gitignore deleted file mode 100644 index 2e6bf1e..0000000 --- a/myproject/.gitignore +++ /dev/null @@ -1,79 +0,0 @@ -# Django -*.log -*.pot -*.pyc -__pycache__/ -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Environment variables (contains secrets!) -.env - -# Virtual environment -venv/ -env/ -ENV/ - -# IDE -.vscode/ -.idea/ -*.swp -*.swo -*~ - -# OS -.DS_Store -Thumbs.db - -# Static and media files -/staticfiles/ -/media/ - -# Python -*.py[cod] -*$py.class -*.so -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# Testing -.pytest_cache/ -.coverage -htmlcov/ - -# Migrations (раскомментируйте если не хотите коммитить миграции) -# */migrations/*.py -# !*/migrations/__init__.py - -# Celery Beat schedule database (автоматически создаётся при запуске celery beat) -celerybeat-schedule -celerybeat-schedule-shm -celerybeat-schedule-wal - -# Documentation files in root (сгенерированные документы) -/CELERY_SETUP_GUIDE.md -/FINAL_REPORT.md -/IMPLEMENTATION_SUMMARY.md -/MIGRATION_GUIDE.md -/QUICK_START.md -/README_CELERY.md -/start_celery.bat -/start_celery.sh diff --git a/myproject/activate_mixflowers.py b/myproject/activate_mixflowers.py deleted file mode 100644 index ed5d29a..0000000 --- a/myproject/activate_mixflowers.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Скрипт для активации заявки mixflowers -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import transaction -from django.utils import timezone -from tenants.models import TenantRegistration, Client, Domain, Subscription - -# Ищем заявку -registration = TenantRegistration.objects.get(schema_name='mixflowers') -print(f'Найдена заявка: {registration.shop_name} ({registration.schema_name})') -print(f'Статус: {registration.get_status_display()}') -print(f'Email: {registration.owner_email}') -print('') - -with transaction.atomic(): - # Создаем тенант - print(f'Создание тенанта: {registration.schema_name}') - client = Client.objects.create( - schema_name=registration.schema_name, - name=registration.shop_name, - owner_email=registration.owner_email, - owner_name=registration.owner_name, - phone=registration.phone, - is_active=True - ) - print(f'[OK] Тенант создан (ID: {client.id})') - - # Создаем домен - domain_name = f"{registration.schema_name}.localhost" - print(f'Создание домена: {domain_name}') - domain = Domain.objects.create( - domain=domain_name, - tenant=client, - is_primary=True - ) - print(f'[OK] Домен создан (ID: {domain.id})') - - # Создаем триальную подписку - print('Создание триальной подписки на 90 дней') - subscription = Subscription.create_trial(client) - print(f'[OK] Подписка создана (ID: {subscription.id})') - print(f' Истекает: {subscription.expires_at.strftime("%Y-%m-%d")} ({subscription.days_left()} дней)') - - # Создаем суперпользователя для тенанта - print('Создание суперпользователя для тенанта') - from django.db import connection - from django.contrib.auth import get_user_model - from django.conf import settings - - # Переключаемся на схему тенанта - connection.set_tenant(client) - - User = get_user_model() - if not User.objects.filter(email=settings.TENANT_ADMIN_EMAIL).exists(): - superuser = User.objects.create_superuser( - email=settings.TENANT_ADMIN_EMAIL, - name=settings.TENANT_ADMIN_NAME, - password=settings.TENANT_ADMIN_PASSWORD - ) - print(f'[OK] Суперпользователь создан (ID: {superuser.id})') - print(f' Email: {superuser.email}') - print(f' Password: {settings.TENANT_ADMIN_PASSWORD}') - else: - print(f'[SKIP] Пользователь с email {settings.TENANT_ADMIN_EMAIL} уже существует') - - # Возвращаемся в public схему - public_tenant = Client.objects.get(schema_name='public') - connection.set_tenant(public_tenant) - - # Обновляем заявку - registration.status = TenantRegistration.STATUS_APPROVED - registration.processed_at = timezone.now() - registration.processed_by = None - registration.tenant = client - registration.save() - print('[OK] Заявка обновлена') - -print('') -print('=' * 60) -print('АКТИВАЦИЯ ЗАВЕРШЕНА УСПЕШНО!') -print('=' * 60) -print(f'Магазин: {client.name}') -print(f'Schema: {client.schema_name}') -print(f'Домен: http://{domain_name}:8000/') -print(f'Подписка до: {subscription.expires_at.strftime("%Y-%m-%d")} ({subscription.days_left()} дней)') -print('') -print('Доступ к админке:') -print(f' URL: http://{domain_name}:8000/admin/') -print(f' Email: {settings.TENANT_ADMIN_EMAIL}') -print(f' Password: {settings.TENANT_ADMIN_PASSWORD}') diff --git a/myproject/activate_tenant.py b/myproject/activate_tenant.py deleted file mode 100644 index a302361..0000000 --- a/myproject/activate_tenant.py +++ /dev/null @@ -1,176 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Универсальный скрипт для активации заявки на создание тенанта. - -Использование: - python activate_tenant.py - -Примеры: - python activate_tenant.py grach - python activate_tenant.py myshop - -Скрипт выполняет: -1. Находит заявку по schema_name -2. Создает тенант (Client) -3. Создает домен ({schema_name}.localhost) -4. Создает триальную подписку (90 дней) -5. Создает суперпользователя (credentials из .env) -6. Обновляет статус заявки на "Одобрено" -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import transaction, connection -from django.utils import timezone -from django.contrib.auth import get_user_model -from django.conf import settings -from tenants.models import TenantRegistration, Client, Domain, Subscription - -def print_usage(): - """Вывод справки по использованию""" - print("Использование: python activate_tenant.py ") - print("") - print("Примеры:") - print(" python activate_tenant.py grach") - print(" python activate_tenant.py myshop") - print("") - print("Доступные заявки (со статусом 'pending'):") - pending_regs = TenantRegistration.objects.filter(status=TenantRegistration.STATUS_PENDING) - if pending_regs.exists(): - for reg in pending_regs: - print(f" - {reg.schema_name}: {reg.shop_name} ({reg.owner_email})") - else: - print(" Нет заявок, ожидающих активации") - -def activate_tenant(schema_name): - """Активация тенанта по schema_name""" - - # Ищем заявку - try: - registration = TenantRegistration.objects.get(schema_name=schema_name) - except TenantRegistration.DoesNotExist: - print(f"Ошибка: Заявка с schema_name '{schema_name}' не найдена") - print("") - print_usage() - return False - - print(f'Найдена заявка: {registration.shop_name} ({registration.schema_name})') - print(f'Статус: {registration.get_status_display()}') - print(f'Email: {registration.owner_email}') - print('') - - # Проверяем статус - if registration.status == TenantRegistration.STATUS_APPROVED: - print(f'Внимание: Эта заявка уже была активирована!') - if registration.tenant: - print(f'Тенант: {registration.tenant.name} (ID: {registration.tenant.id})') - print(f'Домен: http://{registration.schema_name}.localhost:8000/') - return False - - # Проверяем, не существует ли уже тенант - if Client.objects.filter(schema_name=schema_name).exists(): - print(f'Ошибка: Тенант с schema_name "{schema_name}" уже существует!') - return False - - print('Начинаю активацию...') - print('') - - try: - with transaction.atomic(): - # Создаем тенант - print(f'1. Создание тенанта: {registration.schema_name}') - client = Client.objects.create( - schema_name=registration.schema_name, - name=registration.shop_name, - owner_email=registration.owner_email, - owner_name=registration.owner_name, - phone=registration.phone, - is_active=True - ) - print(f' [OK] Тенант создан (ID: {client.id})') - - # Создаем домен - domain_name = f"{registration.schema_name}.localhost" - print(f'2. Создание домена: {domain_name}') - domain = Domain.objects.create( - domain=domain_name, - tenant=client, - is_primary=True - ) - print(f' [OK] Домен создан (ID: {domain.id})') - - # Создаем триальную подписку - print('3. Создание триальной подписки на 90 дней') - subscription = Subscription.create_trial(client) - print(f' [OK] Подписка создана (ID: {subscription.id})') - print(f' Истекает: {subscription.expires_at.strftime("%Y-%m-%d")} ({subscription.days_left()} дней)') - - # Создаем суперпользователя для тенанта - print('4. Создание суперпользователя для тенанта') - - # Переключаемся на схему тенанта - connection.set_tenant(client) - - User = get_user_model() - if not User.objects.filter(email=settings.TENANT_ADMIN_EMAIL).exists(): - superuser = User.objects.create_superuser( - email=settings.TENANT_ADMIN_EMAIL, - name=settings.TENANT_ADMIN_NAME, - password=settings.TENANT_ADMIN_PASSWORD - ) - print(f' [OK] Суперпользователь создан (ID: {superuser.id})') - else: - print(f' [SKIP] Пользователь с email {settings.TENANT_ADMIN_EMAIL} уже существует') - - # Возвращаемся в public схему - public_tenant = Client.objects.get(schema_name='public') - connection.set_tenant(public_tenant) - - # Обновляем заявку - print('5. Обновление статуса заявки') - registration.status = TenantRegistration.STATUS_APPROVED - registration.processed_at = timezone.now() - registration.processed_by = None # Активировано через скрипт - registration.tenant = client - registration.save() - print(' [OK] Заявка помечена как "Одобрено"') - - print('') - print('=' * 70) - print('АКТИВАЦИЯ ЗАВЕРШЕНА УСПЕШНО!') - print('=' * 70) - print(f'Магазин: {client.name}') - print(f'Schema: {client.schema_name}') - print(f'Домен: http://{domain_name}:8000/') - print(f'Подписка до: {subscription.expires_at.strftime("%Y-%m-%d")} ({subscription.days_left()} дней)') - print('') - print('Доступ к админке тенанта:') - print(f' URL: http://{domain_name}:8000/admin/') - print(f' Email: {settings.TENANT_ADMIN_EMAIL}') - print(f' Password: {settings.TENANT_ADMIN_PASSWORD}') - print('=' * 70) - - return True - - except Exception as e: - print('') - print(f'Ошибка при активации: {str(e)}') - import traceback - traceback.print_exc() - return False - - -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Ошибка: Не указан schema_name") - print("") - print_usage() - sys.exit(1) - - schema_name = sys.argv[1] - success = activate_tenant(schema_name) - sys.exit(0 if success else 1) diff --git a/myproject/check_order_101.py b/myproject/check_order_101.py deleted file mode 100644 index 0f90943..0000000 --- a/myproject/check_order_101.py +++ /dev/null @@ -1,74 +0,0 @@ -from django.db import connection -from orders.models import Order -from inventory.models import Reservation, Sale, Stock, StockBatch, Warehouse - -# Устанавливаем схему тенанта -connection.set_schema('buba') - -# Получаем заказ -try: - order = Order.objects.get(order_number='101') - - print("=" * 60) - print(f"ЗАКАЗ: {order.order_number}") - print("=" * 60) - print(f"ID: {order.id}") - print(f"Статус: '{order.status}'") - print(f"Склад самовывоза: {order.pickup_warehouse}") - - print("\n" + "=" * 60) - print("ТОВАРЫ В ЗАКАЗЕ") - print("=" * 60) - items = order.items.all() - print(f"Количество товаров: {items.count()}") - for item in items: - product = item.product or item.product_kit - print(f" - {product.name if product else 'НЕТ!'}: {item.quantity} шт, цена: {item.price}") - - print("\n" + "=" * 60) - print("РЕЗЕРВЫ") - print("=" * 60) - reservations = Reservation.objects.filter(order_item__order=order) - print(f"Количество резервов: {reservations.count()}") - for res in reservations: - print(f" - {res.product.name}: {res.quantity} шт, статус: '{res.status}'") - - print("\n" + "=" * 60) - print("ПРОДАЖИ (Sale)") - print("=" * 60) - sales = Sale.objects.filter(order=order) - print(f"Количество продаж: {sales.count()}") - if sales: - for sale in sales: - print(f" - {sale.product.name}: {sale.quantity} шт, обработано: {sale.processed}") - else: - print(" ⚠️ ПРОДАЖ НЕТ!") - - print("\n" + "=" * 60) - print("ДИАГНОСТИКА") - print("=" * 60) - - warehouse = order.pickup_warehouse or Warehouse.objects.filter(is_active=True).first() - - print(f"Статус заказа: '{order.status}' (тип: {type(order.status).__name__})") - print(f"Условие: order.status != 'completed' = {order.status != 'completed'}") - print(f"Склад: {warehouse.name if warehouse else 'НЕ НАЙДЕН!'}") - - # Проверяем наличие товара - if warehouse and items: - print("\nОстатки на складе:") - for item in items: - product = item.product or item.product_kit - if product: - batches = StockBatch.objects.filter(product=product, warehouse=warehouse, is_active=True) - total = sum(b.quantity for b in batches) - print(f" - {product.name}: {total} доступно (нужно {item.quantity})") - if total < item.quantity: - print(f" ⚠️ НЕДОСТАТОЧНО! (не хватает {item.quantity - total})") - -except Order.DoesNotExist: - print("⚠️ ЗАКАЗ 101 НЕ НАЙДЕН В ТЕНАНТЕ 'buba'!") -except Exception as e: - print(f"❌ ОШИБКА: {e}") - import traceback - traceback.print_exc() diff --git a/myproject/check_orders.py b/myproject/check_orders.py deleted file mode 100644 index ffc593e..0000000 --- a/myproject/check_orders.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Проверка созданных заказов и резервов -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection - -with connection.cursor() as cursor: - cursor.execute("SET search_path TO grach") - - # Считаем заказы - cursor.execute("SELECT COUNT(*) FROM grach.orders_order") - orders_count = cursor.fetchone()[0] - print(f"Заказов: {orders_count}") - - # Считаем позиции заказов - cursor.execute("SELECT COUNT(*) FROM grach.orders_orderitem") - items_count = cursor.fetchone()[0] - print(f"Позиций в заказах: {items_count}") - - # Считаем резервы - cursor.execute("SELECT COUNT(*) FROM grach.inventory_reservation") - reservations_count = cursor.fetchone()[0] - print(f"Резервов: {reservations_count}") - - # Детали по заказам без резервов - print("\nПервые 10 позиций без резервов:") - cursor.execute(""" - SELECT - o.order_number, - oi.id as item_id, - p.name as product_name, - oi.quantity, - COUNT(r.id) as reservations_count - FROM grach.orders_order o - JOIN grach.orders_orderitem oi ON oi.order_id = o.id - LEFT JOIN grach.products_product p ON p.id = oi.product_id - LEFT JOIN grach.inventory_reservation r ON r.order_item_id = oi.id - GROUP BY o.order_number, oi.id, p.name, oi.quantity - HAVING COUNT(r.id) = 0 - ORDER BY o.order_number - LIMIT 10 - """) - rows = cursor.fetchall() - if rows: - for row in rows: - print(f" Заказ {row[0]}: ItemID={row[1]}, Товар=\"{row[2]}\", Кол-во={row[3]}, Резервов={row[4]}") - else: - print(" Все позиции имеют резервы!") diff --git a/myproject/check_stock.py b/myproject/check_stock.py deleted file mode 100644 index 0797d5e..0000000 --- a/myproject/check_stock.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -Проверка Stock с quantity_reserved -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection - -with connection.cursor() as cursor: - cursor.execute("SET search_path TO grach") - - # Проверяем Stock с резервами - print("Stock с резервами:\n") - cursor.execute(""" - SELECT - s.id, - p.name as product_name, - s.quantity_available, - s.quantity_reserved, - (s.quantity_available - s.quantity_reserved) as free_quantity - FROM grach.inventory_stock s - JOIN grach.products_product p ON p.id = s.product_id - ORDER BY s.quantity_reserved DESC - """) - - print(f"{'ID':<5} {'Товар':<30} {'Всего':<10} {'Резерв':<10} {'Свободно':<10}") - print("=" * 75) - - for row in cursor.fetchall(): - stock_id, product_name, qty_available, qty_reserved, free_qty = row - print(f"{stock_id:<5} {product_name:<30} {qty_available:<10} {qty_reserved:<10} {free_qty:<10}") diff --git a/myproject/check_stock_103.py b/myproject/check_stock_103.py deleted file mode 100644 index c8da78a..0000000 --- a/myproject/check_stock_103.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -""" -Диагностика Stock для заказа 103 в схеме buba -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django_tenants.utils import schema_context -from orders.models import Order -from inventory.models import Reservation, Stock, Sale -from django.db.models import Sum - -# Работаем в схеме buba -with schema_context('buba'): - # Получаем заказ 103 - order = Order.objects.get(order_number=103) - - print("="*80) - print(f"ДИАГНОСТИКА ЗАКАЗА #{order.order_number} (схема: buba)") - print("="*80) - - # Проверяем резервы - print("\n📝 РЕЗЕРВЫ:") - reservations = Reservation.objects.filter(order_item__order=order) - for res in reservations: - print(f" - {res.product.name}:") - print(f" Количество: {res.quantity}") - print(f" Статус: {res.status}") - print(f" Склад: {res.warehouse.name}") - print(f" Product ID: {res.product_id}") - print(f" Warehouse ID: {res.warehouse_id}") - - # Проверяем Sale - print("\n💰 ПРОДАЖИ (Sale):") - sales = Sale.objects.filter(order=order) - for sale in sales: - print(f" - {sale.product.name}: {sale.quantity} шт.") - - # Проверяем Stock - print("\n📊 STOCK:") - for res in reservations: - stock = Stock.objects.get( - product_id=res.product_id, - warehouse_id=res.warehouse_id - ) - print(f" - {stock.product.name} на {stock.warehouse.name}:") - print(f" quantity_available: {stock.quantity_available}") - print(f" quantity_reserved: {stock.quantity_reserved}") - print(f" quantity_free: {stock.quantity_free}") - - # Проверяем: сколько РЕАЛЬНО резервов со статусом 'reserved' - print("\n🔍 ПЕРЕСЧЁТ РЕЗЕРВОВ ВРУЧНУЮ:") - for res in reservations.values('product_id', 'warehouse_id').distinct(): - product_id = res['product_id'] - warehouse_id = res['warehouse_id'] - - # Считаем резервы со статусом 'reserved' - reserved_count = Reservation.objects.filter( - product_id=product_id, - warehouse_id=warehouse_id, - status='reserved' - ).aggregate(Sum('quantity'))['quantity__sum'] or 0 - - # Считаем резервы со статусом 'converted_to_sale' - converted_count = Reservation.objects.filter( - product_id=product_id, - warehouse_id=warehouse_id, - status='converted_to_sale' - ).aggregate(Sum('quantity'))['quantity__sum'] or 0 - - print(f" Product ID {product_id}, Warehouse ID {warehouse_id}:") - print(f" Резервов 'reserved': {reserved_count}") - print(f" Резервов 'converted_to_sale': {converted_count}") - - # Что должно быть в Stock - stock = Stock.objects.get(product_id=product_id, warehouse_id=warehouse_id) - print(f" Stock.quantity_reserved: {stock.quantity_reserved}") - print(f" ❌ ПРОБЛЕМА!" if stock.quantity_reserved != reserved_count else " ✅ OK") - - print("\n" + "="*80) - print("ВЫВОД:") - print("="*80) - if stock.quantity_reserved > 0 and converted_count > 0: - print("❌ Stock НЕ обновился после конвертации резервов!") - print(" quantity_reserved показывает старое значение") - print("\n🔧 Попробуем обновить вручную...") - stock.refresh_from_batches() - print(f" После refresh_from_batches():") - print(f" quantity_reserved: {stock.quantity_reserved}") - print(f" ✅ ИСПРАВЛЕНО!" if stock.quantity_reserved == 0 else " ❌ НЕ ПОМОГЛО!") - else: - print("✅ Всё в порядке!") diff --git a/myproject/cleanup_duplicate_reservations.py b/myproject/cleanup_duplicate_reservations.py deleted file mode 100644 index 4e106a3..0000000 --- a/myproject/cleanup_duplicate_reservations.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Скрипт для очистки дубликатов резервов в базе данных (для tenant: buba). - -Проблема: У некоторых позиций заказов (OrderItem) существует несколько резервов -в статусе 'reserved', что вызывает ошибку MultipleObjectsReturned. - -Решение: Оставляем только первый резерв, остальные удаляем. -""" - -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import transaction, connection -from django.db.models import Count -from inventory.models import Reservation -from orders.models import OrderItem - - -# Устанавливаем tenant-схему -def set_tenant_schema(schema_name='buba'): - """Переключаемся на нужную tenant-схему""" - connection.set_schema(schema_name) - print(f"✓ Переключились на схему: {schema_name}") - - -def find_duplicate_reservations(): - """Находит OrderItem с несколькими резервами в статусе 'reserved'""" - - print("\n" + "="*80) - print("Поиск дубликатов резервов...") - print("="*80) - - # Группируем резервы по order_item и считаем количество - duplicates = Reservation.objects.filter( - status='reserved' - ).values('order_item').annotate( - count=Count('id') - ).filter(count__gt=1).order_by('-count') - - print(f"\nНайдено OrderItem с дубликатами: {duplicates.count()}") - - if duplicates.count() == 0: - print("✅ Дубликатов не обнаружено!") - return [] - - # Выводим детали - problem_items = [] - - for dup in duplicates: - order_item_id = dup['order_item'] - count = dup['count'] - - try: - order_item = OrderItem.objects.get(id=order_item_id) - - product_name = ( - order_item.product.sku if order_item.product - else order_item.product_kit.name if order_item.product_kit - else "Unknown" - ) - - print(f"\n OrderItem #{order_item_id}:") - print(f" Заказ: #{order_item.order.order_number}") - print(f" Товар: {product_name}") - print(f" Количество резервов: {count}") - - # Показываем все резервы - reservations = Reservation.objects.filter( - order_item=order_item, - status='reserved' - ).order_by('reserved_at') # Сортируем по дате создания - - for idx, res in enumerate(reservations, 1): - marker = "✓ ОСТАВИТЬ" if idx == 1 else "✗ УДАЛИТЬ" - print(f" {marker} - Резерв #{res.id}: qty={res.quantity}, создан {res.reserved_at}") - - problem_items.append({ - 'order_item': order_item, - 'count': count, - 'reservations': list(reservations) - }) - - except OrderItem.DoesNotExist: - print(f"\n ⚠ OrderItem #{order_item_id} не существует (удален)") - - return problem_items - - -def clean_duplicate_reservations(problem_items, dry_run=True): - """ - Очищает дубликаты резервов. - - Args: - problem_items: Список OrderItem с дубликатами - dry_run: Если True, только показывает что будет сделано, но не выполняет - """ - - print("\n" + "="*80) - if dry_run: - print("РЕЖИМ ПРОВЕРКИ (dry_run=True) - изменения НЕ будут сохранены") - else: - print("⚠ РЕЖИМ ОЧИСТКИ (dry_run=False) - изменения БУДУТ сохранены!") - print("="*80) - - if not problem_items: - print("\nНечего очищать!") - return - - total_deleted = 0 - - for item_data in problem_items: - order_item = item_data['order_item'] - reservations = item_data['reservations'] - - # Оставляем первый (самый старый) резерв - first_reservation = reservations[0] - duplicates = reservations[1:] - - print(f"\nOrderItem #{order_item.id} (Заказ #{order_item.order.order_number}):") - print(f" Оставляем: Резерв #{first_reservation.id}") - print(f" Удаляем: {len(duplicates)} дубликатов") - - if not dry_run: - with transaction.atomic(): - for dup in duplicates: - print(f" ✗ Удаляем Резерв #{dup.id}") - dup.delete() - total_deleted += 1 - else: - for dup in duplicates: - print(f" [DRY RUN] Будет удален Резерв #{dup.id}") - total_deleted += len(duplicates) - - print("\n" + "="*80) - if dry_run: - print(f"[DRY RUN] Будет удалено резервов: {total_deleted}") - else: - print(f"✅ УДАЛЕНО резервов: {total_deleted}") - print("="*80) - - -def main(): - """Главная функция""" - - print("\n" + "="*80) - print("ОЧИСТКА ДУБЛИКАТОВ РЕЗЕРВОВ") - print("="*80) - - # Переключаемся на tenant buba - set_tenant_schema('buba') - - # Шаг 1: Находим дубликаты - problem_items = find_duplicate_reservations() - - if not problem_items: - return - - # Шаг 2: Сначала делаем dry run - print("\n" + "="*80) - print("ШАГ 1: ПРОВЕРКА (без изменений)") - print("="*80) - clean_duplicate_reservations(problem_items, dry_run=True) - - # Шаг 3: Спрашиваем подтверждение - print("\n" + "="*80) - response = input("\n⚠ Выполнить очистку? (yes/no): ") - - if response.lower() in ['yes', 'y', 'да', 'д']: - print("\n" + "="*80) - print("ШАГ 2: ОЧИСТКА (с изменениями)") - print("="*80) - clean_duplicate_reservations(problem_items, dry_run=False) - - # Проверяем что дубликатов больше нет - print("\n" + "="*80) - print("ПРОВЕРКА ПОСЛЕ ОЧИСТКИ") - print("="*80) - remaining = find_duplicate_reservations() - - if not remaining: - print("\n✅ ВСЕ ДУБЛИКАТЫ УСПЕШНО УДАЛЕНЫ!") - else: - print(f"\n⚠ Еще остались дубликаты: {len(remaining)}") - else: - print("\n❌ Очистка отменена") - - -if __name__ == '__main__': - main() diff --git a/myproject/create_demo_orders.sql b/myproject/create_demo_orders.sql deleted file mode 100644 index fec1f2e..0000000 --- a/myproject/create_demo_orders.sql +++ /dev/null @@ -1,186 +0,0 @@ --- Создание демо-заказов для схемы grach -SET search_path TO grach; - --- Создаем 25 заказов с разными датами (от -15 до +15 дней от сегодня) -DO $$ -DECLARE - customer_ids INT[]; - product_ids INT[]; - address_ids INT[]; - shop_ids INT[]; - i INT; - random_customer_id INT; - random_product_id INT; - random_address_id INT; - random_shop_id INT; - is_delivery_flag BOOLEAN; - delivery_date_val DATE; - status_val VARCHAR(20); - payment_status_val VARCHAR(20); - payment_method_val VARCHAR(20); - order_id INT; - items_total DECIMAL(10,2); - delivery_cost_val DECIMAL(10,2); - total_amount_val DECIMAL(10,2); -BEGIN - -- Получаем существующие ID - SELECT ARRAY_AGG(id) INTO customer_ids FROM grach.customers_customer; - SELECT ARRAY_AGG(id) INTO product_ids FROM grach.products_product; - SELECT ARRAY_AGG(id) INTO address_ids FROM grach.customers_address; - SELECT ARRAY_AGG(id) INTO shop_ids FROM grach.shops_shop; - - -- Проверяем наличие данных - IF customer_ids IS NULL OR array_length(customer_ids, 1) = 0 THEN - RAISE EXCEPTION 'Нет клиентов в базе!'; - END IF; - - IF product_ids IS NULL OR array_length(product_ids, 1) = 0 THEN - RAISE EXCEPTION 'Нет товаров в базе!'; - END IF; - - -- Создаем 25 заказов - FOR i IN 1..25 LOOP - -- Случайные значения - random_customer_id := customer_ids[1 + floor(random() * array_length(customer_ids, 1))::int]; - is_delivery_flag := (random() > 0.5); - delivery_date_val := CURRENT_DATE + (floor(random() * 31) - 15)::int; - - -- Случайный статус - CASE floor(random() * 6)::int - WHEN 0 THEN status_val := 'new'; - WHEN 1 THEN status_val := 'confirmed'; - WHEN 2 THEN status_val := 'in_assembly'; - WHEN 3 THEN status_val := 'in_delivery'; - WHEN 4 THEN status_val := 'delivered'; - ELSE status_val := 'cancelled'; - END CASE; - - -- Случайный статус оплаты - CASE floor(random() * 3)::int - WHEN 0 THEN payment_status_val := 'unpaid'; - WHEN 1 THEN payment_status_val := 'partial'; - ELSE payment_status_val := 'paid'; - END CASE; - - -- Случайный способ оплаты - CASE floor(random() * 4)::int - WHEN 0 THEN payment_method_val := 'cash_to_courier'; - WHEN 1 THEN payment_method_val := 'card_to_courier'; - WHEN 2 THEN payment_method_val := 'online'; - ELSE payment_method_val := 'bank_transfer'; - END CASE; - - -- Стоимость доставки - IF is_delivery_flag THEN - delivery_cost_val := 200 + floor(random() * 300)::int; - ELSE - delivery_cost_val := 0; - END IF; - - -- Создаем заказ - INSERT INTO grach.orders_order ( - customer_id, - order_number, - is_delivery, - delivery_address_id, - pickup_shop_id, - delivery_date, - delivery_time_start, - delivery_time_end, - delivery_cost, - status, - payment_method, - is_paid, - total_amount, - discount_amount, - amount_paid, - payment_status, - customer_is_recipient, - recipient_name, - recipient_phone, - is_anonymous, - special_instructions, - created_at, - updated_at, - modified_by_id - ) VALUES ( - random_customer_id, - 'ORD-' || to_char(CURRENT_DATE, 'YYYYMMDD') || '-' || substring(md5(random()::text) from 1 for 4), - is_delivery_flag, - CASE WHEN is_delivery_flag AND address_ids IS NOT NULL THEN address_ids[1 + floor(random() * array_length(address_ids, 1))::int] ELSE NULL END, - CASE WHEN NOT is_delivery_flag AND shop_ids IS NOT NULL THEN shop_ids[1 + floor(random() * array_length(shop_ids, 1))::int] ELSE NULL END, - delivery_date_val, - CASE WHEN random() > 0.3 THEN ((9 + floor(random() * 10)::int)::text || ':00:00')::time ELSE NULL END, - CASE WHEN random() > 0.3 THEN ((11 + floor(random() * 8)::int)::text || ':00:00')::time ELSE NULL END, - delivery_cost_val, - status_val, - payment_method_val, - (payment_status_val = 'paid'), - 1000, -- Временное значение, пересчитаем позже - CASE WHEN random() > 0.8 THEN (100 + floor(random() * 400)::int) ELSE 0 END, - 0, -- Временное значение - payment_status_val, - (random() > 0.7), - CASE WHEN random() > 0.7 THEN 'Получатель ' || i ELSE NULL END, - CASE WHEN random() > 0.7 THEN '+79' || lpad(floor(random() * 1000000000)::text, 9, '0') ELSE NULL END, - (random() > 0.8), - CASE WHEN random() > 0.5 THEN - CASE floor(random() * 5)::int - WHEN 0 THEN 'Позвонить за час до доставки' - WHEN 1 THEN 'Доставить точно в указанное время' - WHEN 2 THEN 'Не звонить в дверь' - WHEN 3 THEN 'Упаковать покрасивее' - ELSE 'Приложить открытку' - END - ELSE NULL END, - CURRENT_TIMESTAMP, - CURRENT_TIMESTAMP, - NULL - ) RETURNING id INTO order_id; - - -- Добавляем 1-3 товара в заказ - items_total := 0; - FOR j IN 1..(1 + floor(random() * 3)::int) LOOP - random_product_id := product_ids[1 + floor(random() * array_length(product_ids, 1))::int]; - - -- Получаем цену товара и добавляем позицию - INSERT INTO grach.orders_orderitem ( - order_id, - product_id, - product_kit_id, - quantity, - price, - is_custom_price, - created_at - ) - SELECT - order_id, - random_product_id, - NULL, - 1 + floor(random() * 3)::int, - price, - FALSE, - CURRENT_TIMESTAMP - FROM grach.products_product - WHERE id = random_product_id - RETURNING (quantity * price) INTO STRICT total_amount_val; - - items_total := items_total + total_amount_val; - END LOOP; - - -- Обновляем итоговую сумму заказа - UPDATE grach.orders_order - SET - total_amount = items_total + delivery_cost - discount_amount, - amount_paid = CASE - WHEN payment_status = 'paid' THEN items_total + delivery_cost - discount_amount - WHEN payment_status = 'partial' THEN (items_total + delivery_cost - discount_amount) * (0.2 + random() * 0.6) - ELSE 0 - END - WHERE id = order_id; - - RAISE NOTICE 'Создан заказ % на дату %', order_id, delivery_date_val; - END LOOP; - - RAISE NOTICE 'Успешно создано 25 заказов!'; -END $$; diff --git a/myproject/create_wallet_payment_method.py b/myproject/create_wallet_payment_method.py deleted file mode 100644 index f11a1e7..0000000 --- a/myproject/create_wallet_payment_method.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Скрипт для создания способа оплаты 'account_balance' для тенанта buba -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.core.management import call_command -from django_tenants.utils import schema_context - -# Создаём способ оплаты для тенанта buba -with schema_context('buba'): - call_command('create_payment_methods') - print("\n✓ Способ оплаты успешно создан для тенанта 'buba'") diff --git a/myproject/diagnose_reservation_issue.py b/myproject/diagnose_reservation_issue.py deleted file mode 100644 index ba40dc5..0000000 --- a/myproject/diagnose_reservation_issue.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python -""" -Скрипт для диагностики проблемы с резервами при смене статуса на 'completed'. -Проверяет: -1. Изменяется ли статус резервов на 'converted_to_sale' -2. Создаются ли Sale -3. Списывается ли товар со склада -4. Освобождаются ли резервы -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection -from orders.models import Order, OrderStatus -from inventory.models import Reservation, Sale, Stock - - -def diagnose_order(order_number): - """Диагностика конкретного заказа""" - print(f"\n{'='*80}") - print(f"ДИАГНОСТИКА ЗАКАЗА #{order_number}") - print(f"{'='*80}\n") - - # Проверяем тенант - print(f"📌 Текущая схема БД: {connection.schema_name}") - - try: - order = Order.objects.get(order_number=order_number) - except Order.DoesNotExist: - print(f"❌ ОШИБКА: Заказ #{order_number} не найден!") - return - - print(f"✓ Заказ найден") - print(f" - Клиент: {order.customer.name}") - print(f" - Статус: {order.status.name if order.status else 'Нет статуса'} (code: {order.status.code if order.status else 'None'})") - print(f" - Дата создания: {order.created_at}") - print(f" - Дата обновления: {order.updated_at}") - - # Проверяем позиции заказа - print(f"\n📦 ПОЗИЦИИ ЗАКАЗА:") - items = order.items.all() - if not items.exists(): - print(" ⚠ Нет позиций в заказе") - else: - for item in items: - product = item.product or item.product_kit - print(f" - {product.name}: {item.quantity} шт. по {item.price} руб.") - - # Проверяем резервы - print(f"\n📝 РЕЗЕРВЫ:") - reservations = Reservation.objects.filter(order_item__order=order) - if not reservations.exists(): - print(" ⚠ НЕТ РЕЗЕРВОВ для этого заказа!") - else: - for res in reservations: - print(f" - {res.product.name}:") - print(f" • Количество: {res.quantity}") - print(f" • Статус: {res.get_status_display()} ({res.status})") - print(f" • Склад: {res.warehouse.name}") - print(f" • Зарезервировано: {res.reserved_at}") - if res.converted_at: - print(f" • Конвертировано: {res.converted_at}") - if res.released_at: - print(f" • Освобождено: {res.released_at}") - - # Проверяем Sale - print(f"\n💰 ПРОДАЖИ (Sale):") - sales = Sale.objects.filter(order=order) - if not sales.exists(): - print(" ⚠ НЕТ ПРОДАЖ для этого заказа!") - if order.status and order.status.code == 'completed': - print(" ❌ ПРОБЛЕМА: Заказ в статусе 'completed', но Sale не созданы!") - else: - for sale in sales: - print(f" - {sale.product.name}:") - print(f" • Количество: {sale.quantity}") - print(f" • Цена продажи: {sale.sale_price}") - print(f" • Склад: {sale.warehouse.name}") - print(f" • Дата: {sale.created_at}") - - # Проверяем распределение по партиям - from inventory.models import SaleBatchAllocation - allocations = SaleBatchAllocation.objects.filter(sale=sale) - if allocations.exists(): - print(f" • Распределение по партиям:") - for alloc in allocations: - print(f" - Партия #{alloc.batch.id}: {alloc.quantity} шт.") - - # Проверяем Stock - print(f"\n📊 ОСТАТКИ НА СКЛАДЕ (Stock):") - for item in items: - product = item.product or item.product_kit - warehouse = order.pickup_warehouse or order.items.first().order.pickup_warehouse - - if warehouse: - try: - stock = Stock.objects.get(product=product, warehouse=warehouse) - print(f" - {product.name} на складе {warehouse.name}:") - print(f" • Всего: {stock.quantity}") - print(f" • Зарезервировано: {stock.reserved_quantity}") - print(f" • Доступно: {stock.available_quantity}") - except Stock.DoesNotExist: - print(f" - {product.name}: ❌ Stock не найден") - else: - print(f" - {product.name}: ⚠ Склад не определён") - - # Проверяем историю изменений - print(f"\n📜 ИСТОРИЯ ИЗМЕНЕНИЙ СТАТУСА:") - history = order.history.all()[:5] # Последние 5 записей - for idx, record in enumerate(history, 1): - status_name = record.status.name if record.status else "Нет статуса" - print(f" {idx}. {status_name} - {record.history_date}") - - # Выводим выводы - print(f"\n{'='*80}") - print("ДИАГНОСТИКА:") - print(f"{'='*80}") - - issues = [] - - # Проверка 1: Резервы существуют? - if not reservations.exists(): - issues.append("❌ КРИТИЧНО: Нет резервов для заказа") - - # Проверка 2: Статус 'completed' + нет Sale - if order.status and order.status.code == 'completed': - if not sales.exists(): - issues.append("❌ КРИТИЧНО: Заказ 'completed', но Sale не созданы") - - # Проверка 3: Статус резервов - reserved_count = reservations.filter(status='reserved').count() - converted_count = reservations.filter(status='converted_to_sale').count() - - if reserved_count > 0: - issues.append(f"❌ ПРОБЛЕМА: {reserved_count} резервов ещё в статусе 'reserved' при completed заказе") - - if converted_count == 0 and reservations.exists(): - issues.append("❌ ПРОБЛЕМА: Ни один резерв не конвертирован в продажу") - - if issues: - print("\n🔴 НАЙДЕНЫ ПРОБЛЕМЫ:") - for issue in issues: - print(f" {issue}") - else: - print("\n✅ Проблем не обнаружено") - - print(f"\n{'='*80}\n") - - -def main(): - print("\n" + "="*80) - print("ДИАГНОСТИКА ПРОБЛЕМЫ С РЕЗЕРВАМИ") - print("="*80) - - # Спрашиваем номер заказа - order_number_input = input("\nВведите номер заказа для диагностики: ").strip() - - try: - order_number = int(order_number_input) - except ValueError: - print("❌ Ошибка: Введите корректный номер заказа (число)") - return - - diagnose_order(order_number) - - -if __name__ == "__main__": - main() diff --git a/myproject/fix_order_119.py b/myproject/fix_order_119.py deleted file mode 100644 index 37eff56..0000000 --- a/myproject/fix_order_119.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Скрипт для исправления дубликатов продаж в заказе 119 -""" -from django.db import connection, transaction -from orders.models import Order -from inventory.models import Sale, SaleBatchAllocation, Stock, StockBatch - -connection.set_schema('buba') - -order = Order.objects.get(order_number='119') -sales = Sale.objects.filter(order=order).order_by('date') - -print(f"Заказ {order.order_number}: найдено {sales.count()} продаж") - -if sales.count() <= 1: - print("Дубликатов нет, всё в порядке") -else: - # Оставляем первую продажу, остальные удаляем - first_sale = sales.first() - duplicate_sales = sales.exclude(id=first_sale.id) - - print(f"\nОставляем продажу ID {first_sale.id}") - print(f"Удаляем {duplicate_sales.count()} дубликатов:") - - with transaction.atomic(): - for sale in duplicate_sales: - print(f" - Продажа ID {sale.id}: {sale.product.name} x {sale.quantity}") - - # Получаем SaleBatchAllocation для восстановления товара - allocations = SaleBatchAllocation.objects.filter(sale=sale) - - # Восстанавливаем товар в партиях - for alloc in allocations: - batch = alloc.batch - print(f" Восстанавливаем партию ID {batch.id}: +{alloc.quantity}") - batch.quantity += alloc.quantity - batch.is_active = True - batch.save() - - # Удаляем продажу (каскадно удалятся и SaleBatchAllocation) - sale.delete() - - # Обновляем Stock - for item in order.items.all(): - product = item.product or item.product_kit - if product: - warehouse = order.pickup_warehouse or Warehouse.objects.filter(is_active=True).first() - if warehouse: - stock, _ = Stock.objects.get_or_create(product=product, warehouse=warehouse) - stock.refresh_from_batches() - print(f"\nStock обновлен для {product.name}:") - print(f" quantity_available: {stock.quantity_available}") - print(f" quantity_reserved: {stock.quantity_reserved}") - print(f" quantity_free: {stock.quantity_free}") - - print("\n✅ Дубликаты удалены, товар восстановлен на складе") - -# Проверяем результат -sales_after = Sale.objects.filter(order=order) -print(f"\nПосле исправления: {sales_after.count()} продаж") diff --git a/myproject/fix_reservations.sql b/myproject/fix_reservations.sql deleted file mode 100644 index ddd1daf..0000000 --- a/myproject/fix_reservations.sql +++ /dev/null @@ -1,59 +0,0 @@ --- Создание резервов для всех позиций заказов без резервов -SET search_path TO grach; - --- Проверяем наличие активного склада -DO $$ -DECLARE - warehouse_id_val INT; - created_count INT := 0; -BEGIN - -- Получаем ID активного склада (если есть) - SELECT id INTO warehouse_id_val - FROM grach.inventory_warehouse - WHERE is_active = true - LIMIT 1; - - IF warehouse_id_val IS NULL THEN - RAISE NOTICE 'WARNING: Нет активного склада, резервы будут созданы без склада'; - ELSE - RAISE NOTICE 'Используем склад ID: %', warehouse_id_val; - END IF; - - -- Создаем резервы для всех позиций без резервов - INSERT INTO grach.inventory_reservation ( - order_item_id, - product_id, - warehouse_id, - quantity, - status, - reserved_at, - released_at, - converted_at - ) - SELECT - oi.id, - COALESCE(oi.product_id, oi.product_kit_id), - warehouse_id_val, - oi.quantity, - 'reserved', - CURRENT_TIMESTAMP, - NULL, - NULL - FROM grach.orders_orderitem oi - LEFT JOIN grach.inventory_reservation r ON r.order_item_id = oi.id - WHERE r.id IS NULL -- Только позиции без резервов - AND (oi.product_id IS NOT NULL OR oi.product_kit_id IS NOT NULL) -- Есть товар - ON CONFLICT DO NOTHING; - - GET DIAGNOSTICS created_count = ROW_COUNT; - - RAISE NOTICE 'Создано резервов: %', created_count; -END $$; - --- Проверяем результат -SELECT - COUNT(*) as total_items, - COUNT(r.id) as items_with_reservations, - COUNT(*) - COUNT(r.id) as items_without_reservations -FROM grach.orders_orderitem oi -LEFT JOIN grach.inventory_reservation r ON r.order_item_id = oi.id; diff --git a/myproject/inventory/views.py.old b/myproject/inventory/views.py.old deleted file mode 100644 index 35d9c22..0000000 --- a/myproject/inventory/views.py.old +++ /dev/null @@ -1,10 +0,0 @@ -from django.shortcuts import render -from django.contrib.auth.decorators import login_required - - -@login_required -def inventory_home(request): - """ - Главная страница Склада для управления инвентаризацией - """ - return render(request, 'inventory/home.html') diff --git a/myproject/myproject/urls.py.backup b/myproject/myproject/urls.py.backup deleted file mode 100644 index de51aa8..0000000 --- a/myproject/myproject/urls.py.backup +++ /dev/null @@ -1,33 +0,0 @@ -""" -URL configuration for myproject project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/5.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" -from django.contrib import admin -from django.urls import path, include -from django.conf import settings -from django.conf.urls.static import static -from . import views - -urlpatterns = [ - path('_nested_admin/', include('nested_admin.urls')), # Для nested admin - path('admin/', admin.site.urls), - path('', views.index, name='index'), # Main page - path('accounts/', include('accounts.urls')), - path('products/', include('products.urls')), -] - -# Serve media files during development -if settings.DEBUG: - urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/myproject/myproject/views.py.backup b/myproject/myproject/views.py.backup deleted file mode 100644 index 2d042e6..0000000 --- a/myproject/myproject/views.py.backup +++ /dev/null @@ -1,12 +0,0 @@ -from django.shortcuts import render - - -def index(request): - # Главная страница - отображается для всех пользователей - # Если пользователь авторизован, можно показать персонализированное содержимое - if request.user.is_authenticated: - # Здесь можно отобразить персонализированное содержимое для авторизованных пользователей - return render(request, 'dashboard.html') # или другую страницу - else: - # Для неавторизованных пользователей показываем приветственную страницу - return render(request, 'home.html') \ No newline at end of file diff --git a/myproject/refresh_stock_reservations.py b/myproject/refresh_stock_reservations.py deleted file mode 100644 index b70d437..0000000 --- a/myproject/refresh_stock_reservations.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -Скрипт для пересчета quantity_reserved для всех Stock записей -Нужен после добавления сигналов для Reservation -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection -from inventory.models import Stock - -# Устанавливаем схему для работы с tenant -with connection.cursor() as cursor: - cursor.execute('SET search_path TO grach') - -print('[НАЧАЛО] Обновление quantity_reserved для всех Stock записей...') - -# Получаем все Stock записи -stocks = Stock.objects.all() -total_count = stocks.count() - -print(f'[INFO] Найдено Stock записей: {total_count}') - -updated_count = 0 -for stock in stocks: - try: - # Вызываем refresh_from_batches() который пересчитывает quantity_reserved - stock.refresh_from_batches() - updated_count += 1 - - if stock.quantity_reserved > 0: - print(f' [OK] Stock #{stock.id}: {stock.product.name} - зарезервировано: {stock.quantity_reserved}') - except Exception as e: - print(f' [ОШИБКА] Stock #{stock.id}: {str(e)}') - -print(f'\n[ЗАВЕРШЕНО] Обновлено записей: {updated_count} из {total_count}') -print('[OK] Все резервы пересчитаны!') diff --git a/myproject/run_demo_orders.py b/myproject/run_demo_orders.py deleted file mode 100644 index 8b08c32..0000000 --- a/myproject/run_demo_orders.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Скрипт для создания демо-заказов напрямую через SQL -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection - -# Читаем SQL скрипт -with open('create_demo_orders.sql', 'r', encoding='utf-8') as f: - sql = f.read() - -# Выполняем SQL -with connection.cursor() as cursor: - try: - cursor.execute(sql) - print("[OK] SQL script executed successfully!") - print("[OK] 25 demo orders created!") - except Exception as e: - print(f"[ERROR] {e}") - raise diff --git a/myproject/switch_to_tenant.py b/myproject/switch_to_tenant.py deleted file mode 100644 index 18f8143..0000000 --- a/myproject/switch_to_tenant.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Скрипт для переключения в пространство конкретного тенанта. - -Использование: - python switch_to_tenant.py grach -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.db import connection -from tenants.models import Client - -if len(sys.argv) < 2: - print("Использование: python switch_to_tenant.py ") - print("\nДоступные тенанты:") - for client in Client.objects.all(): - print(f" - {client.schema_name}: {client.name}") - sys.exit(1) - -schema_name = sys.argv[1] - -try: - # Находим тенанта - client = Client.objects.get(schema_name=schema_name) - print(f"Найден тенант: {client.name} ({client.schema_name})") - - # Переключаемся на схему тенанта - connection.set_tenant(client) - print(f"Переключено на схему: {connection.tenant.schema_name}") - print("") - - # Теперь можем работать с данными тенанта - print("=" * 60) - print("Теперь вы работаете в контексте тенанта!") - print("=" * 60) - print("") - - # Примеры работы с данными тенанта - from products.models import Product - from customers.models import Customer - from orders.models import Order - - products_count = Product.objects.count() - customers_count = Customer.objects.count() - orders_count = Order.objects.count() - - print(f"Товары: {products_count}") - print(f"Клиенты: {customers_count}") - print(f"Заказы: {orders_count}") - print("") - - # Интерактивный режим - print("Запуск интерактивной оболочки...") - print("Вы можете использовать: Product, Customer, Order и другие модели") - print("") - - import code - code.interact(local=locals()) - -except Client.DoesNotExist: - print(f"Ошибка: Тенант с schema_name '{schema_name}' не найден") - print("\nДоступные тенанты:") - for client in Client.objects.all(): - print(f" - {client.schema_name}: {client.name}") - sys.exit(1) diff --git a/myproject/test_card_interface.py b/myproject/test_card_interface.py deleted file mode 100644 index 3eb2d1e..0000000 --- a/myproject/test_card_interface.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python -""" -Test card-based interface for ConfigurableKitProduct attributes -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from products.models.kits import ( - ConfigurableKitProduct, - ConfigurableKitProductAttribute, - ProductKit -) -from django_tenants.utils import tenant_context -from tenants.models import Client -from django.db import transaction - -try: - client = Client.objects.get(schema_name='grach') - print(f"Found tenant: {client.name}\n") -except Client.DoesNotExist: - print("Tenant 'grach' not found") - sys.exit(1) - -with tenant_context(client): - print("=" * 70) - print("TEST: Card-Based Attribute Interface") - print("=" * 70) - - # Step 1: Create a test product - print("\n[1] Creating test product...") - try: - ConfigurableKitProduct.objects.filter(name__icontains="card-test").delete() - - product = ConfigurableKitProduct.objects.create( - name="Card Test Product", - sku="CARD-TEST-001", - description="Test card interface" - ) - print(f" OK: Created product: {product.name}") - except Exception as e: - print(f" ERROR: {e}") - sys.exit(1) - - # Step 2: Manually create attributes like the interface would - print("\n[2] Creating attributes (simulating card interface)...") - try: - # Parameter 1: Dlina (3 values) - attr_dlina_50 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Dlina", - option="50", - position=0, - visible=True - ) - attr_dlina_60 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Dlina", - option="60", - position=0, - visible=True - ) - attr_dlina_70 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Dlina", - option="70", - position=0, - visible=True - ) - print(f" OK: Created parameter 'Dlina' with 3 values: 50, 60, 70") - - # Parameter 2: Upakovka (2 values) - attr_pack_bez = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Upakovka", - option="BEZ", - position=1, - visible=True - ) - attr_pack_v = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Upakovka", - option="V_UPAKOVKE", - position=1, - visible=True - ) - print(f" OK: Created parameter 'Upakovka' with 2 values: BEZ, V_UPAKOVKE") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 3: Verify the structure - print("\n[3] Verifying attribute structure...") - try: - # Get unique parameter names - params = product.parent_attributes.values_list('name', flat=True).distinct() - print(f" OK: Found {params.count()} unique parameters:") - - for param_name in params: - values = product.parent_attributes.filter(name=param_name).values_list('option', flat=True) - print(f" - {param_name}: {list(values)}") - - # Verify counts - assert product.parent_attributes.count() == 5, "Should have 5 total attributes" - assert product.parent_attributes.filter(name="Dlina").count() == 3, "Should have 3 Dlina values" - assert product.parent_attributes.filter(name="Upakovka").count() == 2, "Should have 2 Upakovka values" - print(f" OK: All assertions passed!") - - except AssertionError as e: - print(f" ERROR: {e}") - sys.exit(1) - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 4: Test data retrieval - print("\n[4] Testing data retrieval...") - try: - # Get first parameter - param = product.parent_attributes.first() - print(f" OK: Retrieved attribute: {param.name} = {param.option}") - - # Test ordering - by_position = product.parent_attributes.values('name').distinct('name').order_by('position', 'name') - print(f" OK: Can order by position and name") - - except Exception as e: - print(f" ERROR: {e}") - sys.exit(1) - - print("\n" + "=" * 70) - print("OK: CARD INTERFACE TEST PASSED!") - print("=" * 70) - print("\nNotes:") - print("- The interface is designed to work with this attribute structure") - print("- Each parameter can have multiple values") - print("- Position is shared by all values of a parameter") - print("- This allows clean grouping in the card interface") diff --git a/myproject/test_configurable_json.py b/myproject/test_configurable_json.py deleted file mode 100644 index 48972f7..0000000 --- a/myproject/test_configurable_json.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env python -""" -Тестовый скрипт для проверки что JSONField работает корректно -в модели ConfigurableKitOption (с поддержкой тенанта). -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from products.models.kits import ConfigurableKitProduct, ConfigurableKitOption, ProductKit -from django_tenants.utils import tenant_context -from tenants.models import Client - -# Переходим в нужную схему (тенант) -try: - client = Client.objects.get(schema_name='grach') - print(f"✅ Найден тенант: {client.name} (schema: {client.schema_name})\n") -except Client.DoesNotExist: - print("❌ Тенант 'grach' не найден") - print("📝 Доступные тенанты:") - for c in Client.objects.all(): - print(f" - {c.name} ({c.schema_name})") - exit(1) - -# Весь тест в контексте тенанта -with tenant_context(client): - print("=" * 70) - print("ТЕСТ: JSONField в ConfigurableKitOption") - print("=" * 70) - - # Проверка 1: Создание вариативного товара - print("\n1️⃣ Проверка создания ConfigurableKitProduct...") - try: - configurable = ConfigurableKitProduct.objects.filter(name__icontains="тест").first() - if configurable: - print(f" ✅ Найден существующий товар: {configurable.name}") - else: - configurable = ConfigurableKitProduct.objects.create( - name="Тестовый букет JSON", - sku="TEST-BUCKET-JSON", - description="Тестовый товар для проверки JSON атрибутов" - ) - print(f" ✅ Создан новый товар: {configurable.name}") - except Exception as e: - print(f" ❌ Ошибка: {e}") - exit(1) - - # Проверка 2: Создание вариантов с JSON атрибутами - print("\n2️⃣ Проверка создания ConfigurableKitOption с JSON атрибутами...") - try: - # Получаем первый комплект или создаём тестовый - kit = ProductKit.objects.filter(name__icontains="тест").first() - if not kit: - kit = ProductKit.objects.first() - if not kit: - print(" ⚠️ В базе нет ProductKit, пропускаем этот тест") - kit = None - - if kit: - print(f" ℹ️ Используем существующий комплект: {kit.name}") - - # Проверяем есть ли уже вариант для этого комплекта - option = ConfigurableKitOption.objects.filter( - parent=configurable, - kit=kit - ).first() - - if option: - print(f" ℹ️ Вариант уже существует, обновляю атрибуты...") - # Обновляем существующий - option.attributes = {"length": "60", "color": "red"} - option.save() - print(f" ✅ Обновлены атрибуты: {option.attributes}") - else: - # Создаём новый вариант с JSON атрибутами - option = ConfigurableKitOption.objects.create( - parent=configurable, - kit=kit, - attributes={"length": "60", "color": "red"}, - is_default=True - ) - print(f" ✅ Создан вариант с JSON атрибутами:") - print(f" - Parent: {option.parent.name}") - print(f" - Kit: {option.kit.name}") - print(f" - Attributes (JSON): {option.attributes}") - print(f" - Type: {type(option.attributes)}") - except Exception as e: - print(f" ❌ Ошибка: {e}") - import traceback - traceback.print_exc() - exit(1) - - # Проверка 3: Получение и работа с JSON атрибутами - print("\n3️⃣ Проверка получения JSON атрибутов из БД...") - try: - options = ConfigurableKitOption.objects.filter(parent=configurable) - print(f" ℹ️ Найдено {options.count()} вариант(ов)") - - for idx, opt in enumerate(options, 1): - print(f"\n Вариант {idx}:") - print(f" - ID: {opt.id}") - print(f" - SKU комплекта: {opt.kit.sku}") - print(f" - Атрибуты (JSON): {opt.attributes}") - print(f" - Тип данных: {type(opt.attributes)}") - - # Проверяем доступ к ключам JSON - if opt.attributes: - if isinstance(opt.attributes, dict): - print(f" - Доступ к ключам JSON:") - for key, value in opt.attributes.items(): - print(f" • {key}: {value}") - print(f" ✅ JSON работает корректно!") - else: - print(f" ❌ Атрибуты не являются dict!") - except Exception as e: - print(f" ❌ Ошибка: {e}") - import traceback - traceback.print_exc() - exit(1) - - # Проверка 4: Фильтрация по JSON атрибутам (PostgreSQL) - print("\n4️⃣ Проверка фильтрации по JSON атрибутам...") - try: - # Попытка использовать JSON фильтрацию (работает в PostgreSQL) - # Для SQLite это может не работать - filtered = ConfigurableKitOption.objects.filter( - parent=configurable, - attributes__length="60" - ) - print(f" ℹ️ Попытка фильтрации по attributes__length='60'") - print(f" ℹ️ Найдено результатов: {filtered.count()}") - - if filtered.count() > 0: - print(f" ✅ JSON фильтрация работает!") - else: - print(f" ℹ️ JSON фильтрация может не поддерживаться в текущей БД") - except Exception as e: - print(f" ℹ️ JSON фильтрация не поддерживается: {type(e).__name__}") - - # Проверка 5: Сложные JSON структуры - print("\n5️⃣ Проверка сохранения сложных JSON структур...") - try: - complex_attrs = { - "length": "70", - "color": "white", - "quantity": 15, - "stems": ["rose1", "rose2", "rose3"], - "metadata": { - "fresh": True, - "days_available": 7 - } - } - - # Обновляем атрибуты сложной структурой - if options.exists(): - opt = options.first() - opt.attributes = complex_attrs - opt.save() - - # Проверяем что сохранилось правильно - opt_reloaded = ConfigurableKitOption.objects.get(pk=opt.pk) - print(f" ✅ Сохранены сложные JSON атрибуты:") - print(f" {opt_reloaded.attributes}") - - # Проверяем вложенность - if opt_reloaded.attributes.get("metadata", {}).get("fresh"): - print(f" ✅ Доступ к вложенным полям JSON работает!") - except Exception as e: - print(f" ❌ Ошибка: {e}") - import traceback - traceback.print_exc() - - print("\n" + "=" * 70) - print("✅ ВСЕ ТЕСТЫ ПРОЙДЕНЫ! JSONField работает корректно!") - print("=" * 70) diff --git a/myproject/test_configurable_simple.py b/myproject/test_configurable_simple.py deleted file mode 100644 index bbcd177..0000000 --- a/myproject/test_configurable_simple.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -""" -Prostoy test skript dlya proverki ConfigurableKitOptionAttribute -bez Unicode simvolov -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from products.models.kits import ( - ConfigurableKitProduct, - ConfigurableKitOption, - ConfigurableKitProductAttribute, - ConfigurableKitOptionAttribute, - ProductKit -) -from django_tenants.utils import tenant_context -from tenants.models import Client - -try: - client = Client.objects.get(schema_name='grach') - print(f"OK: Found tenant: {client.name} (schema: {client.schema_name})\n") -except Client.DoesNotExist: - print("ERROR: Tenant 'grach' not found") - print("Available tenants:") - for c in Client.objects.all(): - print(f" - {c.name} ({c.schema_name})") - sys.exit(1) - -with tenant_context(client): - print("=" * 70) - print("TEST: ConfigurableKitOptionAttribute M2M Model") - print("=" * 70) - - # Test 1: Check models exist - print("\n1. Checking if models exist...") - try: - # Try to get a ConfigurableKitProduct - products = ConfigurableKitProduct.objects.filter(name__icontains="test").first() - if products: - print(f" OK: Found ConfigurableKitProduct: {products.name}") - else: - print(" INFO: No test ConfigurableKitProduct found") - - # Check ConfigurableKitProductAttribute exists - attrs = ConfigurableKitProductAttribute.objects.all() - print(f" OK: ConfigurableKitProductAttribute model exists. Count: {attrs.count()}") - - # Check ConfigurableKitOptionAttribute exists - opt_attrs = ConfigurableKitOptionAttribute.objects.all() - print(f" OK: ConfigurableKitOptionAttribute model exists. Count: {opt_attrs.count()}") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Test 2: Check M2M relationships - print("\n2. Checking M2M relationships...") - try: - # Get a sample variant - option = ConfigurableKitOption.objects.first() - if option: - print(f" OK: Found option: {option.id} for parent: {option.parent.name}") - - # Check if we can access attributes_set - attr_set = option.attributes_set.all() - print(f" OK: Can access attributes_set. Count: {attr_set.count()}") - - # Check if we can reverse access - if attr_set.exists(): - opt_attr = attr_set.first() - print(f" OK: Can access option_attr.option: {opt_attr.option.id}") - print(f" OK: Can access option_attr.attribute: {opt_attr.attribute.id}") - else: - print(" INFO: No ConfigurableKitOption found") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Test 3: Check form validation logic - print("\n3. Checking form validation setup...") - try: - from products.forms import ConfigurableKitOptionForm - - # Create a test form with instance - option = ConfigurableKitOption.objects.filter( - parent__parent_attributes__isnull=False - ).first() - - if option: - form = ConfigurableKitOptionForm(instance=option) - print(f" OK: Form created for option with parent: {option.parent.name}") - - # Check dynamically generated fields - dynamic_fields = [f for f in form.fields if f.startswith('attribute_')] - print(f" OK: Found {len(dynamic_fields)} dynamic attribute fields:") - for field_name in dynamic_fields: - print(f" - {field_name}") - else: - print(" INFO: No option with parent attributes found") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Test 4: Check view integration - print("\n4. Checking view imports...") - try: - from products.views.configurablekit_views import ( - ConfigurableKitProductCreateView, - ConfigurableKitProductUpdateView - ) - print(" OK: Views imported successfully") - print(" OK: ConfigurableKitProductCreateView available") - print(" OK: ConfigurableKitProductUpdateView available") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - print("\n" + "=" * 70) - print("OK: ALL TESTS PASSED! Implementation is ready for testing.") - print("=" * 70) diff --git a/myproject/test_encoding.txt b/myproject/test_encoding.txt deleted file mode 100644 index 6a31e19..0000000 --- a/myproject/test_encoding.txt +++ /dev/null @@ -1,3 +0,0 @@ -Тестовый файл с кириллическими символами для проверки кодировки в PowerShell. - -This is a test file with Cyrillic characters to verify encoding. \ No newline at end of file diff --git a/myproject/test_kit_binding.py b/myproject/test_kit_binding.py deleted file mode 100644 index c0f6e17..0000000 --- a/myproject/test_kit_binding.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/env python -""" -Test kit binding for ConfigurableKitProduct attributes -Verifies that each attribute value can be bound to a specific ProductKit -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from products.models.kits import ( - ConfigurableKitProduct, - ConfigurableKitProductAttribute, - ProductKit -) -from django_tenants.utils import tenant_context -from tenants.models import Client -from django.db import transaction - -try: - client = Client.objects.get(schema_name='grach') - print(f"Found tenant: {client.name}\n") -except Client.DoesNotExist: - print("Tenant 'grach' not found") - sys.exit(1) - -with tenant_context(client): - print("=" * 80) - print("TEST: Kit Binding for ConfigurableKitProduct Attributes") - print("=" * 80) - - # Step 1: Create or get ProductKits - print("\n[1] Setting up ProductKits...") - try: - # Clean up old test kits - ProductKit.objects.filter(name__icontains="test-kit").delete() - - kits = [] - for i, name in enumerate(['Test Kit A', 'Test Kit B', 'Test Kit C']): - kit, created = ProductKit.objects.get_or_create( - name=name, - defaults={ - 'sku': f'TEST-KIT-{i}', - 'status': 'active', - 'is_temporary': False - } - ) - kits.append(kit) - status = "Created" if created else "Found" - print(f" {status}: {kit.name} (ID: {kit.id})") - except Exception as e: - print(f" ERROR: {e}") - sys.exit(1) - - # Step 2: Create a test product - print("\n[2] Creating test ConfigurableKitProduct...") - try: - ConfigurableKitProduct.objects.filter(name__icontains="kit-binding-test").delete() - - product = ConfigurableKitProduct.objects.create( - name="Kit Binding Test Product", - sku="KIT-BINDING-TEST-001", - description="Test product with kit-bound attributes" - ) - print(f" OK: Created product: {product.name} (ID: {product.id})") - except Exception as e: - print(f" ERROR: {e}") - sys.exit(1) - - # Step 3: Create attributes with kit bindings - print("\n[3] Creating attributes with kit bindings...") - try: - # Параметр "Длина" с 3 значениями, каждое привязано к своему комплекту - attrs = [] - - attr1 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Длина", - option="50", - position=0, - visible=True, - kit=kits[0] # Kit A - ) - attrs.append(attr1) - print(" OK: Created Dlina=50 -> " + kits[0].name) - - attr2 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Длина", - option="60", - position=0, - visible=True, - kit=kits[1] # Kit B - ) - attrs.append(attr2) - print(" OK: Created Dlina=60 -> " + kits[1].name) - - attr3 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Длина", - option="70", - position=0, - visible=True, - kit=kits[2] # Kit C - ) - attrs.append(attr3) - print(" OK: Created Dlina=70 -> " + kits[2].name) - - # Parametr "Upakovka" s 2 znacheniyami (odin bez komplekta) - attr4 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Упаковка", - option="БЕЗ", - position=1, - visible=True, - kit=kits[0] # Kit A - ) - attrs.append(attr4) - print(" OK: Created Upakovka=BEZ -> " + kits[0].name) - - attr5 = ConfigurableKitProductAttribute.objects.create( - parent=product, - name="Упаковка", - option="В УПАКОВКЕ", - position=1, - visible=True - # Kit is NULL for this one - ) - attrs.append(attr5) - print(" OK: Created Upakovka=V_UPAKOVKE -> (no kit)") - - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 4: Verify the structure - print("\n[4] Verifying attribute structure...") - try: - # Get unique parameter names - params = product.parent_attributes.values_list('name', flat=True).distinct().order_by('name') - print(f" OK: Found {len(list(params))} unique parameters") - - for param_name in product.parent_attributes.values_list('name', flat=True).distinct().order_by('name'): - param_attrs = product.parent_attributes.filter(name=param_name) - print("\n Parameter: " + param_name) - for attr in param_attrs: - kit_name = attr.kit.name if attr.kit else "(no kit)" - print(" - " + param_name + "=" + attr.option + " -> " + kit_name) - - # Verify relationships - print("\n Verifying relationships...") - assert product.parent_attributes.count() == 5, f"Should have 5 total attributes, got {product.parent_attributes.count()}" - print(" [OK] Total attributes: " + str(product.parent_attributes.count())) - - assert product.parent_attributes.filter(name="Длина").count() == 3, "Should have 3 Dlina values" - print(" [OK] Dlina values: " + str(product.parent_attributes.filter(name='Длина').count())) - - assert product.parent_attributes.filter(name="Упаковка").count() == 2, "Should have 2 Upakovka values" - print(" [OK] Upakovka values: " + str(product.parent_attributes.filter(name='Упаковка').count())) - - # Check kit bindings - kit_bound = product.parent_attributes.filter(kit__isnull=False).count() - assert kit_bound == 4, f"Should have 4 kit-bound attributes, got {kit_bound}" - print(" [OK] Kit-bound attributes: " + str(kit_bound)) - - kit_unbound = product.parent_attributes.filter(kit__isnull=True).count() - assert kit_unbound == 1, f"Should have 1 unbound attribute, got {kit_unbound}" - print(" [OK] Unbound attributes: " + str(kit_unbound)) - - except AssertionError as e: - print(f" ERROR: {e}") - sys.exit(1) - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 5: Test querying by kit - print("\n[5] Testing queries by kit binding...") - try: - for kit in kits: - attrs_for_kit = ConfigurableKitProductAttribute.objects.filter(kit=kit) - print(" Attributes for " + kit.name + ":") - for attr in attrs_for_kit: - print(" - " + attr.name + "=" + attr.option) - - # Reverse query: get kit for a specific attribute value - attr_value = "60" - attr = product.parent_attributes.get(option=attr_value) - if attr.kit: - print("\n Attribute value '" + attr_value + "' is bound to: " + attr.kit.name) - else: - print("\n Attribute value '" + attr_value + "' has no kit binding") - - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 6: Test FK relationship integrity - print("\n[6] Testing FK relationship integrity...") - try: - # Verify that kit field is properly populated - kit_a = kits[0] - attrs_with_kit_a = ConfigurableKitProductAttribute.objects.filter(kit=kit_a) - print(" Attributes linked to " + kit_a.name + ": " + str(attrs_with_kit_a.count())) - - # Verify NULL kit is allowed - null_kit_attrs = ConfigurableKitProductAttribute.objects.filter(kit__isnull=True) - print(" Attributes with NULL kit: " + str(null_kit_attrs.count())) - - assert null_kit_attrs.count() > 0, "Should have at least one NULL kit attribute" - print(" [OK] FK relationship integrity verified") - - except Exception as e: - print(" ERROR: " + str(e)) - import traceback - traceback.print_exc() - sys.exit(1) - - print("\n" + "=" * 80) - print("OK: KIT BINDING TEST PASSED!") - print("=" * 80) - print("\nSummary:") - print("[OK] ProductKit creation and retrieval") - print("[OK] Attribute creation with kit FK") - print("[OK] Mixed kit-bound and unbound attributes") - print("[OK] Querying attributes by kit") - print("[OK] FK cascade deletion on kit delete") - print("[OK] Reverse queries (get kit for attribute value)") diff --git a/myproject/test_order_status_default.py b/myproject/test_order_status_default.py deleted file mode 100644 index e5ca361..0000000 --- a/myproject/test_order_status_default.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Тест для проверки настройки статусов при создании и редактировании заказа. -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from orders.models import OrderStatus, Order -from orders.forms import OrderForm - - -def test_default_status(): - """Проверяет настройки статусов для новых и существующих заказов""" - - print("\n=== ТЕСТ: Настройки статусов заказов ===\n") - - # Проверяем наличие статуса "Черновик" - try: - draft_status = OrderStatus.objects.get(code='draft', is_system=True) - print(f"✓ Статус 'Черновик' найден: {draft_status.name} (ID: {draft_status.pk})") - except OrderStatus.DoesNotExist: - print("✗ ОШИБКА: Статус 'draft' не найден в БД!") - print(" Создайте системные статусы командой:") - print(" python manage.py shell -c \"from orders.services.order_status_service import OrderStatusService; OrderStatusService.create_default_statuses()\"") - return False - - # Проверяем финальные статусы - final_positive = OrderStatus.objects.filter(is_positive_end=True) - final_negative = OrderStatus.objects.filter(is_negative_end=True) - intermediate = OrderStatus.objects.filter(is_positive_end=False, is_negative_end=False) - - print(f"\n📊 Статистика статусов:") - print(f" - Промежуточные (доступны при создании): {intermediate.count()}") - print(f" - Положительные финальные: {final_positive.count()}") - print(f" - Отрицательные финальные: {final_negative.count()}") - - print(f"\n📋 Промежуточные статусы:") - for status in intermediate.order_by('order'): - print(f" - {status.name} ({status.code})") - - print(f"\n🚫 Финальные статусы (недоступны при создании):") - for status in final_positive: - print(f" - {status.name} ({status.code}) [положительный]") - for status in final_negative: - print(f" - {status.name} ({status.code}) [отрицательный]") - - # === ТЕСТ 1: Создание нового заказа === - print("\n=== ТЕСТ 1: Создание нового заказа ===\n") - - form_new = OrderForm() - status_field = form_new.fields['status'] - - # Проверяем начальное значение - initial_value = status_field.initial - print(f"✓ Начальное значение поля 'status': {initial_value}") - print(f"✓ Ожидаемое значение (ID статуса 'Черновик'): {draft_status.pk}") - - if initial_value == draft_status.pk: - print("✓ УСПЕХ: Статус 'Черновик' установлен по умолчанию!") - else: - print(f"✗ ОШИБКА: Начальное значение {initial_value} != {draft_status.pk}") - return False - - # Проверяем queryset (только промежуточные статусы) - available_statuses = list(status_field.queryset) - print(f"\n✓ Доступно статусов при создании: {len(available_statuses)}") - - has_final_positive = any(s.is_positive_end for s in available_statuses) - has_final_negative = any(s.is_negative_end for s in available_statuses) - - if not has_final_positive and not has_final_negative: - print("✓ УСПЕХ: Финальные статусы исключены из выбора!") - else: - print("✗ ОШИБКА: В списке есть финальные статусы!") - return False - - # Проверяем, что поле обязательно - if status_field.required: - print("✓ Поле 'status' обязательно (required=True)") - else: - print("✗ ОШИБКА: Поле 'status' не обязательно!") - return False - - # Проверяем, что пустой выбор убран - if status_field.empty_label is None: - print("✓ Пустой выбор '-------' убран (empty_label=None)") - else: - print(f"✗ ОШИБКА: Пустой выбор не убран! empty_label={status_field.empty_label}") - return False - - # === ТЕСТ 2: Редактирование существующего заказа === - print("\n=== ТЕСТ 2: Редактирование существующего заказа ===\n") - - # Создаем мок-объект заказа с pk (чтобы форма считала его существующим) - class MockOrder: - pk = 999 - status = draft_status - customer = None - delivery_address = None - - form_edit = OrderForm(instance=MockOrder()) - status_field_edit = form_edit.fields['status'] - - # Проверяем queryset (все статусы) - all_statuses = list(status_field_edit.queryset) - print(f"✓ Доступно статусов при редактировании: {len(all_statuses)}") - - has_final_in_edit = any(s.is_positive_end or s.is_negative_end for s in all_statuses) - - if has_final_in_edit: - print("✓ УСПЕХ: При редактировании доступны ВСЕ статусы (включая финальные)!") - else: - print("⚠ ВНИМАНИЕ: При редактировании финальные статусы отсутствуют") - - print("\n=== ВСЕ ТЕСТЫ ПРОЙДЕНЫ! ===\n") - return True - - -if __name__ == '__main__': - success = test_default_status() - exit(0 if success else 1) diff --git a/myproject/test_output.txt b/myproject/test_output.txt deleted file mode 100644 index 513f2cb..0000000 --- a/myproject/test_output.txt +++ /dev/null @@ -1,1066 +0,0 @@ -Creating test database for alias 'default' ('test_inventory_db')... - -Found 5 test(s). -=== Starting migration -Operations to perform: - Synchronize unmigrated apps: django_filters, django_tenants, messages, nested_admin, simple_history, staticfiles - Apply all migrations: accounts, admin, auth, contenttypes, customers, django_celery_results, inventory, orders, products, sessions, tenants -Synchronizing apps without migrations: - Creating tables... - Running deferred SQL... -Running migrations: - Applying contenttypes.0001_initial... - OK - Applying contenttypes.0002_remove_content_type_name... - OK - Applying auth.0001_initial... - OK - Applying auth.0002_alter_permission_name_max_length... - OK - Applying auth.0003_alter_user_email_max_length... - OK - Applying auth.0004_alter_user_username_opts... - OK - Applying auth.0005_alter_user_last_login_null... - OK - Applying auth.0006_require_contenttypes_0002... - OK - Applying auth.0007_alter_validators_add_error_messages... - OK - Applying auth.0008_alter_user_username_max_length... - OK - Applying auth.0009_alter_user_last_name_max_length... - OK - Applying auth.0010_alter_group_name_max_length... - OK - Applying auth.0011_update_proxy_permissions... - OK - Applying auth.0012_alter_user_first_name_max_length... - OK - Applying accounts.0001_initial... - OK - Applying admin.0001_initial... - OK - Applying admin.0002_logentry_remove_auto_add... - OK - Applying admin.0003_logentry_add_action_flag_choices... - OK - Applying inventory.0001_initial... - OK - Applying customers.0001_initial... - OK - Applying orders.0001_initial... - OK - Applying products.0001_initial... - OK - Applying inventory.0002_initial... - OK - Applying orders.0002_initial... - OK - Applying inventory.0003_showcase_reservation_showcase_and_more... - OK - Applying orders.0003_historicalorderitem_is_from_showcase_and_more... - OK - Applying orders.0004_refactor_models_and_add_payment_method... - OK - Applying customers.0002_customer_is_system_customer... - OK - Applying customers.0003_remove_customer_customers_c_loyalty_5162a0_idx_and_more... - OK - Applying customers.0004_customer_wallet_balance_wallettransaction... - OK - Applying django_celery_results.0001_initial... - OK - Applying django_celery_results.0002_add_task_name_args_kwargs... - OK - Applying django_celery_results.0003_auto_20181106_1101... - OK - Applying django_celery_results.0004_auto_20190516_0412... - OK - Applying django_celery_results.0005_taskresult_worker... - OK - Applying django_celery_results.0006_taskresult_date_created... - OK - Applying django_celery_results.0007_remove_taskresult_hidden... - OK - Applying django_celery_results.0008_chordcounter... - OK - Applying django_celery_results.0009_groupresult... - OK - Applying django_celery_results.0010_remove_duplicate_indices... - OK - Applying django_celery_results.0011_taskresult_periodic_task_name... - OK - Applying products.0002_configurablekitproduct_configurablekitoption... - OK - Applying products.0003_alter_configurablekitproduct_options_and_more... - OK - Applying products.0004_configurablekitproductattribute... - OK - Applying products.0005_alter_configurablekitoption_attributes... - OK - Applying products.0006_add_configurablekitoptionattribute... - OK - Applying products.0007_add_kit_to_attribute... - OK - Applying inventory.0004_showcase_is_default_and_more... - OK - Applying products.0008_productkit_showcase_and_more... - OK - Applying inventory.0005_reservation_product_kit_and_more... - OK - Applying inventory.0006_reservation_cart_lock_expires_at_and_more... - OK - Applying orders.0005_remove_historicalorder_discount_amount_and_more... - OK - Applying orders.0006_transaction_delete_payment_and_more... - OK - Applying products.0009_alter_productcategoryphoto_image_and_more... - OK - Applying products.0010_alter_product_cost_price... - OK - Applying sessions.0001_initial... - OK - Applying tenants.0001_initial... - OK -System check identified no issues (0 silenced). -=== Starting migration -Operations to perform: - Apply all migrations: accounts, admin, auth, contenttypes, customers, django_celery_results, inventory, orders, products, sessions, tenants -Running migrations: - Applying contenttypes.0001_initial... - OK - Applying contenttypes.0002_remove_content_type_name... - OK - Applying auth.0001_initial... - OK - Applying auth.0002_alter_permission_name_max_length... - OK - Applying auth.0003_alter_user_email_max_length... - OK - Applying auth.0004_alter_user_username_opts... - OK - Applying auth.0005_alter_user_last_login_null... - OK - Applying auth.0006_require_contenttypes_0002... - OK - Applying auth.0007_alter_validators_add_error_messages... - OK - Applying auth.0008_alter_user_username_max_length... - OK - Applying auth.0009_alter_user_last_name_max_length... - OK - Applying auth.0010_alter_group_name_max_length... - OK - Applying auth.0011_update_proxy_permissions... - OK - Applying auth.0012_alter_user_first_name_max_length... - OK - Applying accounts.0001_initial... - OK - Applying admin.0001_initial... - OK - Applying admin.0002_logentry_remove_auto_add... - OK - Applying admin.0003_logentry_add_action_flag_choices... - OK - Applying inventory.0001_initial... - OK - Applying customers.0001_initial... - OK - Applying orders.0001_initial... - OK - Applying products.0001_initial... - OK - Applying inventory.0002_initial... - OK - Applying orders.0002_initial... - OK - Applying inventory.0003_showcase_reservation_showcase_and_more... - OK - Applying orders.0003_historicalorderitem_is_from_showcase_and_more... - OK - Applying orders.0004_refactor_models_and_add_payment_method... - OK - Applying customers.0002_customer_is_system_customer... - OK - Applying customers.0003_remove_customer_customers_c_loyalty_5162a0_idx_and_more... - OK - Applying customers.0004_customer_wallet_balance_wallettransaction... - OK - Applying django_celery_results.0001_initial... - OK - Applying django_celery_results.0002_add_task_name_args_kwargs... - OK - Applying django_celery_results.0003_auto_20181106_1101... - OK - Applying django_celery_results.0004_auto_20190516_0412... - OK - Applying django_celery_results.0005_taskresult_worker... - OK - Applying django_celery_results.0006_taskresult_date_created... - OK - Applying django_celery_results.0007_remove_taskresult_hidden... - OK - Applying django_celery_results.0008_chordcounter... - OK - Applying django_celery_results.0009_groupresult... - OK - Applying django_celery_results.0010_remove_duplicate_indices... - OK - Applying django_celery_results.0011_taskresult_periodic_task_name... - OK - Applying products.0002_configurablekitproduct_configurablekitoption... - OK - Applying products.0003_alter_configurablekitproduct_options_and_more... - OK - Applying products.0004_configurablekitproductattribute... - OK - Applying products.0005_alter_configurablekitoption_attributes... - OK - Applying products.0006_add_configurablekitoptionattribute... - OK - Applying products.0007_add_kit_to_attribute... - OK - Applying inventory.0004_showcase_is_default_and_more... - OK - Applying products.0008_productkit_showcase_and_more... - OK - Applying inventory.0005_reservation_product_kit_and_more... - OK - Applying inventory.0006_reservation_cart_lock_expires_at_and_more... - OK - Applying orders.0005_remove_historicalorder_discount_amount_and_more... - OK - Applying orders.0006_transaction_delete_payment_and_more... - OK - Applying products.0009_alter_productcategoryphoto_image_and_more... - OK - Applying products.0010_alter_product_cost_price... - OK - Applying sessions.0001_initial... - OK - Applying tenants.0001_initial... - OK -test_01_draft_to_completed_to_cancelled_to_completed (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_01_draft_to_completed_to_cancelled_to_completed) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #1: ╠эюцхёЄтхээ√х яхЁхїюф√ ьхцфє ёЄрЄєёрьш ... ERROR -test_01_draft_to_completed_to_cancelled_to_completed (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_01_draft_to_completed_to_cancelled_to_completed) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #1: ╠эюцхёЄтхээ√х яхЁхїюф√ ьхцфє ёЄрЄєёрьш ... ERROR -test_02_draft_to_cancelled_releases_reservations (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_02_draft_to_cancelled_releases_reservations) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #2: ╬Єьхэр шч ўхЁэютшър юётюсюцфрхЄ ЁхчхЁт√ ... ERROR -test_02_draft_to_cancelled_releases_reservations (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_02_draft_to_cancelled_releases_reservations) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #2: ╬Єьхэр шч ўхЁэютшър юётюсюцфрхЄ ЁхчхЁт√ ... ERROR -test_03_cancelled_to_pending_reserves_stock (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_03_cancelled_to_pending_reserves_stock) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #3: ┬ючтЁрЄ шч юЄьхэ√ ЁхчхЁтшЁєхЄ ЄютрЁ ... ERROR -test_03_cancelled_to_pending_reserves_stock (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_03_cancelled_to_pending_reserves_stock) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #3: ┬ючтЁрЄ шч юЄьхэ√ ЁхчхЁтшЁєхЄ ЄютрЁ ... ERROR -test_04_create_order_with_intermediate_status (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_04_create_order_with_intermediate_status) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #4: ╤ючфрэшх чрърчр ё яЁюьхцєЄюўэ√ь ёЄрЄєёюь ... ERROR -test_04_create_order_with_intermediate_status (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_04_create_order_with_intermediate_status) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #4: ╤ючфрэшх чрърчр ё яЁюьхцєЄюўэ√ь ёЄрЄєёюь ... ERROR -test_05_completed_to_draft_rollback_sale (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_05_completed_to_draft_rollback_sale) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #5: ╬ЄърЄ юЄ completed ъ draft ... ERROR -test_05_completed_to_draft_rollback_sale (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_05_completed_to_draft_rollback_sale) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #5: ╬ЄърЄ юЄ completed ъ draft ... ERROR - -====================================================================== -ERROR: test_01_draft_to_completed_to_cancelled_to_completed (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_01_draft_to_completed_to_cancelled_to_completed) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #1: ╠эюцхёЄтхээ√х яхЁхїюф√ ьхцфє ёЄрЄєёрьш ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 83, in setUp - self._create_test_data() - ~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 184, in _create_test_data - self.product = Product.objects.create( - ~~~~~~~~~~~~~~~~~~~~~~^ - name='╥хёЄют√щ ЄютрЁ', - ^^^^^^^^^^^^^^^^^^^^^^ - ...<3 lines>... - base_price=Decimal('10.00') - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 677, in create - obj = self.model(**kwargs) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 567, in __init__ - raise TypeError( - ...<2 lines>... - ) -TypeError: Product() got unexpected keyword arguments: 'category', 'base_price' - -====================================================================== -ERROR: test_01_draft_to_completed_to_cancelled_to_completed (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_01_draft_to_completed_to_cancelled_to_completed) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #1: ╠эюцхёЄтхээ√х яхЁхїюф√ ьхцфє ёЄрЄєёрьш ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -psycopg2.errors.FeatureNotSupported: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 73, in handle - connection.ops.execute_sql_flush(sql_list) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\base\operations.py", line 461, in execute_sql_flush - cursor.execute(sql) - ~~~~~~~~~~~~~~^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -django.db.utils.NotSupportedError: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 296, in _setup_and_call - self._post_teardown() - ~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1102, in _post_teardown - self._fixture_teardown() - ~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1136, in _fixture_teardown - call_command( - ~~~~~~~~~~~~^ - "flush", - ^^^^^^^^ - ...<5 lines>... - inhibit_post_migrate=inhibit_post_migrate, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\__init__.py", line 194, in call_command - return command.execute(*args, **defaults) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\base.py", line 459, in execute - output = self.handle(*args, **options) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 75, in handle - raise CommandError( - ...<7 lines>... - ) from exc -django.core.management.base.CommandError: Database test_inventory_db couldn't be flushed. Possible reasons: - * The database isn't running or isn't configured correctly. - * At least one of the expected database tables doesn't exist. - * The SQL was invalid. -Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run. - -====================================================================== -ERROR: test_02_draft_to_cancelled_releases_reservations (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_02_draft_to_cancelled_releases_reservations) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #2: ╬Єьхэр шч ўхЁэютшър юётюсюцфрхЄ ЁхчхЁт√ ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 80, in setUp - self._create_system_entities() - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 156, in _create_system_entities - self.payment_method = PaymentMethod.objects.create( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - code='cash', - ^^^^^^^^^^^^ - ...<2 lines>... - is_active=True - ^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 679, in create - obj.save(force_insert=True, using=self.db) - ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 822, in save - self.save_base( - ~~~~~~~~~~~~~~^ - using=using, - ^^^^^^^^^^^^ - ...<2 lines>... - update_fields=update_fields, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 909, in save_base - updated = self._save_table( - raw, - ...<4 lines>... - update_fields, - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1071, in _save_table - results = self._do_insert( - cls._base_manager, using, fields, returning_fields, raw - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1112, in _do_insert - return manager._insert( - ~~~~~~~~~~~~~~~^ - [self], - ^^^^^^^ - ...<3 lines>... - raw=raw, - ^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 1847, in _insert - return query.get_compiler(using=using).execute_sql(returning_fields) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1823, in execute_sql - cursor.execute(sql, params) - ~~~~~~~~~~~~~~^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -django.db.utils.IntegrityError: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -====================================================================== -ERROR: test_02_draft_to_cancelled_releases_reservations (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_02_draft_to_cancelled_releases_reservations) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #2: ╬Єьхэр шч ўхЁэютшър юётюсюцфрхЄ ЁхчхЁт√ ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -psycopg2.errors.FeatureNotSupported: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 73, in handle - connection.ops.execute_sql_flush(sql_list) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\base\operations.py", line 461, in execute_sql_flush - cursor.execute(sql) - ~~~~~~~~~~~~~~^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -django.db.utils.NotSupportedError: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 296, in _setup_and_call - self._post_teardown() - ~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1102, in _post_teardown - self._fixture_teardown() - ~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1136, in _fixture_teardown - call_command( - ~~~~~~~~~~~~^ - "flush", - ^^^^^^^^ - ...<5 lines>... - inhibit_post_migrate=inhibit_post_migrate, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\__init__.py", line 194, in call_command - return command.execute(*args, **defaults) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\base.py", line 459, in execute - output = self.handle(*args, **options) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 75, in handle - raise CommandError( - ...<7 lines>... - ) from exc -django.core.management.base.CommandError: Database test_inventory_db couldn't be flushed. Possible reasons: - * The database isn't running or isn't configured correctly. - * At least one of the expected database tables doesn't exist. - * The SQL was invalid. -Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run. - -====================================================================== -ERROR: test_03_cancelled_to_pending_reserves_stock (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_03_cancelled_to_pending_reserves_stock) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #3: ┬ючтЁрЄ шч юЄьхэ√ ЁхчхЁтшЁєхЄ ЄютрЁ ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 80, in setUp - self._create_system_entities() - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 156, in _create_system_entities - self.payment_method = PaymentMethod.objects.create( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - code='cash', - ^^^^^^^^^^^^ - ...<2 lines>... - is_active=True - ^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 679, in create - obj.save(force_insert=True, using=self.db) - ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 822, in save - self.save_base( - ~~~~~~~~~~~~~~^ - using=using, - ^^^^^^^^^^^^ - ...<2 lines>... - update_fields=update_fields, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 909, in save_base - updated = self._save_table( - raw, - ...<4 lines>... - update_fields, - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1071, in _save_table - results = self._do_insert( - cls._base_manager, using, fields, returning_fields, raw - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1112, in _do_insert - return manager._insert( - ~~~~~~~~~~~~~~~^ - [self], - ^^^^^^^ - ...<3 lines>... - raw=raw, - ^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 1847, in _insert - return query.get_compiler(using=using).execute_sql(returning_fields) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1823, in execute_sql - cursor.execute(sql, params) - ~~~~~~~~~~~~~~^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -django.db.utils.IntegrityError: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -====================================================================== -ERROR: test_03_cancelled_to_pending_reserves_stock (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_03_cancelled_to_pending_reserves_stock) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #3: ┬ючтЁрЄ шч юЄьхэ√ ЁхчхЁтшЁєхЄ ЄютрЁ ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -psycopg2.errors.FeatureNotSupported: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 73, in handle - connection.ops.execute_sql_flush(sql_list) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\base\operations.py", line 461, in execute_sql_flush - cursor.execute(sql) - ~~~~~~~~~~~~~~^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -django.db.utils.NotSupportedError: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 296, in _setup_and_call - self._post_teardown() - ~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1102, in _post_teardown - self._fixture_teardown() - ~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1136, in _fixture_teardown - call_command( - ~~~~~~~~~~~~^ - "flush", - ^^^^^^^^ - ...<5 lines>... - inhibit_post_migrate=inhibit_post_migrate, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\__init__.py", line 194, in call_command - return command.execute(*args, **defaults) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\base.py", line 459, in execute - output = self.handle(*args, **options) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 75, in handle - raise CommandError( - ...<7 lines>... - ) from exc -django.core.management.base.CommandError: Database test_inventory_db couldn't be flushed. Possible reasons: - * The database isn't running or isn't configured correctly. - * At least one of the expected database tables doesn't exist. - * The SQL was invalid. -Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run. - -====================================================================== -ERROR: test_04_create_order_with_intermediate_status (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_04_create_order_with_intermediate_status) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #4: ╤ючфрэшх чрърчр ё яЁюьхцєЄюўэ√ь ёЄрЄєёюь ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 80, in setUp - self._create_system_entities() - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 156, in _create_system_entities - self.payment_method = PaymentMethod.objects.create( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - code='cash', - ^^^^^^^^^^^^ - ...<2 lines>... - is_active=True - ^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 679, in create - obj.save(force_insert=True, using=self.db) - ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 822, in save - self.save_base( - ~~~~~~~~~~~~~~^ - using=using, - ^^^^^^^^^^^^ - ...<2 lines>... - update_fields=update_fields, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 909, in save_base - updated = self._save_table( - raw, - ...<4 lines>... - update_fields, - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1071, in _save_table - results = self._do_insert( - cls._base_manager, using, fields, returning_fields, raw - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1112, in _do_insert - return manager._insert( - ~~~~~~~~~~~~~~~^ - [self], - ^^^^^^^ - ...<3 lines>... - raw=raw, - ^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 1847, in _insert - return query.get_compiler(using=using).execute_sql(returning_fields) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1823, in execute_sql - cursor.execute(sql, params) - ~~~~~~~~~~~~~~^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -django.db.utils.IntegrityError: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -====================================================================== -ERROR: test_04_create_order_with_intermediate_status (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_04_create_order_with_intermediate_status) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #4: ╤ючфрэшх чрърчр ё яЁюьхцєЄюўэ√ь ёЄрЄєёюь ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -psycopg2.errors.FeatureNotSupported: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 73, in handle - connection.ops.execute_sql_flush(sql_list) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\base\operations.py", line 461, in execute_sql_flush - cursor.execute(sql) - ~~~~~~~~~~~~~~^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -django.db.utils.NotSupportedError: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 296, in _setup_and_call - self._post_teardown() - ~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1102, in _post_teardown - self._fixture_teardown() - ~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1136, in _fixture_teardown - call_command( - ~~~~~~~~~~~~^ - "flush", - ^^^^^^^^ - ...<5 lines>... - inhibit_post_migrate=inhibit_post_migrate, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\__init__.py", line 194, in call_command - return command.execute(*args, **defaults) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\base.py", line 459, in execute - output = self.handle(*args, **options) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 75, in handle - raise CommandError( - ...<7 lines>... - ) from exc -django.core.management.base.CommandError: Database test_inventory_db couldn't be flushed. Possible reasons: - * The database isn't running or isn't configured correctly. - * At least one of the expected database tables doesn't exist. - * The SQL was invalid. -Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run. - -====================================================================== -ERROR: test_05_completed_to_draft_rollback_sale (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_05_completed_to_draft_rollback_sale) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #5: ╬ЄърЄ юЄ completed ъ draft ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 80, in setUp - self._create_system_entities() - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\myproject\inventory\tests\test_order_status_transitions.py", line 156, in _create_system_entities - self.payment_method = PaymentMethod.objects.create( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - code='cash', - ^^^^^^^^^^^^ - ...<2 lines>... - is_active=True - ^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 679, in create - obj.save(force_insert=True, using=self.db) - ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 822, in save - self.save_base( - ~~~~~~~~~~~~~~^ - using=using, - ^^^^^^^^^^^^ - ...<2 lines>... - update_fields=update_fields, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 909, in save_base - updated = self._save_table( - raw, - ...<4 lines>... - update_fields, - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1071, in _save_table - results = self._do_insert( - cls._base_manager, using, fields, returning_fields, raw - ) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\base.py", line 1112, in _do_insert - return manager._insert( - ~~~~~~~~~~~~~~~^ - [self], - ^^^^^^^ - ...<3 lines>... - raw=raw, - ^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method - return getattr(self.get_queryset(), name)(*args, **kwargs) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\query.py", line 1847, in _insert - return query.get_compiler(using=using).execute_sql(returning_fields) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1823, in execute_sql - cursor.execute(sql, params) - ~~~~~~~~~~~~~~^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute - return self.cursor.execute(sql, params) - ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ -django.db.utils.IntegrityError: duplicate key value violates unique constraint "orders_paymentmethod_code_key" -DETAIL: Key (code)=(cash) already exists. - - -====================================================================== -ERROR: test_05_completed_to_draft_rollback_sale (inventory.tests.test_order_status_transitions.OrderStatusTransitionCriticalTest.test_05_completed_to_draft_rollback_sale) -╩╨╚╥╚╫┼╤╩╚╔ ╥┼╤╥ #5: ╬ЄърЄ юЄ completed ъ draft ----------------------------------------------------------------------- -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -psycopg2.errors.FeatureNotSupported: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 73, in handle - connection.ops.execute_sql_flush(sql_list) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\base\operations.py", line 461, in execute_sql_flush - cursor.execute(sql) - ~~~~~~~~~~~~~~^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute - return self._execute_with_wrappers( - ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ - sql, params, many=False, executor=self._execute - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers - return executor(sql, params, many, context) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute - with self.db.wrap_database_errors: - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\utils.py", line 91, in __exit__ - raise dj_exc_value.with_traceback(traceback) from exc_value - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\db\backends\utils.py", line 103, in _execute - return self.cursor.execute(sql) - ~~~~~~~~~~~~~~~~~~~^^^^^ -django.db.utils.NotSupportedError: cannot truncate a table referenced in a foreign key constraint -DETAIL: Table "inventory_reservation" references "accounts_customuser". -HINT: Truncate table "inventory_reservation" at the same time, or use TRUNCATE ... CASCADE. - - -The above exception was the direct cause of the following exception: - -Traceback (most recent call last): - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 296, in _setup_and_call - self._post_teardown() - ~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1102, in _post_teardown - self._fixture_teardown() - ~~~~~~~~~~~~~~~~~~~~~~^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\test\testcases.py", line 1136, in _fixture_teardown - call_command( - ~~~~~~~~~~~~^ - "flush", - ^^^^^^^^ - ...<5 lines>... - inhibit_post_migrate=inhibit_post_migrate, - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ) - ^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\__init__.py", line 194, in call_command - return command.execute(*args, **defaults) - ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^ - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\base.py", line 459, in execute - output = self.handle(*args, **options) - File "C:\Users\team_\Desktop\test_qwen\venv\Lib\site-packages\django\core\management\commands\flush.py", line 75, in handle - raise CommandError( - ...<7 lines>... - ) from exc -django.core.management.base.CommandError: Database test_inventory_db couldn't be flushed. Possible reasons: - * The database isn't running or isn't configured correctly. - * At least one of the expected database tables doesn't exist. - * The SQL was invalid. -Hint: Look at the output of 'django-admin sqlflush'. That's the SQL this command wasn't able to run. - ----------------------------------------------------------------------- -Ran 5 tests in 7.828s - -FAILED (errors=10) -Destroying test database for alias 'default' ('test_inventory_db')... - diff --git a/myproject/test_rollback_fix.py b/myproject/test_rollback_fix.py deleted file mode 100644 index 9052810..0000000 --- a/myproject/test_rollback_fix.py +++ /dev/null @@ -1,232 +0,0 @@ -""" -Тест для проверки исправления двойного возврата товара и резервов. - -Проблема: При смене статуса с 'completed' на нейтральный возвращается -двойное количество товара и резервов. - -Решение: Использовать update() вместо save() для резервов, чтобы избежать -повторного вызова сигнала update_stock_on_reservation_change. -""" - -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from decimal import Decimal -from django.db import transaction -from orders.models import Order, OrderStatus -from inventory.models import Sale, Reservation, Stock, StockBatch - - -def print_state(order, title): - """Выводит текущее состояние заказа, резервов, товара и Stock""" - print(f"\n{'='*60}") - print(f"{title}") - print(f"{'='*60}") - - print(f"Заказ #{order.order_number}: status={order.status.code if order.status else None}") - - # Резервы - print("\nРезервы:") - reservations = Reservation.objects.filter(order_item__order=order).select_related('product') - for res in reservations: - print(f" {res.product.sku}: qty={res.quantity}, status={res.status}") - - # Sale - print("\nSale:") - sales = Sale.objects.filter(order=order).select_related('product') - for sale in sales: - print(f" {sale.product.sku}: qty={sale.quantity}") - - if not sales.exists(): - print(" (нет Sale)") - - # Stock и Batches - print("\nStock и StockBatch:") - for item in order.items.all(): - product = item.product if item.product else item.product_kit - warehouse = order.pickup_warehouse - - if not product or not warehouse: - continue - - # Stock - try: - stock = Stock.objects.get(product=product, warehouse=warehouse) - print(f" {product.sku}:") - print(f" Stock: available={stock.quantity_available}, reserved={stock.quantity_reserved}") - except Stock.DoesNotExist: - print(f" {product.sku}: Stock не найден") - continue - - # Batches - batches = StockBatch.objects.filter( - product=product, - warehouse=warehouse, - is_active=True - ).order_by('created_at') - - total_batch_qty = sum(b.quantity for b in batches) - print(f" Batches (всего {batches.count()}): total_qty={total_batch_qty}") - - for batch in batches: - print(f" Batch #{batch.id}: qty={batch.quantity}, cost={batch.cost_price}") - - -def test_status_change_rollback(): - """ - Тест: Проверка отката при смене статуса completed → draft - - Шаги: - 1. Найти заказ в статусе 'draft' с товарами - 2. Записать начальное состояние Stock/Batches - 3. Перевести в 'completed' (создаются Sale, списывается товар) - 4. Вернуть в 'draft' (откат Sale, восстановление товара) - 5. Проверить, что количество вернулось к исходному (без дублирования) - """ - - print("\n" + "="*80) - print("ТЕСТ: Проверка отката при смене статуса completed → draft") - print("="*80) - - # Найти заказ для теста - draft_status = OrderStatus.objects.get(code='draft') - completed_status = OrderStatus.objects.get(code='completed') - - order = Order.objects.filter(status=draft_status).exclude(items__isnull=True).first() - - if not order: - print("❌ Не найден заказ в статусе 'draft' для теста") - return - - print(f"Тестовый заказ: #{order.order_number}") - - # Получаем товар и склад для проверки - item = order.items.first() - product = item.product if item.product else item.product_kit - warehouse = order.pickup_warehouse - - if not product or not warehouse: - print("❌ У заказа нет товара или склада") - return - - # === ШАГ 1: Записываем начальное состояние === - print_state(order, "ШАГ 1: Начальное состояние (draft)") - - try: - stock_initial = Stock.objects.get(product=product, warehouse=warehouse) - initial_available = stock_initial.quantity_available - initial_reserved = stock_initial.quantity_reserved - except Stock.DoesNotExist: - print("❌ Stock не найден для товара") - return - - batches_initial = list( - StockBatch.objects.filter( - product=product, - warehouse=warehouse, - is_active=True - ).values('id', 'quantity') - ) - - print(f"\n📊 Записано начальное состояние:") - print(f" Stock: available={initial_available}, reserved={initial_reserved}") - print(f" Batches: {len(batches_initial)} партий") - - # === ШАГ 2: Переводим в 'completed' === - print(f"\n{'='*60}") - print("ШАГ 2: Переводим заказ в 'completed'") - print(f"{'='*60}") - - with transaction.atomic(): - order.status = completed_status - order.save() - - print_state(order, "Состояние после перехода в 'completed'") - - # === ШАГ 3: Возвращаем в 'draft' === - print(f"\n{'='*60}") - print("ШАГ 3: Возвращаем заказ в 'draft' (ОТКАТ)") - print(f"{'='*60}") - - with transaction.atomic(): - order.status = draft_status - order.save() - - print_state(order, "Состояние после возврата в 'draft'") - - # === ШАГ 4: Проверка результатов === - print(f"\n{'='*60}") - print("ШАГ 4: Проверка результатов") - print(f"{'='*60}") - - stock_final = Stock.objects.get(product=product, warehouse=warehouse) - final_available = stock_final.quantity_available - final_reserved = stock_final.quantity_reserved - - batches_final = list( - StockBatch.objects.filter( - product=product, - warehouse=warehouse, - is_active=True - ).values('id', 'quantity') - ) - - print(f"\n📊 Сравнение начального и конечного состояния:") - print(f" Stock available: {initial_available} → {final_available}") - print(f" Stock reserved: {initial_reserved} → {final_reserved}") - print(f" Batches count: {len(batches_initial)} → {len(batches_final)}") - - # Проверки - errors = [] - - if final_available != initial_available: - errors.append( - f"❌ Stock.quantity_available не совпадает! " - f"Ожидалось {initial_available}, получено {final_available}" - ) - else: - print(f"✅ Stock.quantity_available вернулся к исходному: {final_available}") - - if final_reserved != initial_reserved: - errors.append( - f"❌ Stock.quantity_reserved не совпадает! " - f"Ожидалось {initial_reserved}, получено {final_reserved}" - ) - else: - print(f"✅ Stock.quantity_reserved вернулся к исходному: {final_reserved}") - - # Проверяем количество в партиях - for batch_init in batches_initial: - batch_final = next((b for b in batches_final if b['id'] == batch_init['id']), None) - if not batch_final: - errors.append(f"❌ Партия #{batch_init['id']} исчезла после отката!") - elif batch_final['quantity'] != batch_init['quantity']: - errors.append( - f"❌ Партия #{batch_init['id']}: количество не совпадает! " - f"Ожидалось {batch_init['quantity']}, получено {batch_final['quantity']}" - ) - - if not errors: - print("\n✅ ТЕСТ ПРОЙДЕН: Все данные вернулись к исходному состоянию!") - else: - print("\n❌ ТЕСТ ПРОВАЛЕН:") - for error in errors: - print(f" {error}") - - # === ШАГ 5: Откатываем изменения (возвращаем заказ в исходное состояние) === - print(f"\n{'='*60}") - print("Откатываем тестовые изменения...") - print(f"{'='*60}") - - with transaction.atomic(): - # Заказ уже в draft, ничего не делаем - pass - - print("Тест завершен.") - - -if __name__ == '__main__': - test_status_change_rollback() diff --git a/myproject/test_smart_quantity_filter.py b/myproject/test_smart_quantity_filter.py deleted file mode 100644 index ed2dd3a..0000000 --- a/myproject/test_smart_quantity_filter.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -""" -Тест для проверки работы фильтра smart_quantity -""" -import os -import django - -# Setup Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from decimal import Decimal -from inventory.templatetags.inventory_filters import smart_quantity - -# Тестовые случаи -test_cases = [ - (5.0, "5"), # Целое число - (5.000, "5"), # Целое с нулями - (10, "10"), # int - (2.5, "2,5"), # Простая дробь - (2.500, "2,5"), # Дробь с лишними нулями - (3.140, "3,14"), # Два знака после запятой - (3.125, "3,125"), # Три знака после запятой - (0.5, "0,5"), # Меньше единицы - (100.0, "100"), # Большое целое - (Decimal("5.000"), "5"), # Decimal целое - (Decimal("2.500"), "2,5"), # Decimal дробное - (Decimal("3.12500"), "3,125"), # Decimal с лишними нулями -] - -print("Testing smart_quantity filter:\n") -print(f"{'Input value':<20} {'Expected':<15} {'Result':<15} {'Status'}") -print("-" * 70) - -all_passed = True -for input_val, expected in test_cases: - result = smart_quantity(input_val) - status = "[PASS]" if result == expected else "[FAIL]" - if result != expected: - all_passed = False - print(f"{str(input_val):<20} {expected:<15} {result:<15} {status}") - -print("-" * 70) -if all_passed: - print("\n[SUCCESS] All tests passed!") -else: - print("\n[ERROR] Some tests failed") - -print("\nПримеры использования в шаблоне:") -print(" {{ batch.quantity|smart_quantity }}") -print(" {{ item.quantity|smart_quantity }}") diff --git a/myproject/test_template_syntax.py b/myproject/test_template_syntax.py deleted file mode 100644 index 8e09f51..0000000 --- a/myproject/test_template_syntax.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -""" -Test template syntax without errors -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django.template import Template, Context - -# Test if the template syntax is valid -try: - # Minimal template to check syntax - test_template = """ - {% for field in form %} - {% if "attribute_" in field.name %} -
{{ field.label }}
- {% endif %} - {% endfor %} - """ - - t = Template(test_template) - print("OK: Template syntax is valid!") - -except Exception as e: - print(f"ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) diff --git a/myproject/test_wallet_system.py b/myproject/test_wallet_system.py deleted file mode 100644 index 439cee7..0000000 --- a/myproject/test_wallet_system.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Тест системы кошелька клиента -""" -import os -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from django_tenants.utils import schema_context -from customers.models import Customer, WalletTransaction -from orders.models import Order, PaymentMethod - -print("\n" + "="*60) -print("ТЕСТ СИСТЕМЫ КОШЕЛЬКА КЛИЕНТА") -print("="*60) - -with schema_context('buba'): - # 1. Проверяем способ оплаты - try: - method = PaymentMethod.objects.get(code='account_balance') - print(f"\n✓ Способ оплаты найден: {method.name}") - print(f" Описание: {method.description}") - print(f" Порядок: {method.order}") - except PaymentMethod.DoesNotExist: - print("\n✗ Способ оплаты 'account_balance' не найден!") - - # 2. Проверяем клиентов - customers = Customer.objects.filter(is_system_customer=False) - print(f"\n✓ Всего клиентов: {customers.count()}") - - if customers.exists(): - customer = customers.first() - print(f"\n Тестовый клиент: {customer.name}") - print(f" Баланс кошелька: {customer.wallet_balance} руб.") - print(f" Всего покупок: {customer.total_spent} руб.") - - # Транзакции - txn_count = customer.wallet_transactions.count() - print(f" Транзакций кошелька: {txn_count}") - - if txn_count > 0: - print("\n Последние транзакции:") - for txn in customer.wallet_transactions.all()[:5]: - print(f" - {txn.created_at.strftime('%d.%m.%Y %H:%M')}: " - f"{txn.get_transaction_type_display()} " - f"{txn.amount} руб.") - - # 3. Проверяем заказы - orders = Order.objects.all() - print(f"\n✓ Всего заказов: {orders.count()}") - - if orders.exists(): - order = orders.first() - print(f"\n Тестовый заказ: #{order.order_number}") - print(f" Клиент: {order.customer.name}") - print(f" Сумма: {order.total_amount} руб.") - print(f" Оплачено: {order.amount_paid} руб.") - print(f" К оплате: {order.amount_due} руб.") - print(f" Статус оплаты: {order.get_payment_status_display()}") - - # Платежи - payments = order.payments.all() - if payments.exists(): - print(f"\n Платежи по заказу:") - for payment in payments: - print(f" - {payment.payment_method.name}: {payment.amount} руб.") - -print("\n" + "="*60) -print("ТЕСТ ЗАВЕРШЁН") -print("="*60 + "\n") diff --git a/myproject/test_workflow.py b/myproject/test_workflow.py deleted file mode 100644 index 8f721b8..0000000 --- a/myproject/test_workflow.py +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env python -""" -Workflow test: Create a full configurable product with attributes and variants -""" -import os -import sys -import django - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') -django.setup() - -from products.models.kits import ( - ConfigurableKitProduct, - ConfigurableKitOption, - ConfigurableKitProductAttribute, - ConfigurableKitOptionAttribute, - ProductKit -) -from django_tenants.utils import tenant_context -from tenants.models import Client -from django.db import transaction - -try: - client = Client.objects.get(schema_name='grach') - print(f"Found tenant: {client.name}\n") -except Client.DoesNotExist: - print("Tenant 'grach' not found") - sys.exit(1) - -with tenant_context(client): - print("=" * 70) - print("WORKFLOW TEST: Complete ConfigurableKitProduct Creation") - print("=" * 70) - - # Step 1: Create ConfigurableKitProduct - print("\n[1] Creating ConfigurableKitProduct...") - with transaction.atomic(): - try: - # Delete old test products - ConfigurableKitProduct.objects.filter(name__icontains="workflow").delete() - - product = ConfigurableKitProduct.objects.create( - name="Workflow Test Product", - sku="WORKFLOW-TEST-001", - description="Test product for workflow validation" - ) - print(f" OK: Created product: {product.name} (ID: {product.id})") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 2: Create attributes with values - print("\n[2] Creating product attributes...") - try: - # Delete old attributes - ConfigurableKitProductAttribute.objects.filter(parent=product).delete() - - attrs_data = [ - ("Dlina", ["50", "60", "70"]), - ("Упаковка", ["BEZ", "V_UPAKOVKE"]) - ] - - created_attrs = {} - for attr_name, values in attrs_data: - print(f" Creating attribute: {attr_name}") - created_attrs[attr_name] = [] - - for pos, value in enumerate(values): - attr = ConfigurableKitProductAttribute.objects.create( - parent=product, - name=attr_name, - option=value, - position=pos, - visible=True - ) - created_attrs[attr_name].append(attr) - print(f" - Created value: {value}") - - print(f" OK: Created {len(created_attrs)} attribute(s)") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 3: Get or create ProductKits - print("\n[3] Getting ProductKits for variants...") - try: - kits = ProductKit.objects.all()[:3] - if kits.count() == 0: - print(" WARNING: No ProductKit found in database") - print(" INFO: Skipping variant creation (need ProductKits in DB)") - print("\n To complete testing:") - print(" 1. Create some ProductKit objects in admin") - print(" 2. Then run this script again") - else: - print(f" OK: Found {kits.count()} ProductKit(s)") - for kit in kits: - print(f" - {kit.name} (SKU: {kit.sku})") - - # Step 4: Create variants with attribute values - print("\n[4] Creating ConfigurableKitOption variants...") - try: - # Delete old options - ConfigurableKitOption.objects.filter(parent=product).delete() - - variant_configs = [ - (kits[0], created_attrs["Dlina"][0], created_attrs["Упаковка"][0], True), # 50, BEZ, default - (kits[1], created_attrs["Dlina"][1], created_attrs["Упаковка"][1], False), # 60, V_UPAKOVKE - (kits[2], created_attrs["Dlina"][2], created_attrs["Упаковка"][0], False), # 70, BEZ - ] - - for kit, dlina_attr, upakovka_attr, is_default in variant_configs: - option = ConfigurableKitOption.objects.create( - parent=product, - kit=kit, - is_default=is_default - ) - print(f" Created variant {option.id} for kit: {kit.name}") - - # Create M2M relationships - ConfigurableKitOptionAttribute.objects.create( - option=option, - attribute=dlina_attr - ) - ConfigurableKitOptionAttribute.objects.create( - option=option, - attribute=upakovka_attr - ) - print(f" - Linked attributes: Dlina={dlina_attr.option}, Upakovka={upakovka_attr.option}") - - print(f" OK: Created {len(variant_configs)} variant(s)") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - # Step 5: Verify data retrieval - print("\n[5] Verifying variant data...") - try: - options = ConfigurableKitOption.objects.filter(parent=product) - print(f" Found {options.count()} variant(s)") - - for opt in options: - print(f"\n Variant {opt.id}:") - print(f" - Kit: {opt.kit.name}") - print(f" - Default: {opt.is_default}") - - # Get attributes through M2M - opt_attrs = opt.attributes_set.all() - print(f" - Attributes ({opt_attrs.count()}):") - for opt_attr in opt_attrs: - print(f" * {opt_attr.attribute.name} = {opt_attr.attribute.option}") - - print("\n OK: All data retrieves correctly") - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - except Exception as e: - print(f" ERROR: {e}") - import traceback - traceback.print_exc() - sys.exit(1) - - print("\n" + "=" * 70) - print("OK: WORKFLOW TEST COMPLETED SUCCESSFULLY!") - print("=" * 70) diff --git a/run_status_tests.bat b/run_status_tests.bat deleted file mode 100644 index f4454f5..0000000 --- a/run_status_tests.bat +++ /dev/null @@ -1,10 +0,0 @@ -@echo off -REM Скрипт для запуска тестов переходов между статусами заказов - -cd /d C:\Users\team_\Desktop\test_qwen -call .venv\Scripts\activate.bat - -cd myproject -python manage.py test inventory.tests.test_order_status_transitions --verbosity=2 - -pause diff --git a/test_simple.py b/test_simple.py deleted file mode 100644 index 2fb64ff..0000000 --- a/test_simple.py +++ /dev/null @@ -1,2 +0,0 @@ -print -Testing wallet diff --git a/ГИД ПО ЗАПУСКУ b/ГИД ПО ЗАПУСКУ deleted file mode 100644 index 97884db..0000000 --- a/ГИД ПО ЗАПУСКУ +++ /dev/null @@ -1,44 +0,0 @@ -docker run -d ` - --name postgres17 ` - -e POSTGRES_PASSWORD=postgres ` - -e POSTGRES_USER=postgres ` - -e POSTGRES_DB=inventory_db ` - -p 5432:5432 ` - -v postgres17-data:/var/lib/postgresql/data ` - postgres:17 - - # 2. Создаем миграции с нуля -python manage.py makemigrations - -# 3. Применяем все миграции -python manage.py migrate - -# 4. Создаем главного тенанта (если нужно) -python manage.py shell -# Внутри shell: -from tenants.models import Client, Domain -client = Client.objects.create( - name='Main', - schema_name='public' -) -Domain.objects.create( - domain='localhost', - tenant=client, - is_primary=True -) -exit() - -# 5. Создаем суперпользователя для public схемы -python manage.py createsuperuser - -# 6. Создаем суперпользователя для конкретного тенанта (опционально) -python manage.py shell -# Внутри: -from tenants.models import Client -from django.core.management import call_command -from django_tenants.utils import schema_context - -client = Client.objects.get(schema_name='public') -with schema_context(client): - call_command('createsuperuser') -exit() \ No newline at end of file