Добавлена защита от повторного списания + команда исправления дубликатов

Проблема: Сигнал post_save срабатывает несколько раз,
создавая дубликаты Sale для одного заказа.

Решения:
1. Добавлена проверка Sale.objects.filter(order=instance).exists()
   перед созданием продаж (inventory/signals.py:74-75)
2. Создана management команда fix_duplicate_sales для исправления
   существующих дубликатов

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-30 22:15:33 +03:00
parent 24292b2e47
commit 920dbf4273
5 changed files with 381 additions and 0 deletions

167
check_order.py Normal file
View File

@@ -0,0 +1,167 @@
#!/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()