fix: Исправить логику обновления Product.in_stock из Stock остатков

Проблема: товары отображались как "нет в наличии" несмотря на наличие остатков на складе.

Причина: сигналы на обновление Product.in_stock срабатывают только при изменении Stock через Django ORM.
Если Stock была создана напрямую (импорт, миграция и т.д.), сигналы не срабатывали.

Решение:

1. Исправлена логика сигналов (inventory/signals.py):
   - Добавлен импорт post_delete для правильной обработки удаления Stock
   - Изменён pre_delete на post_delete для более надёжной проверки остатков
   - Сигналы теперь правильно срабатывают при любом изменении Stock

2. Добавлена миграция (products/migrations/0004_fix_product_in_stock.py):
   - Пересчитывает in_stock для всех существующих товаров на основе Stock.quantity_available
   - Товар считается в наличии если есть хотя бы один Stock с quantity_available > 0
   - Обратима и безопасна (может быть отменена)

3. Добавлена команда управления (products/management/commands/update_product_in_stock.py):
   - Позволяет вручную пересчитать in_stock если потребуется
   - Поддерживает параметр --verbose для подробного логирования
   - Может быть запущена по расписанию или вручную

После этого исправления:
- Все товары с остатками на складе автоматически обновляют статус in_stock
- Сигналы срабатывают при любом изменении Stock (создание, обновление, удаление)
- Отображение наличия товаров в UI будет корректным

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-29 23:42:20 +03:00
parent 9ff1f2d184
commit 83412f3447
4 changed files with 209 additions and 6 deletions

80
fix_product_in_stock.py Normal file
View File

@@ -0,0 +1,80 @@
#!/usr/bin/env python
"""
Скрипт для исправления статуса Product.in_stock на основе текущих остатков в Stock.
Пересчитывает in_stock для всех товаров, которые имеют остатки на складе.
"""
import os
import sys
import django
# Добавляем путь к myproject
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'myproject'))
os.chdir(os.path.join(os.path.dirname(__file__), 'myproject'))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
from decimal import Decimal
from products.models import Product
from inventory.models import Stock
def fix_product_in_stock():
"""
Исправить статус in_stock для всех товаров.
Логика:
- Если для товара есть Stock с quantity_available > 0 → in_stock = True
- Если нет таких Stock или все пусты → in_stock = False
"""
print("\n" + "="*80)
print("ИСПРАВЛЕНИЕ СТАТУСА НАЛИЧИЯ ТОВАРОВ")
print("="*80 + "\n")
# Получаем все товары
all_products = Product.all_objects.all()
total = all_products.count()
updated = 0
no_stock = 0
print(f"Всего товаров в системе: {total}\n")
for product in all_products:
# Проверяем есть ли остаток
has_stock = Stock.objects.filter(
product=product,
quantity_available__gt=0
).exists()
# Обновляем in_stock если статус изменился
if product.in_stock != has_stock:
Product.all_objects.filter(id=product.id).update(in_stock=has_stock)
status = "ДОБАВЛЕН В НАЛИЧИЕ" if has_stock else "УБРАН ИЗ НАЛИЧИЯ"
print(f"{product.name:50}{status}")
updated += 1
else:
if not has_stock:
no_stock += 1
print("\n" + "="*80)
print(f"РЕЗУЛЬТАТЫ:")
print(f" - Всего товаров: {total}")
print(f" - Обновлено: {updated}")
print(f" - Товаров без наличия: {no_stock}")
print("="*80 + "\n")
# Проверка
print("ПРОВЕРКА:")
in_stock_count = Product.all_objects.filter(in_stock=True).count()
out_of_stock_count = Product.all_objects.filter(in_stock=False).count()
print(f" - Товаров в наличии: {in_stock_count}")
print(f" - Товаров не в наличии: {out_of_stock_count}")
print("="*80 + "\n")
if __name__ == '__main__':
try:
fix_product_in_stock()
except Exception as e:
print(f"\nОШИБКА: {e}")
import traceback
traceback.print_exc()