Интегрирован компонент поиска товаров в документы списания с фильтром по складу
- Добавлен параметр warehouse в API search_products_and_variants - API фильтрует товары по наличию на указанном складе через Stock - Обновлен _apply_product_filters для поддержки warehouse_id - ProductSearchPicker теперь поддерживает data-warehouse-id - Warehouse автоматически передается в AJAX запросы - В WriteOffDocumentDetailView добавлены categories и tags в контекст - Компонент поиска встроен в detail.html с жестким фильтром по складу документа - Single-select режим для выбора одного товара - JS автоматически заполняет select формы при выборе товара - Отображение выбранного товара с фото и артикулом - Автофокус на поле количества после выбора товара - Пользователь видит только товары доступные на складе документа
This commit is contained in:
@@ -20,7 +20,7 @@ def _get_product_photo_url(product_id):
|
||||
return None
|
||||
|
||||
|
||||
def _apply_product_filters(queryset, category_id=None, tag_id=None, in_stock_only=False):
|
||||
def _apply_product_filters(queryset, category_id=None, tag_id=None, in_stock_only=False, warehouse_id=None):
|
||||
"""Применяет фильтры к queryset товаров."""
|
||||
if category_id:
|
||||
queryset = queryset.filter(categories__id=category_id)
|
||||
@@ -28,6 +28,14 @@ def _apply_product_filters(queryset, category_id=None, tag_id=None, in_stock_onl
|
||||
queryset = queryset.filter(tags__id=tag_id)
|
||||
if in_stock_only:
|
||||
queryset = queryset.filter(in_stock=True)
|
||||
if warehouse_id:
|
||||
# Фильтруем только товары, которые есть на указанном складе с доступным количеством
|
||||
from inventory.models import Stock
|
||||
products_with_stock = Stock.objects.filter(
|
||||
warehouse_id=warehouse_id,
|
||||
quantity_available__gt=0
|
||||
).values_list('product_id', flat=True)
|
||||
queryset = queryset.filter(id__in=products_with_stock)
|
||||
return queryset.distinct()
|
||||
|
||||
|
||||
@@ -44,6 +52,7 @@ def search_products_and_variants(request):
|
||||
- category: ID категории для фильтрации (опционально)
|
||||
- tag: ID тега для фильтрации (опционально)
|
||||
- in_stock: 'true' для фильтрации только товаров в наличии (опционально)
|
||||
- warehouse: ID склада для фильтрации только товаров с доступным остатком (опционально)
|
||||
|
||||
Возвращает JSON в формате Select2 с группировкой:
|
||||
{
|
||||
@@ -156,11 +165,12 @@ def search_products_and_variants(request):
|
||||
category_id = request.GET.get('category', '').strip()
|
||||
tag_id = request.GET.get('tag', '').strip()
|
||||
in_stock_only = request.GET.get('in_stock', '').lower() == 'true'
|
||||
warehouse_id = request.GET.get('warehouse', '').strip()
|
||||
|
||||
results = []
|
||||
|
||||
# Проверяем, есть ли дополнительные фильтры
|
||||
has_filters = category_id or tag_id or in_stock_only
|
||||
has_filters = category_id or tag_id or in_stock_only or warehouse_id
|
||||
|
||||
# Если поиска нет - показываем популярные товары и комплекты
|
||||
if not query or len(query) < 2:
|
||||
@@ -178,7 +188,7 @@ def search_products_and_variants(request):
|
||||
# Показываем последние добавленные активные товары
|
||||
products_qs = Product.objects.filter(status='active')
|
||||
# Применяем фильтры
|
||||
products_qs = _apply_product_filters(products_qs, category_id, tag_id, in_stock_only)
|
||||
products_qs = _apply_product_filters(products_qs, category_id, tag_id, in_stock_only, warehouse_id)
|
||||
products = products_qs.order_by('-created_at')[:page_size]\
|
||||
.values('id', 'name', 'sku', 'price', 'sale_price', 'in_stock')
|
||||
|
||||
@@ -305,7 +315,7 @@ def search_products_and_variants(request):
|
||||
).order_by('-relevance', 'name')
|
||||
|
||||
# Применяем дополнительные фильтры
|
||||
products_query = _apply_product_filters(products_query, category_id, tag_id, in_stock_only)
|
||||
products_query = _apply_product_filters(products_query, category_id, tag_id, in_stock_only, warehouse_id)
|
||||
|
||||
total_products = products_query.count()
|
||||
start = (page - 1) * page_size
|
||||
|
||||
Reference in New Issue
Block a user