Проблема: - При смене статуса заказа на 'Выполнен' товар списывался со склада - Резервы обновлялись на статус 'converted_to_sale' - НО Stock.quantity_reserved не обновлялся автоматически - В результате резервы продолжали 'держать' товар, хотя он уже продан Решение: 1. Изменен сигнал create_sale_on_order_completion: - Используется .save(update_fields=[...]) вместо .update() - Это вызывает сигнал update_stock_on_reservation_change - Убран костыль с ручным вызовом refresh_from_batches() 2. Оптимизирован сигнал update_stock_on_reservation_change: - Stock обновляется ТОЛЬКО при изменении status или quantity - При изменении других полей (даты и т.д.) Stock НЕ пересчитывается - Предотвращены лишние пересчёты и улучшена производительность 3. Добавлены диагностические инструменты: - check_stock_103.py - для диагностики проблем с Stock - fix_stock_after_sale.py - команда для исправления старых заказов - diagnose_reservation_issue.py - универсальная диагностика Результат: - Элегантное решение без дублирования логики - Stock автоматически обновляется при изменении резервов - Работает везде, не только в заказах - Оптимизировано для производительности
96 lines
4.0 KiB
Python
96 lines
4.0 KiB
Python
#!/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("✅ Всё в порядке!")
|