Implement card-based interface for ConfigurableKitProduct attributes

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>
This commit is contained in:
2025-11-18 20:54:14 +03:00
parent 48938db04f
commit def795f0ad
9 changed files with 1310 additions and 107 deletions

210
TESTING_GUIDE.md Normal file
View File

@@ -0,0 +1,210 @@
# ConfigurableKitProduct Testing Guide
## Overview
The M2M architecture for variable products is now fully implemented. This guide walks through testing the complete workflow.
## Prerequisites
- Django project is running on `http://grach.localhost:8000/`
- You have at least 2-3 ProductKit objects in the database
- Admin panel is accessible
## Automated Tests
Run the test scripts to verify implementation:
```bash
cd myproject
# Test 1: Basic model and form verification
python test_configurable_simple.py
# Test 2: Complete workflow test
python test_workflow.py
```
Expected output: "OK: ALL TESTS PASSED!"
## Manual Testing - Full Workflow
### Step 1: Create a Variable Product
1. Open http://grach.localhost:8000/products/configurable-kits/create/
2. Fill in the form:
- **Name**: "Test Bouquet"
- **SKU**: "TEST-BQ-001"
- **Description**: "A test variable product"
### Step 2: Define Attributes
In the "Attributes" section, add attribute values:
1. **First Attribute Group** - "Length" (Длина)
- Click "Add Attribute"
- Name: Длина
- Value: 50
- Position: 0
- Click "Add Attribute" again
- Name: Длина
- Value: 60
- Position: 1
- Click "Add Attribute" again
- Name: Длина
- Value: 70
- Position: 2
2. **Second Attribute Group** - "Packaging" (Упаковка)
- Click "Add Attribute"
- Name: Упаковка
- Value: БЕЗ
- Position: 0
- Click "Add Attribute" again
- Name: Упаковка
- Value: В УПАКОВКЕ
- Position: 1
### Step 3: Create Variants
In the "Variants" section, create variants by:
1. **Variant 1** - Default variant
- Select a ProductKit (e.g., "Kit 1")
- Select attributes:
- Длина: 50
- Упаковка: БЕЗ
- Check "По умолчанию" (Default)
2. **Variant 2** - Alternative
- Click "Add Variant"
- Select a different ProductKit (e.g., "Kit 2")
- Select attributes:
- Длина: 60
- Упаковка: В УПАКОВКЕ
- Don't check default
3. **Variant 3** - Another alternative
- Click "Add Variant"
- Select yet another ProductKit (e.g., "Kit 3")
- Select attributes:
- Длина: 70
- Упаковка: БЕЗ
- Don't check default
### Step 4: Save and Verify
1. Click "Save"
2. If successful, you should see the product in the list
3. Click on it to edit and verify:
- All attributes are saved correctly
- All variants have their correct attribute values
- The default variant is marked correctly
## Testing Validation
### Test 1: Missing Attribute Validation
1. Edit the product you just created
2. Add a new variant
3. Select a ProductKit but leave one of the attribute dropdowns empty
4. Click Save
5. **Expected**: Form should show error: "Вариант X: необходимо заполнить атрибут(ы) 'Длина'."
### Test 2: Duplicate Kit Validation
1. Edit the product
2. Add a new variant with the same ProductKit as Variant 1
3. Click Save
4. **Expected**: Form should show error: "Комплект 'X' добавлен более одного раза."
### Test 3: Multiple Default Validation
1. Edit the product
2. Check the "Default" checkbox on Variant 2
3. Don't uncheck Variant 1's default
4. Click Save
5. **Expected**: Form should show error: "Можно установить только один вариант как 'по умолчанию'."
### Test 4: Dynamic Variant Addition
1. Click "Add Variant" button
2. A new form row should appear with:
- Kit dropdown
- All attribute dropdowns matching the first variant
- Default checkbox
- Delete button
3. **Expected**: All fields should be properly named with correct formset indices
## Database Verification
### Check M2M Relationships
```python
from django_tenants.utils import tenant_context
from tenants.models import Client
from products.models.kits import ConfigurableKitProduct, ConfigurableKitOptionAttribute
client = Client.objects.get(schema_name='grach')
with tenant_context(client):
# Get your test product
product = ConfigurableKitProduct.objects.get(name='Test Bouquet')
# Check attributes
attrs = product.parent_attributes.all()
print(f"Attributes: {attrs.count()}")
for attr in attrs:
print(f" - {attr.name} = {attr.option}")
# Check variants and their attributes
for option in product.options.all():
print(f"\nVariant for kit {option.kit.name}:")
for opt_attr in option.attributes_set.all():
print(f" - {opt_attr.attribute.name} = {opt_attr.attribute.option}")
```
## What to Check
- [ ] Product created successfully
- [ ] Attributes display in correct order
- [ ] Variants can be created with all required attributes
- [ ] Form validates missing attributes
- [ ] Form prevents duplicate kits
- [ ] Form prevents multiple default variants
- [ ] Dynamic variant addition works with all attribute fields
- [ ] Delete button removes variants correctly
- [ ] Data persists correctly after save
- [ ] Editing existing product pre-fills attribute selections
## Troubleshooting
### Template Error: "Unused 'attribute_' at end of if expression"
- **Fixed**: Changed `field.name.startswith 'attribute_'` to `"attribute_" in field.name`
- Already applied in the template
### Form Fields Not Showing for Attributes
- Check that parent product has attributes defined
- Verify `parent_attributes` are accessible in form __init__
- Check browser console for JavaScript errors
### M2M Relationships Not Saving
- Verify ConfigurableKitOptionAttribute model exists
- Check migration 0006 has been applied: `python manage.py migrate products`
- Verify view code properly creates ConfigurableKitOptionAttribute records
### Dynamic Variant Form Doesn't Show Attributes
- Check first form has attribute selects with `data-attribute-name` attribute
- Verify JavaScript addOptionBtn listener is working
- Check browser console for errors
## Performance Notes
- Attributes are indexed on option and attribute fields for fast queries
- Formset validation iterates through all forms and attributes
- For products with many attributes (>10), consider pagination
## Next Steps
After successful testing, you can:
1. Delete test products and attributes
2. Create real variable products in admin
3. Test WooCommerce integration (if applicable)
4. Monitor performance with actual product data