Исправлен поиск товаров в форме массового поступления

Проблема:
- На странице /inventory/incoming/create/ не работал поиск товаров
- Использовался обычный <select> с предзагруженным списком всех товаров
- При большом количестве товаров список был неудобным
- Невозможно было искать товары по названию в реальном времени

Решение:
- Заменён обычный <select> на Select2 с AJAX автокомплитом
- Подключен API endpoint /products/api/search-products-variants/
- Поиск товаров работает в реальном времени (с задержкой 250ms)
- Минимальная длина поиска: 0 символов (можно открыть весь список)
- Поддержка русского языка
- Theme: bootstrap-5 для визуального соответствия

Изменения:
- Удалён предзагруженный список товаров из контекста шаблона
- Добавлена инициализация Select2 для каждой новой строки товара
- При удалении строки вызывается select2('destroy') для очистки
- Исправлена логика восстановления товаров при ошибке валидации
- Используется Option API для программной установки значений

Технические детали:
- jQuery и Select2 уже подключены в base.html
- Не дублируем подключение библиотек
- Используем событие 'change' для Select2 вместо 'input'
- Кэширование AJAX запросов включено

Теперь поиск товаров работает корректно! 🎉
This commit is contained in:
2025-12-01 10:29:57 +03:00
parent 4597ddbd87
commit dc39f56b9a

View File

@@ -168,14 +168,6 @@ document.addEventListener('DOMContentLoaded', function() {
const productsJsonInput = document.getElementById('productsJson');
const submitBtn = document.getElementById('submitBtn');
// Список всех доступных товаров (преобразуем QuerySet в JSON)
const products = [
{% for product in products %}
{ id: {{ product.id }}, name: "{{ product.name }}" },
{% endfor %}
];
const productOptions = products.map(p => `<option value="${p.id}">${p.name}</option>`).join('');
let rowCounter = 0;
// Добавление новой строки товара
@@ -193,8 +185,7 @@ document.addEventListener('DOMContentLoaded', function() {
row.innerHTML = `
<td>
<select class="form-control form-control-sm product-select" data-row-id="${rowId}">
<option value="">Выберите товар...</option>
${productOptions}
<option value="">Начните вводить название товара...</option>
</select>
<div class="error-message" style="display:none;"></div>
</td>
@@ -221,15 +212,49 @@ document.addEventListener('DOMContentLoaded', function() {
productsBody.appendChild(row);
// Инициализируем Select2 для нового селекта товара
const productSelect = row.querySelector('.product-select');
$(productSelect).select2({
theme: 'bootstrap-5',
placeholder: 'Начните вводить название товара...',
allowClear: true,
width: '100%',
language: 'ru',
minimumInputLength: 0,
ajax: {
url: '/products/api/search-products-variants/',
dataType: 'json',
delay: 250,
data: function (params) {
return {
q: params.term || '',
type: 'product',
page: params.page || 1
};
},
processResults: function (data) {
return {
results: data.results,
pagination: {
more: data.pagination.more
}
};
},
cache: true
}
});
// Добавляем event listeners для новой строки
const quantityInput = row.querySelector('.quantity-input');
const priceInput = row.querySelector('.price-input');
const removeBtn = row.querySelector('.btn-remove-row');
$(productSelect).on('change', updateTotals);
quantityInput.addEventListener('input', updateTotals);
priceInput.addEventListener('input', updateTotals);
removeBtn.addEventListener('click', function(e) {
e.preventDefault();
$(productSelect).select2('destroy');
row.remove();
updateTotals();
});
@@ -298,15 +323,16 @@ document.addEventListener('DOMContentLoaded', function() {
// Добавляем восстановленные товары
savedProducts.forEach(item => {
const product = products.find(p => p.id === item.product_id);
if (product) {
addProductRow();
const lastRow = productsBody.querySelector('tr:last-child');
addProductRow();
const lastRow = productsBody.querySelector('tr:last-child');
const lastSelect = lastRow.querySelector('.product-select');
lastRow.querySelector('.product-select').value = item.product_id;
lastRow.querySelector('.quantity-input').value = item.quantity;
lastRow.querySelector('.price-input').value = item.cost_price;
}
// Создаём option и устанавливаем его в Select2
const newOption = new Option(item.product_name || `Товар #${item.product_id}`, item.product_id, true, true);
$(lastSelect).append(newOption).trigger('change');
lastRow.querySelector('.quantity-input').value = item.quantity;
lastRow.querySelector('.price-input').value = item.cost_price;
});
// Обновляем итоги