- Автоматическое проведение документов списания и оприходования после завершения инвентаризации - Оптимизация SQL-запросов: устранение N+1, bulk-операции для Stock, агрегация для StockBatch и Reservation - Изменение формулы расчета разницы: (quantity_fact + quantity_reserved) - quantity_available - Переименование поля 'По факту' в 'Подсчитано (факт, свободные)' - Добавлены столбцы 'В резервах' и 'Всего на складе' в таблицу инвентаризации - Перемещение столбца 'В системе (свободно)' после 'В резервах' с визуальным выделением - Центральное выравнивание значений в столбцах таблицы - Автоматическое выделение текста при фокусе на поле ввода количества - Исправление форматирования разницы (убраны лишние нули) - Изменение статуса 'Не обработана' на 'Не проведено' - Добавление номера документа для инвентаризаций (INV-XXXXXX) - Отображение всех типов списаний в debug-странице (WriteOff, WriteOffDocument, WriteOffDocumentItem) - Улучшение отображения документов в детальном просмотре инвентаризации с возможностью перехода к ним
138 lines
6.1 KiB
Python
138 lines
6.1 KiB
Python
"""
|
||
Отладочные view для суперюзеров.
|
||
Для мониторинга работы системы инвентаризации.
|
||
"""
|
||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||
from django.shortcuts import render
|
||
from django.db.models import Q, Sum, Count
|
||
from inventory.models import StockBatch, Stock, Reservation, Sale, SaleBatchAllocation, WriteOff, WriteOffDocument, WriteOffDocumentItem
|
||
from orders.models import Order
|
||
from products.models import Product
|
||
from inventory.models import Warehouse
|
||
|
||
|
||
def is_superuser(user):
|
||
"""Проверка что пользователь - суперюзер."""
|
||
return user.is_superuser
|
||
|
||
|
||
@login_required
|
||
@user_passes_test(is_superuser)
|
||
def debug_inventory_page(request):
|
||
"""
|
||
Отладочная страница для суперюзеров.
|
||
Показывает полную картину по инвентаризации: партии, остатки, резервы, продажи.
|
||
"""
|
||
# Получаем параметры фильтров
|
||
product_id = request.GET.get('product')
|
||
order_number = request.GET.get('order')
|
||
warehouse_id = request.GET.get('warehouse')
|
||
|
||
# Базовые querysets
|
||
stock_batches = StockBatch.objects.select_related('product', 'warehouse').order_by('-created_at')
|
||
stocks = Stock.objects.select_related('product', 'warehouse').order_by('product__name')
|
||
reservations = Reservation.objects.select_related(
|
||
'product', 'warehouse', 'order_item__order'
|
||
).order_by('-reserved_at')
|
||
sales = Sale.objects.select_related('product', 'warehouse', 'order').order_by('-date')
|
||
allocations = SaleBatchAllocation.objects.select_related(
|
||
'sale__product', 'batch'
|
||
).order_by('-id')
|
||
# Все списания: из продаж (WriteOff) и из документов списания (WriteOffDocumentItem)
|
||
writeoffs = WriteOff.objects.select_related('batch__product', 'batch__warehouse').order_by('-date')
|
||
writeoff_documents = WriteOffDocument.objects.select_related('warehouse').order_by('-date')
|
||
writeoff_document_items = WriteOffDocumentItem.objects.select_related(
|
||
'product', 'document__warehouse'
|
||
).order_by('-id')
|
||
orders = Order.objects.prefetch_related('items').order_by('-created_at')
|
||
|
||
# Применяем фильтры
|
||
if product_id:
|
||
product = Product.objects.filter(id=product_id).first()
|
||
stock_batches = stock_batches.filter(product_id=product_id)
|
||
stocks = stocks.filter(product_id=product_id)
|
||
reservations = reservations.filter(product_id=product_id)
|
||
sales = sales.filter(product_id=product_id)
|
||
allocations = allocations.filter(sale__product_id=product_id)
|
||
writeoffs = writeoffs.filter(batch__product_id=product_id)
|
||
writeoff_document_items = writeoff_document_items.filter(product_id=product_id)
|
||
orders = orders.filter(items__product_id=product_id).distinct()
|
||
else:
|
||
product = None
|
||
|
||
if order_number:
|
||
# Парсим номер заказа: "ORD-103" -> 103 или "103" -> 103
|
||
try:
|
||
# Если формат "ORD-XXX", извлекаем число
|
||
if order_number.upper().startswith('ORD-'):
|
||
order_num = int(order_number.upper().replace('ORD-', ''))
|
||
else:
|
||
# Просто число
|
||
order_num = int(order_number)
|
||
|
||
order = Order.objects.filter(order_number=order_num).first()
|
||
except (ValueError, AttributeError):
|
||
order = None
|
||
|
||
if order:
|
||
reservations = reservations.filter(order_item__order=order)
|
||
sales = sales.filter(order=order)
|
||
# Фильтруем товары по заказу
|
||
product_ids = order.items.values_list('product_id', flat=True)
|
||
stock_batches = stock_batches.filter(product_id__in=product_ids)
|
||
stocks = stocks.filter(product_id__in=product_ids)
|
||
allocations = allocations.filter(sale__order=order)
|
||
# Фильтруем только этот заказ в таблице заказов
|
||
orders = orders.filter(id=order.id)
|
||
else:
|
||
order = None
|
||
|
||
if warehouse_id:
|
||
warehouse = Warehouse.objects.filter(id=warehouse_id).first()
|
||
stock_batches = stock_batches.filter(warehouse_id=warehouse_id)
|
||
stocks = stocks.filter(warehouse_id=warehouse_id)
|
||
reservations = reservations.filter(warehouse_id=warehouse_id)
|
||
sales = sales.filter(warehouse_id=warehouse_id)
|
||
writeoffs = writeoffs.filter(batch__warehouse_id=warehouse_id)
|
||
writeoff_documents = writeoff_documents.filter(warehouse_id=warehouse_id)
|
||
writeoff_document_items = writeoff_document_items.filter(document__warehouse_id=warehouse_id)
|
||
else:
|
||
warehouse = None
|
||
|
||
# Ограничиваем количество записей для производительности
|
||
stock_batches = stock_batches[:100]
|
||
stocks = stocks[:100]
|
||
reservations = reservations[:100]
|
||
sales = sales[:100]
|
||
allocations = allocations[:100]
|
||
writeoffs = writeoffs[:100]
|
||
writeoff_documents = writeoff_documents[:50]
|
||
writeoff_document_items = writeoff_document_items[:100]
|
||
orders = orders[:50]
|
||
|
||
# Списки для фильтров
|
||
products = Product.objects.filter(archived_at__isnull=True).order_by('name')[:200]
|
||
warehouses = Warehouse.objects.filter(is_active=True).order_by('name')
|
||
|
||
context = {
|
||
'stock_batches': stock_batches,
|
||
'stocks': stocks,
|
||
'reservations': reservations,
|
||
'sales': sales,
|
||
'allocations': allocations,
|
||
'writeoffs': writeoffs,
|
||
'writeoff_documents': writeoff_documents,
|
||
'writeoff_document_items': writeoff_document_items,
|
||
'orders': orders,
|
||
'products': products,
|
||
'warehouses': warehouses,
|
||
'selected_product': product,
|
||
'selected_order': order,
|
||
'selected_warehouse': warehouse,
|
||
'product_id': product_id,
|
||
'order_number': order_number,
|
||
'warehouse_id': warehouse_id,
|
||
}
|
||
|
||
return render(request, 'inventory/debug_page.html', context)
|