diff --git a/myproject/inventory/templates/inventory/debug_page.html b/myproject/inventory/templates/inventory/debug_page.html new file mode 100644 index 0000000..d37d25d --- /dev/null +++ b/myproject/inventory/templates/inventory/debug_page.html @@ -0,0 +1,417 @@ +{% extends 'base.html' %} +{% load static %} + +{% block title %}Отладка Inventory - Суперюзер{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
+
+
+

🔧 Отладка Inventory (только для суперюзеров)

+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + Сбросить +
+
+
+ + {% if selected_product or selected_order or selected_warehouse %} +
+ Активные фильтры: + {% if selected_product %}Товар: {{ selected_product.name }}{% endif %} + {% if selected_order %}Заказ: {{ selected_order.order_number }}{% endif %} + {% if selected_warehouse %}Склад: {{ selected_warehouse.name }}{% endif %} +
+ {% endif %} + + +
+

📦 Заказы ({{ orders.count }})

+
+ + + + + + + + + + + + + + + {% for order in orders %} + + + + + + + + + + + {% empty %} + + {% endfor %} + +
IDНомерСтатусВозвратПокупательТоварыСуммаСоздан
{{ order.id }}{{ order.order_number }} + {{ order.status.name|default:"?" }} + + {% if order.is_returned %} + Возврат + {% else %} + - + {% endif %} + {{ order.customer.name|default:"-" }}{{ order.items.count }} шт{{ order.total_price|floatformat:2 }}{{ order.created_at|date:"d.m.Y H:i" }}
Нет заказов
+
+
+ + +
+

📊 Остатки Stock ({{ stocks.count }})

+
+ + + + + + + + + + + + + + {% for stock in stocks %} + + + + + + + + + + {% empty %} + + {% endfor %} + +
IDТоварСкладДоступноЗарезервированоСвободноОбновлено
{{ stock.id }}{{ stock.product.name }}{{ stock.warehouse.name }}{{ stock.quantity_available }}{{ stock.quantity_reserved }}{{ stock.quantity_free }}{{ stock.updated_at|date:"d.m.Y H:i:s" }}
Нет данных Stock
+
+
+ + +
+

📦 Партии StockBatch ({{ stock_batches.count }})

+
+ + + + + + + + + + + + + + {% for batch in stock_batches %} + + + + + + + + + + {% empty %} + + {% endfor %} + +
IDТоварСкладКол-воСебест.АктивнаСоздана
{{ batch.id }}{{ batch.product.name }}{{ batch.warehouse.name }}{{ batch.quantity }}{{ batch.cost_per_unit|floatformat:2 }} + {% if batch.is_active %} + Да + {% else %} + Нет + {% endif %} + {{ batch.created_at|date:"d.m.Y H:i" }}
Нет партий
+
+
+ + +
+

🔒 Резервы Reservation ({{ reservations.count }})

+
+ + + + + + + + + + + + + + + + {% for res in reservations %} + + + + + + + + + + + + {% empty %} + + {% endfor %} + +
IDТоварСкладКол-воСтатусЗаказСозданПреобразованОсвобожден
{{ res.id }}{{ res.product.name }}{{ res.warehouse.name }}{{ res.quantity }} + {% if res.status == 'reserved' %} + Зарезервирован + {% elif res.status == 'converted_to_sale' %} + В продажу + {% elif res.status == 'released' %} + Освобожден + {% else %} + {{ res.status }} + {% endif %} + + {% if res.order_item.order %} + {{ res.order_item.order.order_number }} + {% else %} + - + {% endif %} + {{ res.created_at|date:"d.m.Y H:i:s" }} + {% if res.converted_at %}{{ res.converted_at|date:"d.m.Y H:i:s" }}{% else %}-{% endif %} + + {% if res.released_at %}{{ res.released_at|date:"d.m.Y H:i:s" }}{% else %}-{% endif %} +
Нет резервов
+
+
+ + +
+

💰 Продажи Sale ({{ sales.count }})

+
+ + + + + + + + + + + + + + + + {% for sale in sales %} + + + + + + + + + + + + {% empty %} + + {% endfor %} + +
IDТоварСкладКол-воЦена продажиСебестоимостьЗаказДокументСоздана
{{ sale.id }}{{ sale.product.name }}{{ sale.warehouse.name }}{{ sale.quantity }}{{ sale.sale_price|floatformat:2 }}{{ sale.cost_price|floatformat:2 }} + {% if sale.order %} + {{ sale.order.order_number }} + {% else %} + - + {% endif %} + {{ sale.document_number|default:"-" }}{{ sale.created_at|date:"d.m.Y H:i:s" }}
Нет продаж
+
+
+ + +
+

📤 Списания SaleBatchAllocation ({{ allocations.count }})

+
+ + + + + + + + + + + + + {% for alloc in allocations %} + + + + + + + + + {% empty %} + + {% endfor %} + +
IDSale IDТоварПартия IDКол-во списаноСебест. за ед.
{{ alloc.id }}{{ alloc.sale.id }}{{ alloc.sale.product.name }}{{ alloc.batch.id }}{{ alloc.quantity }}{{ alloc.cost_per_unit|floatformat:2 }}
Нет списаний
+
+
+ +
+ Примечание: Показаны последние 100 записей для каждой таблицы. + Используйте фильтры для уточнения результатов. +
+
+
+
+{% endblock %} diff --git a/myproject/inventory/urls.py b/myproject/inventory/urls.py index a9edf6b..423cf29 100644 --- a/myproject/inventory/urls.py +++ b/myproject/inventory/urls.py @@ -28,6 +28,8 @@ from .views import ( ) # Showcase views from .views.showcase import ShowcaseListView, ShowcaseCreateView, ShowcaseUpdateView, ShowcaseDeleteView, SetDefaultShowcaseView +# Debug views +from .views.debug_views import debug_inventory_page from . import views app_name = 'inventory' @@ -102,4 +104,7 @@ urlpatterns = [ path('showcases//edit/', ShowcaseUpdateView.as_view(), name='showcase-update'), path('showcases//delete/', ShowcaseDeleteView.as_view(), name='showcase-delete'), path('showcases//set-default/', SetDefaultShowcaseView.as_view(), name='showcase-set-default'), + + # ==================== DEBUG (SUPERUSER ONLY) ==================== + path('debug/', debug_inventory_page, name='debug_page'), ] diff --git a/myproject/inventory/views/debug_views.py b/myproject/inventory/views/debug_views.py new file mode 100644 index 0000000..76ff79a --- /dev/null +++ b/myproject/inventory/views/debug_views.py @@ -0,0 +1,106 @@ +""" +Отладочные 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 +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('-created_at') + sales = Sale.objects.select_related('product', 'warehouse', 'order').order_by('-created_at') + allocations = SaleBatchAllocation.objects.select_related( + 'sale__product', 'batch' + ).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) + orders = orders.filter(items__product_id=product_id).distinct() + else: + product = None + + if order_number: + order = Order.objects.filter(order_number=order_number).first() + 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) + 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) + else: + warehouse = None + + # Ограничиваем количество записей для производительности + stock_batches = stock_batches[:100] + stocks = stocks[:100] + reservations = reservations[:100] + sales = sales[:100] + allocations = allocations[:100] + orders = orders[:50] + + # Списки для фильтров + products = Product.objects.filter(is_active=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, + '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) diff --git a/myproject/templates/navbar.html b/myproject/templates/navbar.html index cbef61b..fa48118 100644 --- a/myproject/templates/navbar.html +++ b/myproject/templates/navbar.html @@ -51,8 +51,13 @@ Витрины + {% if user.is_superuser %} + + {% endif %} {% endif %}