Enforce parameter binding requirement for ConfigurableKitProduct variants

Changes:
1. Removed unused attributesMetadata container from configurablekit_form.html
   - Dead code from old formset-based attribute system
   - 10 lines of unused HTML and templating removed

2. Enhanced formset validation in BaseConfigurableKitOptionFormSet.clean():
   - If product HAS parameters: variants MUST select values for ALL parameters
   - If product HAS NO parameters: variants MUST NOT be created
   - Error message guides user to add parameters first

Business logic:
- ConfigurableKitProduct variants (options) are ALWAYS bound to attribute values
- You cannot create orphan variants without parameter selections
- Each variant must have a value for every product parameter

User experience:
- Clear error message if trying to add variant without parameters
- Enforces proper product structure: parameters first, then variants

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-18 21:46:58 +03:00
parent b1f0d99324
commit 29859503a7
4 changed files with 88 additions and 21 deletions

View File

@@ -722,7 +722,7 @@ class BaseConfigurableKitOptionFormSet(forms.BaseInlineFormSet):
parent = self.instance
if parent and parent.pk:
# Получаем все уникальные названия атрибутов родителя
attribute_names = (
attribute_names = list(
parent.parent_attributes
.all()
.order_by('position', 'name')
@@ -730,17 +730,24 @@ class BaseConfigurableKitOptionFormSet(forms.BaseInlineFormSet):
.values_list('name', flat=True)
)
# Проверяем что каждый атрибут выбран
missing_attributes = []
for attr_name in attribute_names:
field_name = f'attribute_{attr_name}'
if field_name not in form.cleaned_data or not form.cleaned_data[field_name]:
missing_attributes.append(attr_name)
# Если у товара есть параметры, вариант ОБЯЗАН иметь значения для них
if attribute_names:
# Проверяем что каждый атрибут выбран
missing_attributes = []
for attr_name in attribute_names:
field_name = f'attribute_{attr_name}'
if field_name not in form.cleaned_data or not form.cleaned_data[field_name]:
missing_attributes.append(attr_name)
if missing_attributes:
attrs_str = ', '.join(f'"{attr}"' for attr in missing_attributes)
if missing_attributes:
attrs_str = ', '.join(f'"{attr}"' for attr in missing_attributes)
raise forms.ValidationError(
f'Вариант {idx + 1}: необходимо заполнить атрибут(ы) {attrs_str}.'
)
else:
# Если у товара нет параметров, вариант без привязки к параметрам бессмысленен
raise forms.ValidationError(
f'Вариант {idx + 1}: необходимо заполнить атрибут(ы) {attrs_str}.'
f'Вариант {idx + 1}: сначала добавьте параметры товара в разделе "Параметры товара".'
)
# Проверяем, что не более одного "is_default"

View File

@@ -258,17 +258,6 @@ input[name*="DELETE"] {
{% endfor %}
</div>
<!-- Скрытый контейнер с информацией об атрибутах для JavaScript -->
<div id="attributesMetadata" style="display: none;">
{% for attr in attribute_formset %}
{% if attr.cleaned_data or attr.instance.pk %}
<div data-attr-name="{{ attr.cleaned_data.name|default:attr.instance.name }}"
data-attr-id="{{ attr.instance.id }}">
</div>
{% endif %}
{% endfor %}
</div>
<button type="button" class="btn btn-sm btn-outline-primary" id="addOptionBtn">
<i class="bi bi-plus-circle me-1"></i>Добавить вариант
</button>