feat(products): улучшить интерфейс массовой синхронизации с Recommerce
- Добавить секцию маркетинговых флагов в модалку синхронизации - Добавить кнопки "Выбрать все" для групп полей - Улучшить UX отображения списка товаров Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
// DOM elements
|
||||
const selectAllCheckbox = document.getElementById('select-all-checkbox');
|
||||
const batchActionsBtn = document.getElementById('batch-actions-btn');
|
||||
const batchActionsDropdown = document.getElementById('batch-actions-dropdown');
|
||||
const batchActionsWrapper = document.getElementById('batch-actions-wrapper');
|
||||
let selectionCountSpan = document.getElementById('selection-count');
|
||||
|
||||
/**
|
||||
@@ -138,17 +138,23 @@
|
||||
const shouldEnable = count > 0;
|
||||
if (batchActionsBtn) {
|
||||
batchActionsBtn.disabled = !shouldEnable;
|
||||
|
||||
|
||||
// Управляем подсказкой через data-атрибут
|
||||
if (batchActionsWrapper) {
|
||||
if (shouldEnable) {
|
||||
batchActionsWrapper.removeAttribute('data-hint');
|
||||
} else {
|
||||
batchActionsWrapper.setAttribute('data-hint', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
// Если в кнопке нет span#selection-count, значит текст был изменён - восстанавливаем
|
||||
if (!batchActionsBtn.querySelector('#selection-count')) {
|
||||
batchActionsBtn.innerHTML = `<i class="bi bi-gear-fill"></i> Действия над выбранными (<span id="selection-count">${count}</span>)`;
|
||||
selectionCountSpan = document.getElementById('selection-count');
|
||||
}
|
||||
}
|
||||
if (batchActionsDropdown) {
|
||||
batchActionsDropdown.disabled = !shouldEnable;
|
||||
}
|
||||
|
||||
|
||||
// Показываем/скрываем dropdown для выбора всех
|
||||
const selectAllDropdown = document.getElementById('select-all-dropdown-group');
|
||||
if (selectAllDropdown) {
|
||||
|
||||
@@ -62,6 +62,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
if (document.getElementById('syncContent').checked) options.fields.push('content');
|
||||
if (document.getElementById('syncImages').checked) options.fields.push('images');
|
||||
|
||||
// Маркетинговые флаги
|
||||
if (document.getElementById('syncIsNew')?.checked) options.fields.push('is_new');
|
||||
if (document.getElementById('syncIsPopular')?.checked) options.fields.push('is_popular');
|
||||
if (document.getElementById('syncIsSpecial')?.checked) options.fields.push('is_special');
|
||||
|
||||
// Блокируем кнопку
|
||||
startBtn.disabled = true;
|
||||
const originalText = startBtn.innerHTML;
|
||||
@@ -125,4 +130,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
// Кнопки "Выбрать все" для групп полей
|
||||
document.getElementById('toggleBasicFields')?.addEventListener('click', function() {
|
||||
const check = !this.dataset.allSelected || this.dataset.allSelected === 'false';
|
||||
this.dataset.allSelected = check;
|
||||
this.textContent = check ? 'Снять все' : 'Выбрать все';
|
||||
document.getElementById('syncPrice').checked = check;
|
||||
document.getElementById('syncStock').checked = check;
|
||||
document.getElementById('syncContent').checked = check;
|
||||
document.getElementById('syncImages').checked = check;
|
||||
});
|
||||
|
||||
document.getElementById('toggleMarketingFields')?.addEventListener('click', function() {
|
||||
const check = !this.dataset.allSelected || this.dataset.allSelected === 'false';
|
||||
this.dataset.allSelected = check;
|
||||
this.textContent = check ? 'Снять все' : 'Выбрать все';
|
||||
document.getElementById('syncIsNew').checked = check;
|
||||
document.getElementById('syncIsPopular').checked = check;
|
||||
document.getElementById('syncIsSpecial').checked = check;
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- Модальное окно для синхронизации с Recommerce -->
|
||||
<div class="modal fade" id="recommerceSyncModal" tabindex="-1" aria-labelledby="recommerceSyncModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="recommerceSyncModalLabel">
|
||||
@@ -9,52 +9,99 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info mb-3">
|
||||
<div class="alert alert-info mb-4">
|
||||
<i class="bi bi-info-circle"></i> <strong>Выбрано товаров:</strong> <span id="recommerceSyncCount">0</span>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">Что обновлять?</label>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="price" id="syncPrice" checked>
|
||||
<label class="form-check-label" for="syncPrice">
|
||||
Цены
|
||||
</label>
|
||||
<!-- Основные данные -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header py-2 d-flex justify-content-between align-items-center">
|
||||
<strong><i class="bi bi-box-seam"></i> Основные данные</strong>
|
||||
<button type="button" class="btn btn-sm btn-link p-0" id="toggleBasicFields">Выбрать все</button>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="count" id="syncStock" checked>
|
||||
<label class="form-check-label" for="syncStock">
|
||||
Остатки
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="content" id="syncContent">
|
||||
<label class="form-check-label" for="syncContent">
|
||||
Название и описание
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="images" id="syncImages">
|
||||
<label class="form-check-label" for="syncImages">
|
||||
Изображения
|
||||
</label>
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="price" id="syncPrice" checked>
|
||||
<label class="form-check-label" for="syncPrice">
|
||||
<i class="bi bi-tag"></i> Цены
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="count" id="syncStock">
|
||||
<label class="form-check-label" for="syncStock">
|
||||
<i class="bi bi-stack"></i> Остатки
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="content" id="syncContent">
|
||||
<label class="form-check-label" for="syncContent">
|
||||
<i class="bi bi-card-text"></i> Название и описание
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="images" id="syncImages">
|
||||
<label class="form-check-label" for="syncImages">
|
||||
<i class="bi bi-images"></i> Изображения
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<!-- Маркетинговые флаги -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header py-2 d-flex justify-content-between align-items-center">
|
||||
<strong><i class="bi bi-megaphone"></i> Маркетинговые флаги</strong>
|
||||
<button type="button" class="btn btn-sm btn-link p-0" id="toggleMarketingFields">Выбрать все</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="is_new" id="syncIsNew">
|
||||
<label class="form-check-label" for="syncIsNew">
|
||||
<span class="badge bg-warning text-dark me-1"><i class="bi bi-stars"></i></span> Новинки
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="is_popular" id="syncIsPopular">
|
||||
<label class="form-check-label" for="syncIsPopular">
|
||||
<span class="badge bg-danger me-1"><i class="bi bi-fire"></i></span> Популярные
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="is_special" id="syncIsSpecial">
|
||||
<label class="form-check-label" for="syncIsSpecial">
|
||||
<span class="badge bg-success me-1"><i class="bi bi-percent"></i></span> Спецпредложения
|
||||
</label>
|
||||
<div class="form-text text-muted small">Также авто при скидке</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="syncCreateNew">
|
||||
<label class="form-check-label" for="syncCreateNew">
|
||||
Создавать товары, если не найдены
|
||||
</label>
|
||||
<div class="form-text text-muted">
|
||||
Если товар отсутствует в Recommerce, он будет создан (требуется полное заполнение).
|
||||
<!-- Дополнительно -->
|
||||
<div class="card">
|
||||
<div class="card-body py-2">
|
||||
<div class="form-check form-switch mb-0">
|
||||
<input class="form-check-input" type="checkbox" id="syncCreateNew">
|
||||
<label class="form-check-label" for="syncCreateNew">
|
||||
<strong>Создавать товары, если не найдены в Recommerce</strong>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,9 +109,9 @@
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
<button type="button" class="btn btn-primary" id="startRecommerceSyncBtn">
|
||||
<i class="bi bi-play-fill"></i> Запустить
|
||||
<i class="bi bi-play-fill"></i> Запустить синхронизацию
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,30 +37,30 @@
|
||||
<hr class="my-3">
|
||||
|
||||
<form method="get" id="filterForm">
|
||||
<div class="row g-3">
|
||||
<div class="row g-2">
|
||||
<!-- Поиск -->
|
||||
<div class="col-12 col-md-4">
|
||||
<label for="search" class="form-label"><i class="bi bi-search"></i> Поиск</label>
|
||||
<input type="text" class="form-control" id="search" name="search"
|
||||
placeholder="Название, артикул, описание..."
|
||||
<label for="search" class="form-label small mb-1">Поиск</label>
|
||||
<input type="text" class="form-control form-control-sm" id="search" name="search"
|
||||
placeholder="Название, артикул..."
|
||||
value="{{ filters.current.search|default:'' }}">
|
||||
</div>
|
||||
|
||||
<!-- Тип -->
|
||||
<div class="col-12 col-md-2">
|
||||
<label for="type" class="form-label"><i class="bi bi-box"></i> Тип</label>
|
||||
<select class="form-select" id="type" name="type">
|
||||
<div class="col-6 col-md-1">
|
||||
<label for="type" class="form-label small mb-1">Тип</label>
|
||||
<select class="form-select form-select-sm" id="type" name="type">
|
||||
<option value="all" {% if filters.current.type == 'all' %}selected{% endif %}>Все</option>
|
||||
<option value="products" {% if filters.current.type == 'products' %}selected{% endif %}>Только товары</option>
|
||||
<option value="kits" {% if filters.current.type == 'kits' %}selected{% endif %}>Только комплекты</option>
|
||||
<option value="products" {% if filters.current.type == 'products' %}selected{% endif %}>Товары</option>
|
||||
<option value="kits" {% if filters.current.type == 'kits' %}selected{% endif %}>Комплекты</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Категория -->
|
||||
<div class="col-12 col-md-3">
|
||||
<label for="category" class="form-label"><i class="bi bi-bookmark"></i> Категория</label>
|
||||
<select class="form-select" id="category" name="category">
|
||||
<option value="">Все категории</option>
|
||||
<div class="col-6 col-md-2">
|
||||
<label for="category" class="form-label small mb-1">Категория</label>
|
||||
<select class="form-select form-select-sm" id="category" name="category">
|
||||
<option value="">Все</option>
|
||||
{% for category in filters.categories %}
|
||||
<option value="{{ category.id }}" {% if filters.current.category == category.id|stringformat:"s" %}selected{% endif %}>
|
||||
{{ category.name }}
|
||||
@@ -70,10 +70,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Статус -->
|
||||
<div class="col-12 col-md-3">
|
||||
<label for="status" class="form-label"><i class="bi bi-toggle-on"></i> Статус</label>
|
||||
<select class="form-select" id="status" name="status">
|
||||
<option value="">Все статусы</option>
|
||||
<div class="col-6 col-md-1">
|
||||
<label for="status" class="form-label small mb-1">Статус</label>
|
||||
<select class="form-select form-select-sm" id="status" name="status">
|
||||
<option value="">Все</option>
|
||||
{% for status_value, status_name in item_statuses %}
|
||||
<option value="{{ status_value }}" {% if filters.current.status == status_value %}selected{% endif %}>
|
||||
{{ status_name }}
|
||||
@@ -81,52 +81,101 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Со скидкой -->
|
||||
<div class="col-6 col-md-1">
|
||||
<label class="form-label small mb-1">Скидка</label>
|
||||
<select class="form-select form-select-sm" id="has_discount" name="has_discount">
|
||||
<option value="">—</option>
|
||||
<option value="1" {% if filters.current.has_discount == '1' %}selected{% endif %}>Да</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Маркетинг -->
|
||||
<div class="col-12 col-md-3">
|
||||
<label class="form-label small mb-1">Маркетинг</label>
|
||||
<div class="btn-group w-100 d-flex" role="group" style="flex-wrap: wrap;">
|
||||
<input type="checkbox" class="btn-check" id="is_new" name="is_new" value="1"
|
||||
{% if filters.current.is_new == '1' %}checked{% endif %}
|
||||
onchange="document.getElementById('filterForm').submit()">
|
||||
<label class="btn btn-outline-warning btn-sm flex-fill" for="is_new" title="Новинки"
|
||||
style="white-space: normal; text-align: center; font-size: 0.75rem;">
|
||||
<i class="bi bi-stars d-block"></i> Новинки
|
||||
</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" id="is_popular" name="is_popular" value="1"
|
||||
{% if filters.current.is_popular == '1' %}checked{% endif %}
|
||||
onchange="document.getElementById('filterForm').submit()">
|
||||
<label class="btn btn-outline-danger btn-sm flex-fill" for="is_popular" title="Популярные"
|
||||
style="white-space: normal; text-align: center; font-size: 0.75rem;">
|
||||
<i class="bi bi-fire d-block"></i> Популярные
|
||||
</label>
|
||||
|
||||
<input type="checkbox" class="btn-check" id="is_special" name="is_special" value="1"
|
||||
{% if filters.current.is_special == '1' %}checked{% endif %}
|
||||
onchange="document.getElementById('filterForm').submit()">
|
||||
<label class="btn btn-outline-success btn-sm flex-fill" for="is_special" title="Акции"
|
||||
style="white-space: normal; text-align: center; font-size: 0.75rem;">
|
||||
<i class="bi bi-percent d-block"></i> Акции
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3 mt-2">
|
||||
<!-- В наличии (только для товаров) -->
|
||||
<div class="col-12 col-md-3">
|
||||
<label for="in_stock" class="form-label"><i class="bi bi-check-circle"></i> В наличии</label>
|
||||
<select class="form-select" id="in_stock" name="in_stock">
|
||||
<option value="">Все</option>
|
||||
<div class="row g-2">
|
||||
<!-- Цена -->
|
||||
<div class="col-12 col-md-6">
|
||||
<label class="form-label small mb-1">Цена</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="number" class="form-control" id="price_from" name="price_from" placeholder="От"
|
||||
value="{{ filters.current.price_from|default:'' }}" min="0" step="0.01">
|
||||
<span class="input-group-text">—</span>
|
||||
<input type="number" class="form-control" id="price_to" name="price_to" placeholder="До"
|
||||
value="{{ filters.current.price_to|default:'' }}" min="0" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- В наличии -->
|
||||
<div class="col-4 col-md-1">
|
||||
<label for="in_stock" class="form-label small mb-1">Наличие</label>
|
||||
<select class="form-select form-select-sm" id="in_stock" name="in_stock">
|
||||
<option value="">—</option>
|
||||
<option value="1" {% if filters.current.in_stock == '1' %}selected{% endif %}>Да</option>
|
||||
<option value="0" {% if filters.current.in_stock == '0' %}selected{% endif %}>Нет</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Теги -->
|
||||
<div class="col-12 col-md-3">
|
||||
<label for="tags" class="form-label"><i class="bi bi-tags"></i> Теги</label>
|
||||
<select class="form-select" id="tags" name="tags" multiple size="1">
|
||||
<div class="col-4 col-md-2">
|
||||
<label for="tags" class="form-label small mb-1">Теги</label>
|
||||
<select class="form-select form-select-sm" id="tags" name="tags" multiple size="1">
|
||||
{% for tag in filters.tags %}
|
||||
<option value="{{ tag.id }}" {% if tag.id in filters.current.tags %}selected{% endif %}>
|
||||
{{ tag.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% if filters.current.tags %}
|
||||
<small class="text-muted">Выбрано: {{ filters.current.tags|length }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Показывать по -->
|
||||
<div class="col-12 col-md-2">
|
||||
<label for="per_page" class="form-label"><i class="bi bi-list-ol"></i> Показывать по:</label>
|
||||
<select class="form-select" id="per_page" name="per_page" onchange="this.form.submit()">
|
||||
<!-- per_page -->
|
||||
<div class="col-4 col-md-1">
|
||||
<label for="per_page" class="form-label small mb-1">На стр.</label>
|
||||
<select class="form-select form-select-sm" id="per_page" name="per_page" onchange="this.form.submit()">
|
||||
<option value="20" {% if filters.current.per_page == '20' %}selected{% endif %}>20</option>
|
||||
<option value="50" {% if filters.current.per_page == '50' %}selected{% endif %}>50</option>
|
||||
<option value="100" {% if filters.current.per_page == '100' %}selected{% endif %}>100</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<label class="form-label d-none d-md-block"> </label>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-circle"></i> Применить
|
||||
<!-- Кнопки -->
|
||||
<div class="col-12 col-md-2">
|
||||
<label class="form-label small mb-1 d-none d-md-block"> </label>
|
||||
<div class="d-flex gap-1">
|
||||
<button type="submit" class="btn btn-primary btn-sm flex-fill">
|
||||
OK
|
||||
</button>
|
||||
<a href="{% url 'products:products-list' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-x-circle"></i> Сбросить
|
||||
<a href="{% url 'products:products-list' %}" class="btn btn-outline-secondary btn-sm">
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -175,15 +224,13 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-outline-secondary" id="batch-actions-btn" disabled>
|
||||
<div class="dropdown d-flex align-items-center gap-2" id="batch-actions-wrapper" style="position: relative;">
|
||||
<button type="button" class="btn btn-light dropdown-toggle border" id="batch-actions-btn" disabled
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-gear-fill"></i> Действия над выбранными (<span id="selection-count">0</span>)
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split"
|
||||
id="batch-actions-dropdown" data-bs-toggle="dropdown" aria-expanded="false" disabled>
|
||||
<span class="visually-hidden">Открыть меню</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="batch-actions-dropdown">
|
||||
<span class="badge bg-secondary" id="batch-actions-hint" style="position: absolute; top: 100%; left: 0; margin-top: 4px; z-index: 10; white-space: nowrap; display: none;">Сначала выберите товары</span>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="batch-actions-btn">
|
||||
<li>
|
||||
<a class="dropdown-item" href="#" id="bulk-category-action">
|
||||
<i class="bi bi-bookmark-fill"></i> Изменить категории
|
||||
@@ -495,11 +542,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#batch-actions-wrapper[data-hint="true"]:hover #batch-actions-hint {
|
||||
display: inline-block !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{% load static %}
|
||||
<script src="{% static 'products/js/batch-selection.js' %}?v=1.2"></script>
|
||||
<script src="{% static 'products/js/batch-selection.js' %}?v=1.5"></script>
|
||||
<script src="{% static 'products/js/bulk-category-modal.js' %}?v=1.6"></script>
|
||||
<script src="{% static 'products/js/recommerce-sync.js' %}?v=1.1"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -343,6 +343,42 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
|
||||
products = products.filter(tags__id__in=tags).distinct()
|
||||
kits = kits.filter(tags__id__in=tags).distinct()
|
||||
|
||||
# Фильтр по цене
|
||||
price_from = self.request.GET.get('price_from')
|
||||
price_to = self.request.GET.get('price_to')
|
||||
if price_from:
|
||||
products = products.filter(
|
||||
Q(sale_price__gte=price_from) | Q(price__gte=price_from)
|
||||
).distinct()
|
||||
kits = kits.filter(
|
||||
Q(sale_price__gte=price_from) | Q(price__gte=price_from)
|
||||
).distinct()
|
||||
if price_to:
|
||||
products = products.filter(
|
||||
Q(sale_price__lte=price_to) | Q(price__lte=price_to)
|
||||
).distinct()
|
||||
kits = kits.filter(
|
||||
Q(sale_price__lte=price_to) | Q(price__lte=price_to)
|
||||
).distinct()
|
||||
|
||||
# Маркетинговые фильтры (OR логика — объединяются через Q)
|
||||
marketing_filters = Q()
|
||||
if self.request.GET.get('is_new') == '1':
|
||||
marketing_filters |= Q(is_new=True)
|
||||
if self.request.GET.get('is_popular') == '1':
|
||||
marketing_filters |= Q(is_popular=True)
|
||||
if self.request.GET.get('is_special') == '1':
|
||||
marketing_filters |= Q(is_special=True)
|
||||
if marketing_filters:
|
||||
products = products.filter(marketing_filters)
|
||||
kits = kits.filter(marketing_filters)
|
||||
|
||||
# Фильтр по скидке
|
||||
has_discount = self.request.GET.get('has_discount')
|
||||
if has_discount == '1':
|
||||
products = products.filter(sale_price__gt=0)
|
||||
kits = kits.filter(sale_price__gt=0)
|
||||
|
||||
# Применяем фильтр по типу
|
||||
products_list = []
|
||||
kits_list = []
|
||||
@@ -387,6 +423,12 @@ class CombinedProductListView(LoginRequiredMixin, ManagerOwnerRequiredMixin, Lis
|
||||
'in_stock': self.request.GET.get('in_stock', ''),
|
||||
'tags': [int(tag) for tag in self.request.GET.getlist('tags') if tag.isdigit()],
|
||||
'per_page': self.request.GET.get('per_page', '20'),
|
||||
'price_from': self.request.GET.get('price_from', ''),
|
||||
'price_to': self.request.GET.get('price_to', ''),
|
||||
'is_new': self.request.GET.get('is_new', ''),
|
||||
'is_popular': self.request.GET.get('is_popular', ''),
|
||||
'is_special': self.request.GET.get('is_special', ''),
|
||||
'has_discount': self.request.GET.get('has_discount', ''),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user