Исправлен поиск товаров при приёмке: добавлен параметр skip_stock_filter
Проблема: при приёмке товаров отображались только товары с ненулевым остатком на складе, товары с нулевым остатком не находились. Решение: добавлен параметр skip_stock_filter в компонент поиска товаров, который отключает фильтрацию по остаткам. Для приёмки этот параметр включён по умолчанию. Изменения: - api_views.py: добавлен параметр skip_stock_filter в _apply_product_filters - product_search_picker.html: добавлен data-атрибут skip_stock_filter - product-search-picker.js: передача параметра в API - incoming_document_detail.html: включён skip_stock_filter=True 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -118,7 +118,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<!-- Компонент поиска товаров -->
|
<!-- Компонент поиска товаров -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
{% include 'products/components/product_search_picker.html' with container_id='incoming-picker' title='Найти товар для поступления' warehouse_id=document.warehouse.id filter_in_stock_only=False categories=categories tags=tags add_button_text='Выбрать товар' content_height='250px' %}
|
{% include 'products/components/product_search_picker.html' with container_id='incoming-picker' title='Найти товар для поступления' warehouse_id=document.warehouse.id filter_in_stock_only=False skip_stock_filter=True categories=categories tags=tags add_button_text='Выбрать товар' content_height='250px' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Информация о выбранном товаре -->
|
<!-- Информация о выбранном товаре -->
|
||||||
|
|||||||
@@ -61,7 +61,8 @@
|
|||||||
category: '',
|
category: '',
|
||||||
tag: '',
|
tag: '',
|
||||||
inStock: false,
|
inStock: false,
|
||||||
warehouse: '' // ID склада для фильтрации
|
warehouse: '', // ID склада для фильтрации
|
||||||
|
skipStockFilter: false // Не фильтровать по остаткам (для приёмки)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,6 +106,11 @@
|
|||||||
if (this.container.dataset.warehouseId) {
|
if (this.container.dataset.warehouseId) {
|
||||||
this.state.filters.warehouse = this.container.dataset.warehouseId;
|
this.state.filters.warehouse = this.container.dataset.warehouseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Инициализация skipStockFilter из data-атрибута
|
||||||
|
if (this.container.dataset.skipStockFilter === 'true') {
|
||||||
|
this.state.filters.skipStockFilter = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,6 +272,9 @@
|
|||||||
if (this.state.filters.warehouse) {
|
if (this.state.filters.warehouse) {
|
||||||
params.append('warehouse', this.state.filters.warehouse);
|
params.append('warehouse', this.state.filters.warehouse);
|
||||||
}
|
}
|
||||||
|
if (this.state.filters.skipStockFilter) {
|
||||||
|
params.append('skip_stock_filter', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
fetch(this.options.apiUrl + '?' + params.toString())
|
fetch(this.options.apiUrl + '?' + params.toString())
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
- initial_view: начальный вид 'grid' или 'list' (default: 'list')
|
- initial_view: начальный вид 'grid' или 'list' (default: 'list')
|
||||||
- filter_in_stock_only: показывать только товары в наличии (default: False)
|
- filter_in_stock_only: показывать только товары в наличии (default: False)
|
||||||
- warehouse_id: ID склада для фильтрации товаров (default: None)
|
- warehouse_id: ID склада для фильтрации товаров (default: None)
|
||||||
|
- skip_stock_filter: не фильтровать по остаткам на складе (default: False, для приёмки: True)
|
||||||
- categories: список категорий для фильтра (queryset или list)
|
- categories: список категорий для фильтра (queryset или list)
|
||||||
- tags: список тегов для фильтра (queryset или list)
|
- tags: список тегов для фильтра (queryset или list)
|
||||||
- content_height: высота контейнера с товарами (default: '400px')
|
- content_height: высота контейнера с товарами (default: '400px')
|
||||||
@@ -43,7 +44,8 @@ ProductSearchPicker.init('#writeoff-products', {
|
|||||||
id="{{ container_id|default:'product-search-picker' }}"
|
id="{{ container_id|default:'product-search-picker' }}"
|
||||||
data-api-url="{{ api_url|default:'/products/api/search-products-variants/' }}"
|
data-api-url="{{ api_url|default:'/products/api/search-products-variants/' }}"
|
||||||
data-exclude-kits="true"
|
data-exclude-kits="true"
|
||||||
{% if warehouse_id %}data-warehouse-id="{{ warehouse_id }}"{% endif %}>
|
{% if warehouse_id %}data-warehouse-id="{{ warehouse_id }}"{% endif %}
|
||||||
|
{% if skip_stock_filter %}data-skip-stock-filter="true"{% endif %}>
|
||||||
|
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
<!-- Строка поиска -->
|
<!-- Строка поиска -->
|
||||||
|
|||||||
@@ -21,16 +21,22 @@ def _get_product_photo_url(product_id):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _apply_product_filters(queryset, category_id=None, tag_id=None, in_stock_only=False, warehouse_id=None):
|
def _apply_product_filters(queryset, category_id=None, tag_id=None, in_stock_only=False, warehouse_id=None, skip_stock_filter=False):
|
||||||
"""Применяет фильтры к queryset товаров."""
|
"""Применяет фильтры к queryset товаров.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
skip_stock_filter: Если True, warehouse_id не фильтрует по остаткам.
|
||||||
|
Используется для приёмки товаров.
|
||||||
|
"""
|
||||||
if category_id:
|
if category_id:
|
||||||
queryset = queryset.filter(categories__id=category_id)
|
queryset = queryset.filter(categories__id=category_id)
|
||||||
if tag_id:
|
if tag_id:
|
||||||
queryset = queryset.filter(tags__id=tag_id)
|
queryset = queryset.filter(tags__id=tag_id)
|
||||||
if in_stock_only:
|
if in_stock_only:
|
||||||
queryset = queryset.filter(in_stock=True)
|
queryset = queryset.filter(in_stock=True)
|
||||||
if warehouse_id:
|
if warehouse_id and not skip_stock_filter:
|
||||||
# Фильтруем только товары, которые есть на указанном складе с доступным количеством
|
# Фильтруем только товары, которые есть на указанном складе с доступным количеством
|
||||||
|
# НЕ применяется при skip_stock_filter=True (приёмка товаров)
|
||||||
from inventory.models import Stock
|
from inventory.models import Stock
|
||||||
products_with_stock = Stock.objects.filter(
|
products_with_stock = Stock.objects.filter(
|
||||||
warehouse_id=warehouse_id,
|
warehouse_id=warehouse_id,
|
||||||
@@ -186,6 +192,7 @@ def search_products_and_variants(request):
|
|||||||
tag_id = request.GET.get('tag', '').strip()
|
tag_id = request.GET.get('tag', '').strip()
|
||||||
in_stock_only = request.GET.get('in_stock', '').lower() == 'true'
|
in_stock_only = request.GET.get('in_stock', '').lower() == 'true'
|
||||||
warehouse_id = request.GET.get('warehouse', '').strip()
|
warehouse_id = request.GET.get('warehouse', '').strip()
|
||||||
|
skip_stock_filter = request.GET.get('skip_stock_filter', '').lower() == 'true'
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
@@ -208,7 +215,7 @@ def search_products_and_variants(request):
|
|||||||
# Показываем последние добавленные активные товары
|
# Показываем последние добавленные активные товары
|
||||||
products_qs = Product.objects.filter(status='active').prefetch_related('sales_units__unit')
|
products_qs = Product.objects.filter(status='active').prefetch_related('sales_units__unit')
|
||||||
# Применяем фильтры
|
# Применяем фильтры
|
||||||
products_qs = _apply_product_filters(products_qs, category_id, tag_id, in_stock_only, warehouse_id)
|
products_qs = _apply_product_filters(products_qs, category_id, tag_id, in_stock_only, warehouse_id, skip_stock_filter)
|
||||||
products = products_qs.order_by('-created_at')[:page_size]
|
products = products_qs.order_by('-created_at')[:page_size]
|
||||||
|
|
||||||
for product in products:
|
for product in products:
|
||||||
@@ -352,7 +359,7 @@ def search_products_and_variants(request):
|
|||||||
).order_by('-relevance', 'name')
|
).order_by('-relevance', 'name')
|
||||||
|
|
||||||
# Применяем дополнительные фильтры
|
# Применяем дополнительные фильтры
|
||||||
products_query = _apply_product_filters(products_query, category_id, tag_id, in_stock_only, warehouse_id)
|
products_query = _apply_product_filters(products_query, category_id, tag_id, in_stock_only, warehouse_id, skip_stock_filter)
|
||||||
|
|
||||||
# Добавляем prefetch для единиц продажи
|
# Добавляем prefetch для единиц продажи
|
||||||
products_query = products_query.prefetch_related('sales_units__unit')
|
products_query = products_query.prefetch_related('sales_units__unit')
|
||||||
|
|||||||
Reference in New Issue
Block a user