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 introduces a complete refactoring of the variable product system:
1. **New Model**: ConfigurableKitOptionAttribute - M2M relationship between variants and attribute values
- Replaces TextField-based attribute storage with proper database relationships
- Ensures one value per attribute per variant through unique_together constraint
- Includes indexes on both option and attribute fields for query performance
2. **Form Refactoring**:
- Removed static 'attributes' field from ConfigurableKitOptionForm
- Added dynamic field generation in __init__ based on parent attributes
- Creates ModelChoiceField for each attribute (e.g., attribute_Длина, attribute_Упаковка)
- Enhanced BaseConfigurableKitOptionFormSet validation to check all attributes are filled
3. **View Updates**:
- Modified ConfigurableKitProductCreateView.form_valid() to save M2M relationships
- Modified ConfigurableKitProductUpdateView.form_valid() with same logic
- Uses transaction.atomic() for data consistency
4. **Template & JS Enhancements**:
- Reordered form so attributes section appears before variants
- Fixed template syntax: changed from field.name.startswith to "attribute_" in field.name
- Updated JavaScript to dynamically generate attribute select fields when adding variants
- Properly handles formset naming convention (options-{idx}-attribute_{name})
5. **Database Migrations**:
- Created migration 0005 to alter ConfigurableKitOption.attributes to JSONField (for future use)
- Created migration 0006 to add ConfigurableKitOptionAttribute model
6. **Tests**:
- Added test_configurable_simple.py for model/form verification
- Added test_workflow.py for complete end-to-end testing
- All tests passing successfully
Features:
✓ All attributes required for each variant if defined on parent
✓ One value per attribute per variant (unique_together constraint)
✓ One default variant per product (formset validation)
✓ Dynamic form field generation based on parent attributes
✓ Atomic transactions for multi-part operations
✓ Proper error messages per variant number
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
- Создана модель ConfigurableKitProductAttribute с полями name, option, position, visible
- Добавлены формы и formsets для управления атрибутами родительского товара
- Обновлены CRUD представления для работы с атрибутами (создание/редактирование)
- Добавлен блок атрибутов в шаблоны создания/редактирования
- Обновлена страница детального просмотра с отображением атрибутов товара
- Добавлен JavaScript для динамического добавления форм атрибутов
- Реализована валидация дубликатов атрибутов в formset
- Атрибуты сохраняются в transaction.atomic() вместе с вариантами
Теперь можно определять схему атрибутов для экспорта на WooCommerce без использования JSON или ID, только name и option.
- Аннотация товаров остатками (available_qty) и резервами (reserved_qty) через Subquery
- Компактный формат отображения: X(−Y) где X - доступно, Y - зарезервировано
- Визуальная стилизация: крупное число для остатков, мелкое для резервов
- Цветовая индикация: зелёный (≥5), жёлтый (<5), красный (≤0)
- Без дополнительных SQL-запросов, оптимизировано через подзапросы
- Уменьшен размер шрифта с 0.95rem до 0.85rem для лучшей читаемости
- Уменьшен line-height с 1.2 до 1.1 для компактного расположения текста
- Текст теперь полностью помещается внутри кнопок без выхода за границы
- Сохранена возможность переноса текста на две строки для кнопки 'Отложенный заказ'
- Добавлено исключение для кнопки #scheduleLater
- Для этой кнопки white-space: normal вместо nowrap
- Текст переносится на две строки для лучшей читаемости
- Остальные кнопки остаются в одну строку
- Увеличен размер шрифта кнопок с 0.75rem до 0.95rem
- Добавлен жирный шрифт (font-weight: 700)
- Изменено white-space с normal на nowrap для избежания переносов строк
- Убраны word-wrap: break-word (не нужен при nowrap)
- Кнопки теперь более читабельны на планшете
- Убрана стартовая загрузка витринных комплектов (теперь только по API)
- showcase_kits_json теперь пустой массив на старте
- Витринные букеты загружаются динамически при клике на ВИТРИНА
- Оптимизирована get_showcase_kits_for_pos - устранены N+1 запросы
- Один запрос для всех резервов вместо N запросов на комплект
- Используется prefetch для kit_items (без дополнительных запросов)
- Добавлена группировка резервов в памяти вместо повторных обращений к БД
- Оптимизирована загрузка фото товаров и комплектов
- Используется Prefetch только для первого фото (thumbnail)
- Вместо photos.first() (который тянет все фото) - ограниченный queryset
- Prefetch с to_attr='first_photo_list' для минимизации запросов
- Результат: значительное сокращение нагрузки на БД при открытии POS
- Добавлены API endpoints для получения и обновления витринных комплектов
- GET /pos/api/product-kits/<id>/ - получение деталей комплекта
- POST /pos/api/product-kits/<id>/update/ - обновление комплекта
- Реализовано редактирование комплектов из POS интерфейса
- Кнопка редактирования (карандаш) на карточках витринных букетов
- Модальное окно предзаполняется данными комплекта
- Поддержка изменения состава, цен, описания и фото
- Умное управление резервами при изменении состава
- Введено изолированное состояние tempCart для модального окна
- Основная корзина (cart) больше не затрагивается при редактировании
- tempCart используется для создания и редактирования комплектов
- Автоочистка tempCart при закрытии модального окна
- Устранён побочный эффект загрузки состава комплекта в основную корзину
- Добавлен API endpoint GET /pos/api/showcase-kits/ для получения актуальных витринных букетов
- Изменена переменная SHOWCASE_KITS на изменяемую showcaseKits
- Добавлена функция refreshShowcaseKits() для обновления данных с сервера
- Кнопка ВИТРИНА теперь загружает свежие данные перед отображением
- После создания временного букета автоматически обновляется список и переключается вид на витрину
- Исправлена проблема с отображением только что созданных витринных букетов
- Reduced spacing around 'Итого:' line for more compact design
- Changed from h5 to strong tags for better space utilization
- Removed bottom margin from cart list
- Set symmetric padding (py-1) for total section
- More vertical space now available for cart items
- Added Bootstrap icon (bi-box-seam) for kit items in POS cart
- Kits and showcase kits now display with blue icon for visual distinction
- Regular products remain without icons for cleaner look
- Maintains consistency with product list view styling
- Added get_showcase_kits_for_pos() function to retrieve showcase kits with active reservations
- Modified POS terminal to show showcase kits when 'Витрина' button is clicked
- Showcase kits displayed as product cards with showcase name badge (🌺 icon)
- Added isShowcaseView flag to toggle between regular and showcase view modes
- Implemented distinct styling for active showcase button:
* Bright orange background (#ff6600)
* Black text for contrast
* Thicker border (3px)
* Enhanced shadow and scale effect (1.05)
- Showcase kits can be added to cart for sale from POS interface
- Добавлен API endpoint для создания временного комплекта из корзины
- Реализован endpoint получения списка активных витрин
- Создано модальное окно для настройки комплекта и выбора витрины
- JavaScript логика: валидация корзины, отправка данных, очистка после успеха
- Автоматическая генерация названия комплекта с датой и временем
- Агрегация дубликатов товаров в корзине перед созданием
- Резервирование компонентов на витрину через ShowcaseManager
- Расчёт и отображение итоговой цены комплекта
- Создана модель Showcase (витрина) привязанная к складу
- Расширена Reservation для поддержки витринных резервов
- Добавлены поля в OrderItem для маркировки витринных продаж
- Реализован ShowcaseManager с методами резервирования, продажи и разбора
- Обновлён админ-интерфейс для управления витринами
- Добавлена кнопка Витрина в POS (категории) и API для просмотра
- Добавлена кнопка На витрину в панели действий POS
- Миграции готовы к применению
- Проверяется количество уже существующих фото перед загрузкой новых
- Блокируется загрузка если уже есть 10 фото (максимум)
- При превышении загружается только доступное количество слотов
- Информативные сообщения об ошибках и предупреждения для пользователя
- Исправлена проблема с накоплением фото при многократном редактировании
- Добавлен retry на 5 сек при DoesNotExist для ожидания коммита транзакции
- temp_path сохраняется в PhotoProcessingStatus.result_data при постановке задачи
- При окончательной неудаче not_found удаляется осиротевший temp файл
- Предотвращает накопление temp файлов при гонке создания фото
- Создан отдельный CSS файл products/static/products/css/gallery.css для стилей галереи
- Перенесены все стили модальной карусели из quality_indicator.css в gallery.css
- Добавлены современные стрелки навигации с широкой областью нажатия (80px)
- Улучшена видимость элементов управления: контрастные обводки, тени, градиенты
- Круглые индикаторы с полупрозрачной подложкой для видимости на любом фоне
- Адаптивные размеры для планшетов (60px) и мобильных (50px)
- Убраны визуальные индикаторы качества фото из углов изображений
- Оставлена только текстовая информация о качестве под фотографиями
- Упрощена разметка списка товаров - удалены ненужные обёртки и стили
- Заменен несуществующий фильтр is_active на status='active' для моделей Product и ProductKit
- Устранена ошибка FieldError при отображении страницы тега
- Комментарии сохранены на русском языке
- Добавлен столбец 'Теги' в таблицу товаров и комплектов
- Реализовано умное отображение тегов: показываются первые 2 тега + многоточие
- При наведении на ячейку тегов показывается полный список во всплывающей подсказке
- Исправлены все ссылки с устаревших URL (product-list, productkit-list) на новый (products-list)
- Обновлены шаблоны: product_detail, product_form, product_confirm_delete, productkit_detail, productkit_create, productkit_edit
- Обновлен компонент category_filter_buttons с поддержкой фильтра ?type=products и ?type=kits
- Удалена ненужная подсказка 'Ctrl+Click' под полем выбора тегов в фильтрах
- Создан единый шаблон products_list.html для отображения товаров и комплектов
- Удалены дублирующиеся шаблоны (product_list, productkit_list, products_unified_list, all_products_list)
- Добавлены фильтры: тип (все/товары/комплекты), категория, статус, наличие, теги
- Обновлен CombinedProductListView с поддержкой фильтрации по типу и тегам
- Изменены URL маршруты: главная страница /products/ теперь показывает объединенный список
- Обновлены success_url во всех CRUD представлениях для редиректа на объединенный список
- Добавлена фильтрация по тегам с отображением количества выбранных элементов
- Улучшена UX: компактный select для тегов с счетчиком выбранных
- Все комментарии в коде переведены на русский язык
- Added temp file deletion in Celery task after successful processing
- Added temp file cleanup in sync fallback method
- Added temp file removal in delete() if processing never completed
- Prevents accumulation of orphaned files in media/<entity>/temp/ folders
Изменения:
- Заменено жёсткое кодирование статусов ('draft', 'new' и т.д.) на динамическое отображение из OrderStatus объекта
- Теперь статусы берут цвет (color) и название (label/name) из модели OrderStatus
- Обновлена логика отображения статуса оплаты: заменено payment_status на is_paid и amount_paid
- Добавлены иконки для наглядности (check-circle, exclamation-circle, x-circle)
- Для частичной оплаты теперь показывается сумма уже оплаченного
Это позволяет:
- Добавлять новые статусы без изменения шаблона
- Менять цвета статусов через admin панель
- Использовать правильные поля из модели Order
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Реализована трёхуровневая система статусов товаров и комплектов:
- active (Активный) - товар доступен для продажи
- archived (Архивный) - скрыт, можно восстановить в следующем сезоне
- discontinued (Снят) - морально устарел, готов к удалению
Изменения:
1. Модели (BaseProductEntity, Product, ProductKit):
- Заменено поле is_deleted (Boolean) на status (CharField)
- Добавлены архивные метаданные (archived_at, archived_by)
- Обновлены методы: archive(), restore(), discontinue(), delete()
- Уникальное ограничение изменено на conditional (status='active')
2. Менеджеры (ActiveManager, SoftDeleteQuerySet):
- Полиморфная поддержка обеих систем (status и is_active)
- Использует hasattr() для совместимости с наследниками
- Методы: archive(), restore(), discontinue(), archived_only(), active_only()
3. Формы (ProductForm, ProductKitForm):
- Включены поле status в формы
- Валидация уникальности по status='active'
- CSS классы для статус-селектора
4. Admin панель:
- DeletedFilter переименован в StatusFilter с тремя опциями
- get_status_display() с цветным отображением статуса
- Actions: restore_items, hard_delete_selected, delete_selected
- Readonly поля для архивирования
5. Представления:
- ProductListView: фильтр status вместо is_active
- CombinedProductListView: поддержка фильтра status для товаров и комплектов
- API views обновлены для работы со статусом
6. Шаблоны:
- product_form.html: form.status вместо form.is_active
- productkit_create.html: form.status вместо form.is_active
- productkit_edit.html: form.status вместо form.is_active
7. Миграции:
- Удалены все старые миграции (чистый перезапуск по требованию пользователя)
- Создана новая миграция 0001_initial с полной структурой status-системы
- Удален старый код преобразования is_deleted -> status
Проведённые проверки:
- Django system check passed ✓
- Полиморфные менеджеры работают с обеими системами
- Уникальные ограничения корректно работают с условиями
- История заказов сохраняется даже после архивирования товара (django-simple-history)
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Реализована полная система обеспечения уникальности названий:
1. **Уровень БД (Model Constraints)** - добавлены UniqueConstraint для:
- Product: уникальность имени среди активных товаров
- ProductCategory: уникальность имени среди активных категорий
- ProductTag: уникальность имени только для активных тегов (неактивные могут повторяться)
- ProductKit: уникальность имени среди активных, непроизвременных комплектов
2. **Уровень формы (Form Validation)** - добавлены clean() методы для:
- ProductForm, ProductKitForm, ProductCategoryForm, ProductTagForm
- Валидация до попытки сохранения в БД
- Сохранение введённых данных при ошибке валидации
3. **Уровень представления (IntegrityError Handling)** - добавлена обработка в views:
- ProductCategoryCreateView, ProductCategoryUpdateView
- ProductTagCreateView, ProductTagUpdateView
- ProductKitCreateView, ProductKitUpdateView
- create_tag_api: защита от race conditions с fallback поиском
Три уровня защиты гарантируют:
- Профилактика ошибок на уровне формы
- Обработка исключительных ситуаций в views
- Защита БД от одновременных запросов (race conditions)
- Пользователь видит понятное сообщение об ошибке вместо 500 ошибки
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Изменена отображение нумерации позиций фотографий товара:
- Главное фото теперь показывается как "⭐ Главное (позиция 1)" вместо "Главное"
- Остальные фотографии нумеруются с 2 вместо 1: "Позиция 2, 3, 4..."
- Это совпадает с интуитивным восприятием пользователя (первая позиция = главное фото)
Изменено:
1. product_detail.html (2 места):
- Отображение в галерее миниатюр
- Отображение в модальной галерее (бейдж главного фото)
2. product_form.html (1 место):
- Отображение позиции при редактировании товара
Внутренняя база данных не изменяется (order = 0,1,2...) - это только визуальное отображение.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Реализована трёхуровневая защита от IntegrityError при создании товаров с одинаковым названием:
1. SlugService улучшен:
- Добавлен метод _get_base_queryset() для работы с мягким удалением
- Проверка всех объектов включая удалённые (all_objects)
- Новый метод get_next_available_slug() для retry обработки
- Максимум 100 попыток поиска уникального slug
2. BaseProductEntity.save() защищена:
- transaction.atomic() для атомарности операции
- Retry логика с 5 попытками при IntegrityError
- При конфликте добавляется суффикс (-1, -2, -3...)
- Fallback на timestamp если суффиксы исчерпаны
3. Views обрабатывают IntegrityError:
- ProductCreateView.form_valid() перехватывает ошибку
- ProductUpdateView.form_valid() перехватывает ошибку
- Пользователю показывается дружелюбное сообщение об ошибке
- Нет 500 ошибок - вместо этого form_invalid() с сообщением
Эффект:
- До: User создаёт товар "Роза красная" 2 раза → IntegrityError → 500 ошибка
- После: User создаёт товар "Роза красная" 2 раза → slug автоматически становится "roza-krasnaya-1"
Протестировано на Django shell и синтаксис проверен.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Исключить из отслеживания:
- README_CELERY.md, CELERY_SETUP_GUIDE.md и другие документы
- start_celery.bat, start_celery.sh скрипты
Эти файлы сгенерированы автоматически и не нужны в репозитории.
🤖 Generated with Claude Code
Изменения:
- ProductCreateView/UpdateView теперь показывают warnings для предупреждений о лимите фото
- Разделение сообщений: error (красный) vs warning (желтый)
- Улучшен components/messages.html:
* Добавлены иконки для каждого типа сообщения
* Bootstrap Icons интеграция
* Кастомные цвета для alerts
* Лучший visual feedback для пользователя
Теперь пользователи видят понятные сообщения везде на сайте!
🤖 Generated with Claude Code