Замена простого select на autocomplete с поиском для привязки атрибутов к товарам/комплектам
- Переиспользован модуль select2-product-search.js из orders - Заменен простой select на Select2 с AJAX поиском через API search_products_and_variants - Добавлена поддержка привязки как ProductKit, так и Product к значениям атрибутов - Обновлен метод _save_attributes_from_cards для обработки item_ids и item_types - Удалены дублирующиеся подключения jQuery и Select2 (используются из base.html) - Улучшен UX: живой поиск, отображение типа товара (🌹/💐), цены и наличия
This commit is contained in:
@@ -29,6 +29,30 @@ input[name*="DELETE"] {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Стили для autocomplete товаров/комплектов */
|
||||||
|
.product-kit-select-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Отображение типа товара в Select2 */
|
||||||
|
.select2-results__option .item-type-badge {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
padding: 0.1rem 0.4rem;
|
||||||
|
margin-left: 0.3rem;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-type-kit {
|
||||||
|
background-color: #0d6efd;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-type-product {
|
||||||
|
background-color: #198754;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -108,12 +132,6 @@ input[name*="DELETE"] {
|
|||||||
|
|
||||||
<!-- Данные для JavaScript -->
|
<!-- Данные для JavaScript -->
|
||||||
<script>
|
<script>
|
||||||
window.AVAILABLE_KITS = [
|
|
||||||
{% for kit in available_kits %}
|
|
||||||
{ id: {{ kit.id }}, name: "{{ kit.name|escapejs }}" }{% if not forloop.last %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
];
|
|
||||||
|
|
||||||
// Справочник атрибутов с их значениями
|
// Справочник атрибутов с их значениями
|
||||||
window.PRODUCT_ATTRIBUTES = [
|
window.PRODUCT_ATTRIBUTES = [
|
||||||
{% for attr in product_attributes %}
|
{% for attr in product_attributes %}
|
||||||
@@ -133,7 +151,8 @@ input[name*="DELETE"] {
|
|||||||
// URL для API
|
// URL для API
|
||||||
window.API_URLS = {
|
window.API_URLS = {
|
||||||
createAttribute: "{% url 'products:api-attribute-create' %}",
|
createAttribute: "{% url 'products:api-attribute-create' %}",
|
||||||
addValue: function(attrId) { return `/products/api/attributes/${attrId}/values/add/`; }
|
addValue: function(attrId) { return `/products/api/attributes/${attrId}/values/add/`; },
|
||||||
|
searchProductsAndVariants: "{% url 'products:api-search-products-variants' %}"
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -266,16 +285,17 @@ input[name*="DELETE"] {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Переиспользуемый модуль для Select2 поиска товаров -->
|
||||||
|
<script src="{% static 'products/js/select2-product-search.js' %}"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// === Управление параметрами товара (карточный интерфейс) ===
|
// === Управление параметрами товара (карточный интерфейс) ===
|
||||||
|
|
||||||
// Функция для добавления нового поля значения параметра с выбором ProductKit
|
// Функция для добавления нового поля значения параметра с выбором Product/Kit через Select2
|
||||||
function addValueField(container, valueText = '', kitId = '') {
|
function addValueField(container, valueText = '', itemId = '', itemType = '') {
|
||||||
const index = container.querySelectorAll('.value-field-group').length;
|
const index = container.querySelectorAll('.value-field-group').length;
|
||||||
const fieldId = `value-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
const fieldId = `value-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
const selectId = `product-kit-select-${fieldId}`;
|
||||||
// Получаем список доступных комплектов
|
|
||||||
const kitOptionsHtml = getKitOptionsHtml(kitId);
|
|
||||||
|
|
||||||
const html = `
|
const html = `
|
||||||
<div class="value-field-group d-flex gap-2 mb-2 align-items-start">
|
<div class="value-field-group d-flex gap-2 mb-2 align-items-start">
|
||||||
@@ -283,13 +303,13 @@ function addValueField(container, valueText = '', kitId = '') {
|
|||||||
placeholder="Введите значение"
|
placeholder="Введите значение"
|
||||||
value="${escapeHtml(valueText)}"
|
value="${escapeHtml(valueText)}"
|
||||||
data-field-id="${fieldId}"
|
data-field-id="${fieldId}"
|
||||||
style="min-width: 100px;">
|
style="flex: 0 0 150px;">
|
||||||
<select class="form-select form-select-sm parameter-kit-select"
|
<select class="form-select form-select-sm product-kit-select"
|
||||||
|
id="${selectId}"
|
||||||
data-field-id="${fieldId}"
|
data-field-id="${fieldId}"
|
||||||
title="Выберите комплект для этого значения"
|
data-ajax-url="${window.API_URLS.searchProductsAndVariants}"
|
||||||
style="min-width: 150px;">
|
style="flex: 1; min-width: 200px;">
|
||||||
<option value="">-- Выберите комплект --</option>
|
<option value=""></option>
|
||||||
${kitOptionsHtml}
|
|
||||||
</select>
|
</select>
|
||||||
<button type="button" class="btn btn-sm btn-outline-danger remove-value-btn" title="Удалить значение">
|
<button type="button" class="btn btn-sm btn-outline-danger remove-value-btn" title="Удалить значение">
|
||||||
<i class="bi bi-trash"></i>
|
<i class="bi bi-trash"></i>
|
||||||
@@ -299,12 +319,22 @@ function addValueField(container, valueText = '', kitId = '') {
|
|||||||
|
|
||||||
container.insertAdjacentHTML('beforeend', html);
|
container.insertAdjacentHTML('beforeend', html);
|
||||||
|
|
||||||
// Установка выбранного комплекта если был передан
|
// Инициализируем Select2 для нового поля
|
||||||
if (kitId) {
|
const newSelect = document.getElementById(selectId);
|
||||||
const lastSelect = container.querySelector('.value-field-group:last-child .parameter-kit-select');
|
if (newSelect) {
|
||||||
if (lastSelect) {
|
// Если есть предзагруженные данные, добавляем option
|
||||||
lastSelect.value = kitId;
|
if (itemId && itemType) {
|
||||||
|
const optionValue = `${itemType}_${itemId}`;
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = optionValue;
|
||||||
|
option.selected = true;
|
||||||
|
option.setAttribute('data-type', itemType);
|
||||||
|
// Текст будет установлен через Select2
|
||||||
|
newSelect.appendChild(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Инициализируем Select2 с AJAX поиском
|
||||||
|
window.initProductSelect2(newSelect, 'all', window.API_URLS.searchProductsAndVariants);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработчик удаления значения
|
// Обработчик удаления значения
|
||||||
@@ -312,6 +342,11 @@ function addValueField(container, valueText = '', kitId = '') {
|
|||||||
if (lastRemoveBtn) {
|
if (lastRemoveBtn) {
|
||||||
lastRemoveBtn.addEventListener('click', function(e) {
|
lastRemoveBtn.addEventListener('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
// Уничтожаем Select2 перед удалением элемента
|
||||||
|
const select = this.closest('.value-field-group').querySelector('.product-kit-select');
|
||||||
|
if (select && $(select).data('select2')) {
|
||||||
|
$(select).select2('destroy');
|
||||||
|
}
|
||||||
this.closest('.value-field-group').remove();
|
this.closest('.value-field-group').remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -324,15 +359,6 @@ function escapeHtml(text) {
|
|||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получить HTML с опциями комплектов
|
|
||||||
function getKitOptionsHtml(selectedKitId = '') {
|
|
||||||
const kitsData = window.AVAILABLE_KITS || [];
|
|
||||||
return kitsData.map(kit => {
|
|
||||||
const selected = kit.id == selectedKitId ? 'selected' : '';
|
|
||||||
return `<option value="${kit.id}" ${selected}>${escapeHtml(kit.name)}</option>`;
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Найти атрибут в справочнике по имени
|
// Найти атрибут в справочнике по имени
|
||||||
function findAttributeByName(name) {
|
function findAttributeByName(name) {
|
||||||
const attributes = window.PRODUCT_ATTRIBUTES || [];
|
const attributes = window.PRODUCT_ATTRIBUTES || [];
|
||||||
@@ -775,24 +801,32 @@ function initParamDeleteToggle(card) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция для сериализации значений параметров и их комплектов перед отправкой формы
|
// Функция для сериализации значений параметров и их товаров/комплектов перед отправкой формы
|
||||||
function serializeAttributeValues() {
|
function serializeAttributeValues() {
|
||||||
document.querySelectorAll('.attribute-card').forEach((card, idx) => {
|
document.querySelectorAll('.attribute-card').forEach((card, idx) => {
|
||||||
const valueGroups = card.querySelectorAll('.value-field-group');
|
const valueGroups = card.querySelectorAll('.value-field-group');
|
||||||
const values = [];
|
const values = [];
|
||||||
const kits = [];
|
const itemIds = [];
|
||||||
|
const itemTypes = [];
|
||||||
|
|
||||||
valueGroups.forEach(group => {
|
valueGroups.forEach(group => {
|
||||||
const valueInput = group.querySelector('.parameter-value-input');
|
const valueInput = group.querySelector('.parameter-value-input');
|
||||||
const kitSelect = group.querySelector('.parameter-kit-select');
|
const itemSelect = group.querySelector('.product-kit-select');
|
||||||
|
|
||||||
if (valueInput) {
|
if (valueInput && itemSelect) {
|
||||||
const value = valueInput.value.trim();
|
const value = valueInput.value.trim();
|
||||||
const kitId = kitSelect ? kitSelect.value : '';
|
const selectedValue = itemSelect.value; // Формат: "product_123" или "kit_456"
|
||||||
|
|
||||||
|
if (value && selectedValue) {
|
||||||
|
const parts = selectedValue.split('_');
|
||||||
|
if (parts.length === 2) {
|
||||||
|
const type = parts[0]; // 'product' или 'kit'
|
||||||
|
const id = parts[1];
|
||||||
|
|
||||||
if (value && kitId) {
|
|
||||||
values.push(value);
|
values.push(value);
|
||||||
kits.push(parseInt(kitId));
|
itemIds.push(parseInt(id));
|
||||||
|
itemTypes.push(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -808,15 +842,25 @@ function serializeAttributeValues() {
|
|||||||
}
|
}
|
||||||
valuesField.value = JSON.stringify(values);
|
valuesField.value = JSON.stringify(values);
|
||||||
|
|
||||||
const kitsFieldName = `attributes-${idx}-kits`;
|
const itemIdsFieldName = `attributes-${idx}-item_ids`;
|
||||||
let kitsField = document.querySelector(`input[name="${kitsFieldName}"]`);
|
let itemIdsField = document.querySelector(`input[name="${itemIdsFieldName}"]`);
|
||||||
if (!kitsField) {
|
if (!itemIdsField) {
|
||||||
kitsField = document.createElement('input');
|
itemIdsField = document.createElement('input');
|
||||||
kitsField.type = 'hidden';
|
itemIdsField.type = 'hidden';
|
||||||
kitsField.name = kitsFieldName;
|
itemIdsField.name = itemIdsFieldName;
|
||||||
card.appendChild(kitsField);
|
card.appendChild(itemIdsField);
|
||||||
}
|
}
|
||||||
kitsField.value = JSON.stringify(kits);
|
itemIdsField.value = JSON.stringify(itemIds);
|
||||||
|
|
||||||
|
const itemTypesFieldName = `attributes-${idx}-item_types`;
|
||||||
|
let itemTypesField = document.querySelector(`input[name="${itemTypesFieldName}"]`);
|
||||||
|
if (!itemTypesField) {
|
||||||
|
itemTypesField = document.createElement('input');
|
||||||
|
itemTypesField.type = 'hidden';
|
||||||
|
itemTypesField.name = itemTypesFieldName;
|
||||||
|
card.appendChild(itemTypesField);
|
||||||
|
}
|
||||||
|
itemTypesField.value = JSON.stringify(itemTypes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,11 +96,6 @@ class ConfigurableProductDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
# Добавляем доступные комплекты для выбора (активные, не временные)
|
|
||||||
context['available_kits'] = ProductKit.objects.filter(
|
|
||||||
status='active',
|
|
||||||
is_temporary=False
|
|
||||||
).order_by('name')
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -138,12 +133,6 @@ class ConfigurableProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
prefix='attributes'
|
prefix='attributes'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Доступные комплекты для JavaScript (для выбора при добавлении значений атрибутов)
|
|
||||||
context['available_kits'] = ProductKit.objects.filter(
|
|
||||||
status='active',
|
|
||||||
is_temporary=False
|
|
||||||
).order_by('name')
|
|
||||||
|
|
||||||
# Справочник атрибутов для autocomplete
|
# Справочник атрибутов для autocomplete
|
||||||
context['product_attributes'] = ProductAttribute.objects.prefetch_related('values').order_by('position', 'name')
|
context['product_attributes'] = ProductAttribute.objects.prefetch_related('values').order_by('position', 'name')
|
||||||
|
|
||||||
@@ -247,10 +236,12 @@ class ConfigurableProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
- attributes-X-visible: видимость
|
- attributes-X-visible: видимость
|
||||||
- attributes-X-DELETE: помечен ли для удаления
|
- attributes-X-DELETE: помечен ли для удаления
|
||||||
- attributes-X-values: JSON массив значений параметра
|
- attributes-X-values: JSON массив значений параметра
|
||||||
- attributes-X-kits: JSON массив ID комплектов для каждого значения
|
- attributes-X-item_ids: JSON массив ID товаров/комплектов
|
||||||
|
- attributes-X-item_types: JSON массив типов ('product' или 'kit')
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
from products.models.kits import ProductKit
|
from products.models.kits import ProductKit
|
||||||
|
from products.models.products import Product
|
||||||
|
|
||||||
# Сначала удаляем все старые атрибуты
|
# Сначала удаляем все старые атрибуты
|
||||||
ConfigurableProductAttribute.objects.filter(parent=self.object).delete()
|
ConfigurableProductAttribute.objects.filter(parent=self.object).delete()
|
||||||
@@ -282,9 +273,10 @@ class ConfigurableProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
|
|
||||||
visible = self.request.POST.get(f'attributes-{idx}-visible') == 'on'
|
visible = self.request.POST.get(f'attributes-{idx}-visible') == 'on'
|
||||||
|
|
||||||
# Получаем значения и их привязанные комплекты
|
# Получаем значения, ID и типы (kit/product)
|
||||||
values_json = self.request.POST.get(f'attributes-{idx}-values', '[]')
|
values_json = self.request.POST.get(f'attributes-{idx}-values', '[]')
|
||||||
kits_json = self.request.POST.get(f'attributes-{idx}-kits', '[]')
|
item_ids_json = self.request.POST.get(f'attributes-{idx}-item_ids', '[]')
|
||||||
|
item_types_json = self.request.POST.get(f'attributes-{idx}-item_types', '[]')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
values = json.loads(values_json)
|
values = json.loads(values_json)
|
||||||
@@ -292,15 +284,21 @@ class ConfigurableProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
values = []
|
values = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kit_ids = json.loads(kits_json)
|
item_ids = json.loads(item_ids_json)
|
||||||
except (json.JSONDecodeError, TypeError):
|
except (json.JSONDecodeError, TypeError):
|
||||||
kit_ids = []
|
item_ids = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
item_types = json.loads(item_types_json)
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
item_types = []
|
||||||
|
|
||||||
# Создаём ConfigurableProductAttribute для каждого значения
|
# Создаём ConfigurableProductAttribute для каждого значения
|
||||||
for value_idx, value in enumerate(values):
|
for value_idx, value in enumerate(values):
|
||||||
if value and value.strip():
|
if value and value.strip():
|
||||||
# Получаем соответствующий ID комплекта
|
# Получаем соответствующие ID и тип
|
||||||
kit_id = kit_ids[value_idx] if value_idx < len(kit_ids) else None
|
item_id = item_ids[value_idx] if value_idx < len(item_ids) else None
|
||||||
|
item_type = item_types[value_idx] if value_idx < len(item_types) else None
|
||||||
|
|
||||||
# Приготавливаем параметры создания
|
# Приготавливаем параметры создания
|
||||||
create_kwargs = {
|
create_kwargs = {
|
||||||
@@ -311,13 +309,17 @@ class ConfigurableProductCreateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
'visible': visible
|
'visible': visible
|
||||||
}
|
}
|
||||||
|
|
||||||
# Добавляем комплект если указан
|
# Добавляем комплект или товар если указан
|
||||||
if kit_id:
|
if item_id and item_type:
|
||||||
try:
|
try:
|
||||||
kit = ProductKit.objects.get(id=kit_id)
|
if item_type == 'kit':
|
||||||
|
kit = ProductKit.objects.get(id=item_id)
|
||||||
create_kwargs['kit'] = kit
|
create_kwargs['kit'] = kit
|
||||||
except ProductKit.DoesNotExist:
|
elif item_type == 'product':
|
||||||
# Комплект не найден - создаём без привязки
|
product = Product.objects.get(id=item_id)
|
||||||
|
create_kwargs['product'] = product
|
||||||
|
except (ProductKit.DoesNotExist, Product.DoesNotExist):
|
||||||
|
# Комплект/товар не найден - создаём без привязки
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ConfigurableProductAttribute.objects.create(**create_kwargs)
|
ConfigurableProductAttribute.objects.create(**create_kwargs)
|
||||||
@@ -527,10 +529,12 @@ class ConfigurableProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
- attributes-X-visible: видимость
|
- attributes-X-visible: видимость
|
||||||
- attributes-X-DELETE: помечен ли для удаления
|
- attributes-X-DELETE: помечен ли для удаления
|
||||||
- attributes-X-values: JSON массив значений параметра
|
- attributes-X-values: JSON массив значений параметра
|
||||||
- attributes-X-kits: JSON массив ID комплектов для каждого значения
|
- attributes-X-item_ids: JSON массив ID товаров/комплектов
|
||||||
|
- attributes-X-item_types: JSON массив типов ('product' или 'kit')
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
from products.models.kits import ProductKit
|
from products.models.kits import ProductKit
|
||||||
|
from products.models.products import Product
|
||||||
|
|
||||||
# Сначала удаляем все старые атрибуты
|
# Сначала удаляем все старые атрибуты
|
||||||
ConfigurableProductAttribute.objects.filter(parent=self.object).delete()
|
ConfigurableProductAttribute.objects.filter(parent=self.object).delete()
|
||||||
@@ -562,9 +566,10 @@ class ConfigurableProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
|
|
||||||
visible = self.request.POST.get(f'attributes-{idx}-visible') == 'on'
|
visible = self.request.POST.get(f'attributes-{idx}-visible') == 'on'
|
||||||
|
|
||||||
# Получаем значения и их привязанные комплекты
|
# Получаем значения, ID и типы (kit/product)
|
||||||
values_json = self.request.POST.get(f'attributes-{idx}-values', '[]')
|
values_json = self.request.POST.get(f'attributes-{idx}-values', '[]')
|
||||||
kits_json = self.request.POST.get(f'attributes-{idx}-kits', '[]')
|
item_ids_json = self.request.POST.get(f'attributes-{idx}-item_ids', '[]')
|
||||||
|
item_types_json = self.request.POST.get(f'attributes-{idx}-item_types', '[]')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
values = json.loads(values_json)
|
values = json.loads(values_json)
|
||||||
@@ -572,15 +577,21 @@ class ConfigurableProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
values = []
|
values = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kit_ids = json.loads(kits_json)
|
item_ids = json.loads(item_ids_json)
|
||||||
except (json.JSONDecodeError, TypeError):
|
except (json.JSONDecodeError, TypeError):
|
||||||
kit_ids = []
|
item_ids = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
item_types = json.loads(item_types_json)
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
item_types = []
|
||||||
|
|
||||||
# Создаём ConfigurableProductAttribute для каждого значения
|
# Создаём ConfigurableProductAttribute для каждого значения
|
||||||
for value_idx, value in enumerate(values):
|
for value_idx, value in enumerate(values):
|
||||||
if value and value.strip():
|
if value and value.strip():
|
||||||
# Получаем соответствующий ID комплекта
|
# Получаем соответствующие ID и тип
|
||||||
kit_id = kit_ids[value_idx] if value_idx < len(kit_ids) else None
|
item_id = item_ids[value_idx] if value_idx < len(item_ids) else None
|
||||||
|
item_type = item_types[value_idx] if value_idx < len(item_types) else None
|
||||||
|
|
||||||
# Приготавливаем параметры создания
|
# Приготавливаем параметры создания
|
||||||
create_kwargs = {
|
create_kwargs = {
|
||||||
@@ -591,13 +602,17 @@ class ConfigurableProductUpdateView(LoginRequiredMixin, ManagerOwnerRequiredMixi
|
|||||||
'visible': visible
|
'visible': visible
|
||||||
}
|
}
|
||||||
|
|
||||||
# Добавляем комплект если указан
|
# Добавляем комплект или товар если указан
|
||||||
if kit_id:
|
if item_id and item_type:
|
||||||
try:
|
try:
|
||||||
kit = ProductKit.objects.get(id=kit_id)
|
if item_type == 'kit':
|
||||||
|
kit = ProductKit.objects.get(id=item_id)
|
||||||
create_kwargs['kit'] = kit
|
create_kwargs['kit'] = kit
|
||||||
except ProductKit.DoesNotExist:
|
elif item_type == 'product':
|
||||||
# Комплект не найден - создаём без привязки
|
product = Product.objects.get(id=item_id)
|
||||||
|
create_kwargs['product'] = product
|
||||||
|
except (ProductKit.DoesNotExist, Product.DoesNotExist):
|
||||||
|
# Комплект/товар не найден - создаём без привязки
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ConfigurableProductAttribute.objects.create(**create_kwargs)
|
ConfigurableProductAttribute.objects.create(**create_kwargs)
|
||||||
|
|||||||
Reference in New Issue
Block a user