+ {% include 'products/components/product_search_picker.html' with container_id='writeoff-document-picker' title='Поиск товара для списания' warehouse_id=document.warehouse.id filter_in_stock_only=True categories=categories tags=tags add_button_text='Выбрать товар' multi_select=False show_select_all=False content_height='300px' %}
+
+
+
+
+
{% endblock %}
diff --git a/myproject/inventory/views/writeoff_document.py b/myproject/inventory/views/writeoff_document.py
index bab5ead..0e1886b 100644
--- a/myproject/inventory/views/writeoff_document.py
+++ b/myproject/inventory/views/writeoff_document.py
@@ -60,6 +60,12 @@ class WriteOffDocumentDetailView(LoginRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['item_form'] = WriteOffDocumentItemForm(document=self.object)
+
+ # Добавляем категории и теги для компонента поиска товаров
+ from products.models import ProductCategory, ProductTag
+ context['categories'] = ProductCategory.objects.filter(is_active=True).order_by('name')
+ context['tags'] = ProductTag.objects.filter(is_active=True).order_by('name')
+
return context
diff --git a/myproject/products/static/products/js/product-search-picker.js b/myproject/products/static/products/js/product-search-picker.js
index fefc274..b64dbcf 100644
--- a/myproject/products/static/products/js/product-search-picker.js
+++ b/myproject/products/static/products/js/product-search-picker.js
@@ -64,7 +64,8 @@
search: '',
category: '',
tag: '',
- inStock: false
+ inStock: false,
+ warehouse: '' // ID склада для фильтрации
}
};
@@ -106,6 +107,11 @@
this.state.currentView = initialView;
this._updateViewButtons();
}
+
+ // Инициализация warehouse из data-атрибута
+ if (this.container.dataset.warehouseId) {
+ this.state.filters.warehouse = this.container.dataset.warehouseId;
+ }
};
/**
@@ -278,6 +284,9 @@
if (this.state.filters.inStock) {
params.append('in_stock', 'true');
}
+ if (this.state.filters.warehouse) {
+ params.append('warehouse', this.state.filters.warehouse);
+ }
fetch(this.options.apiUrl + '?' + params.toString())
.then(function(response) {
diff --git a/myproject/products/templates/products/components/product_search_picker.html b/myproject/products/templates/products/components/product_search_picker.html
index 6a3c096..5756c91 100644
--- a/myproject/products/templates/products/components/product_search_picker.html
+++ b/myproject/products/templates/products/components/product_search_picker.html
@@ -14,6 +14,7 @@
- multi_select: множественный выбор (default: True)
- max_selection: максимальное количество выбранных товаров (default: null)
- filter_in_stock_only: показывать только товары в наличии (default: False)
+- warehouse_id: ID склада для фильтрации товаров (default: None)
- categories: список категорий для фильтра (queryset или list)
- tags: список тегов для фильтра (queryset или list)
- content_height: высота контейнера с товарами (default: '400px')
@@ -46,7 +47,8 @@ ProductSearchPicker.init('#writeoff-products', {
data-api-url="{{ api_url|default:'/products/api/search-products-variants/' }}"
data-multi-select="{{ multi_select|default:'true' }}"
data-max-selection="{{ max_selection|default:'' }}"
- data-exclude-kits="true">
+ data-exclude-kits="true"
+ {% if warehouse_id %}data-warehouse-id="{{ warehouse_id }}"{% endif %}>
diff --git a/myproject/products/views/api_views.py b/myproject/products/views/api_views.py
index dd6b754..c344397 100644
--- a/myproject/products/views/api_views.py
+++ b/myproject/products/views/api_views.py
@@ -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