This commit introduces a new user-friendly interface for managing product attributes:
1. **Form Changes** (products/forms.py):
- Removed 'option' field from ConfigurableKitOptionForm (values now inline)
- Updated ConfigurableKitProductAttributeFormSetCreate to only include name, position, visible
- Updated BaseConfigurableKitProductAttributeFormSet validation for new structure
2. **Template Updates** (products/templates/products/configurablekit_form.html):
- Replaced row-based attribute interface with card-based design
- Each card contains:
- Parameter name field
- Position field
- Visibility toggle
- Inline value inputs with add/remove buttons
- "Add parameter" button creates new cards
- "Add value" button adds inline value inputs
3. **JavaScript Enhancements**:
- addValueField(): Creates new value input with delete button
- initAddValueBtn(): Initializes add value button for each card
- addParameterBtn: Dynamically generates new parameter cards
- serializeAttributeValues(): Converts inline values to JSON for POST submission
- Form submission intercept to serialize data before sending
4. **View Updates** (products/views/configurablekit_views.py):
- Both Create and Update views now have _save_attributes_from_cards() method
- Reads attributes-X-values JSON from POST data
- Creates ConfigurableKitProductAttribute for each parameter+value combination
- Handles parameter deletion and visibility toggling
**Key Features**:
✓ One-time parameter name entry with multiple inline values
✓ Add/remove values without reloading page
✓ Add/remove entire parameters with one click
✓ No database changes required
✓ Better UX: card layout more intuitive than rows
✓ Proper JSON serialization for value transmission
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
132 lines
4.5 KiB
Python
132 lines
4.5 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
Prostoy test skript dlya proverki ConfigurableKitOptionAttribute
|
|
bez Unicode simvolov
|
|
"""
|
|
import os
|
|
import sys
|
|
import django
|
|
|
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
|
|
django.setup()
|
|
|
|
from products.models.kits import (
|
|
ConfigurableKitProduct,
|
|
ConfigurableKitOption,
|
|
ConfigurableKitProductAttribute,
|
|
ConfigurableKitOptionAttribute,
|
|
ProductKit
|
|
)
|
|
from django_tenants.utils import tenant_context
|
|
from tenants.models import Client
|
|
|
|
try:
|
|
client = Client.objects.get(schema_name='grach')
|
|
print(f"OK: Found tenant: {client.name} (schema: {client.schema_name})\n")
|
|
except Client.DoesNotExist:
|
|
print("ERROR: Tenant 'grach' not found")
|
|
print("Available tenants:")
|
|
for c in Client.objects.all():
|
|
print(f" - {c.name} ({c.schema_name})")
|
|
sys.exit(1)
|
|
|
|
with tenant_context(client):
|
|
print("=" * 70)
|
|
print("TEST: ConfigurableKitOptionAttribute M2M Model")
|
|
print("=" * 70)
|
|
|
|
# Test 1: Check models exist
|
|
print("\n1. Checking if models exist...")
|
|
try:
|
|
# Try to get a ConfigurableKitProduct
|
|
products = ConfigurableKitProduct.objects.filter(name__icontains="test").first()
|
|
if products:
|
|
print(f" OK: Found ConfigurableKitProduct: {products.name}")
|
|
else:
|
|
print(" INFO: No test ConfigurableKitProduct found")
|
|
|
|
# Check ConfigurableKitProductAttribute exists
|
|
attrs = ConfigurableKitProductAttribute.objects.all()
|
|
print(f" OK: ConfigurableKitProductAttribute model exists. Count: {attrs.count()}")
|
|
|
|
# Check ConfigurableKitOptionAttribute exists
|
|
opt_attrs = ConfigurableKitOptionAttribute.objects.all()
|
|
print(f" OK: ConfigurableKitOptionAttribute model exists. Count: {opt_attrs.count()}")
|
|
except Exception as e:
|
|
print(f" ERROR: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
# Test 2: Check M2M relationships
|
|
print("\n2. Checking M2M relationships...")
|
|
try:
|
|
# Get a sample variant
|
|
option = ConfigurableKitOption.objects.first()
|
|
if option:
|
|
print(f" OK: Found option: {option.id} for parent: {option.parent.name}")
|
|
|
|
# Check if we can access attributes_set
|
|
attr_set = option.attributes_set.all()
|
|
print(f" OK: Can access attributes_set. Count: {attr_set.count()}")
|
|
|
|
# Check if we can reverse access
|
|
if attr_set.exists():
|
|
opt_attr = attr_set.first()
|
|
print(f" OK: Can access option_attr.option: {opt_attr.option.id}")
|
|
print(f" OK: Can access option_attr.attribute: {opt_attr.attribute.id}")
|
|
else:
|
|
print(" INFO: No ConfigurableKitOption found")
|
|
except Exception as e:
|
|
print(f" ERROR: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
# Test 3: Check form validation logic
|
|
print("\n3. Checking form validation setup...")
|
|
try:
|
|
from products.forms import ConfigurableKitOptionForm
|
|
|
|
# Create a test form with instance
|
|
option = ConfigurableKitOption.objects.filter(
|
|
parent__parent_attributes__isnull=False
|
|
).first()
|
|
|
|
if option:
|
|
form = ConfigurableKitOptionForm(instance=option)
|
|
print(f" OK: Form created for option with parent: {option.parent.name}")
|
|
|
|
# Check dynamically generated fields
|
|
dynamic_fields = [f for f in form.fields if f.startswith('attribute_')]
|
|
print(f" OK: Found {len(dynamic_fields)} dynamic attribute fields:")
|
|
for field_name in dynamic_fields:
|
|
print(f" - {field_name}")
|
|
else:
|
|
print(" INFO: No option with parent attributes found")
|
|
except Exception as e:
|
|
print(f" ERROR: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
# Test 4: Check view integration
|
|
print("\n4. Checking view imports...")
|
|
try:
|
|
from products.views.configurablekit_views import (
|
|
ConfigurableKitProductCreateView,
|
|
ConfigurableKitProductUpdateView
|
|
)
|
|
print(" OK: Views imported successfully")
|
|
print(" OK: ConfigurableKitProductCreateView available")
|
|
print(" OK: ConfigurableKitProductUpdateView available")
|
|
except Exception as e:
|
|
print(f" ERROR: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|
|
|
|
print("\n" + "=" * 70)
|
|
print("OK: ALL TESTS PASSED! Implementation is ready for testing.")
|
|
print("=" * 70)
|