- Добавить inline-редактирование цен в списке товаров
- Оптимизировать карточки товаров в POS-терминале
- Рефакторинг моделей единиц измерения
- Миграция unit -> base_unit в SalesUnit
- Улучшить UI форм создания/редактирования товаров
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Добавлена поддержка выбора основной категории (primary_category) для товаров и наборов, а также новая модель IntegrationCategoryMapping для связи категорий с внешними площадками. Теперь можно указать категорию товара, которая будет использоваться при экспорте на внешние площадки (Recommerce, WooCommerce и др.), с возможностью настройки маппинга категорий для каждого типа интеграции.
Добавлены поля is_new, is_popular, is_special в форму продукта.
Настроено отображение полей в виде переключателей (switch).
Добавлено отображение бейджей флагов в списке товаров
и на странице детализации продукта.
При редактировании товара проверка зарезервированных префиксов теперь
пропускается, если артикул не изменился. Это позволяет редактировать
товары с автоматически сгенерированными артикулами.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Добавлена полноценная интеграция единиц измерения (UoM) для продажи
товаров в разных единицах с автоматическим пересчётом цен и остатков.
## Основные изменения:
### Backend
- Расширен API поиска товаров (api_views.py): добавлена сериализация sales_units
- Создан новый endpoint get_product_sales_units_api для загрузки единиц с остатками
- Добавлено поле sales_unit в OrderItemForm и SaleForm с валидацией
- Созданы CRUD views для управления единицами продажи (uom_views.py)
- Обновлена ProductForm: использует base_unit вместо устаревшего unit
### Frontend
- Создан модуль sales-units.js с функциями для работы с единицами
- Интегрирован в select2-product-search.js: автозагрузка единиц при выборе товара
- Добавлены контейнеры для единиц в order_form.html и sale_form.html
- Реализовано автоматическое обновление цены при смене единицы продажи
- При выборе базовой единицы цена возвращается к базовой цене товара
### UI
- Добавлены страницы управления единицами продажи в навбар
- Созданы шаблоны: sales_unit_list.html, sales_unit_form.html, sales_unit_delete.html
- Добавлены фильтры по товару, единице, активности и дефолтности
## Исправленные ошибки:
- Порядок инициализации: обработчики устанавливаются ДО триггера события change
- Цена корректно обновляется при выборе единицы продажи
- При выборе "Базовая единица" возвращается базовая цена товара
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- В миксин SKUUniqueMixin добавлен словарь RESERVED_PREFIXES
- Префиксы PROD-, KIT-, CAT-, VAR- зарезервированы для автогенерации
- При попытке ручного ввода артикула с зарезервированным префиксом выдается понятная ошибка
- Проверка регистронезависимая (prod-123 тоже будет заблокирован)
- Пользователю предлагается либо использовать другой артикул, либо оставить поле пустым для автогенерации
- Решение элегантное, централизованное в миксине, работает для всех форм товаров
- Добавлен миксин SKUUniqueMixin для единообразной валидации артикулов
- Валидация проверяет уникальность SKU среди Product, ProductKit, ProductCategory, ConfigurableProduct
- Реализована автогенерация артикулов для ConfigurableProduct (формат VAR-XXXXXX)
- Добавлен новый тип счетчика 'configurable' в SKUCounter
- Обновлены формы Product, ProductKit, ProductCategory, ConfigurableProduct
- Рефакторинг методов clean() в формах: валидация имени вынесена в clean_name()
- Добавлена функция generate_configurable_sku() в sku_generator.py
- Обновлена функция ensure_sku_unique() для проверки ConfigurableProduct
- Добавлен метод save() в модель ConfigurableProduct для автогенерации SKU
- Обновлен шаблон configurableproduct_form.html с отображением help_text для SKU
Код стал чистым, без дублирования логики валидации.
Основные изменения:
- Переименование ConfigurableKitProduct → ConfigurableProduct
- Добавлена поддержка Product как варианта (не только ProductKit)
- Создан справочник атрибутов (ProductAttribute, ProductAttributeValue)
- CRUD для управления атрибутами с inline редактированием значений
- Пересозданы миграции с нуля для всех приложений
- Добавлена ссылка на атрибуты в навигацию
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Удалено ручное редактирование себестоимости из формы товара
- Себестоимость теперь рассчитывается автоматически из партий (FIFO)
- Добавлена модель CostPriceHistory для логирования изменений
- Добавлен signal для автоматического логирования изменений cost_price
- Админ-панель: себестоимость read-only с детальной информацией о партиях
- Фронтенд: цены перемещены под название, теги под категории
- Поле cost_price сделано опциональным (default=0) для создания товаров
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Changed from table to card-based design for better space efficiency
- Reduced padding and margins to fit 15+ statuses on screen without scrolling
- Minimized font sizes and icon sizes for compact display
- Added proper styling for edit and delete buttons with hover effects
- Improved visual hierarchy with color indicators and badges
- Maintained all functionality while improving UX
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
The parameter name field had readonly='readonly' which prevented users from entering values.
This fix allows users to:
- Enter parameter name directly in the form field
- Modify parameter names during editing
- Type any parameter name they need
The readonly attribute was from a mistaken assumption that values would be pre-filled by JavaScript.
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
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.
Реализована трёхуровневая система статусов товаров и комплектов:
- 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. Фильтрация тегов по активности
- ProductForm и ProductKitForm показывают только активные теги в селектах
- ProductListView, ProductKitListView передают только активные теги в контекст фильтров
### 2. Отображение тегов на страницах товаров/комплектов
- product_detail.html отображает только активные теги
- productkit_detail.html отображает только активные теги
### 3. Логика отображения в деталях тега
- Для активного тега: показываются только активные товары/комплекты
- Для неактивного тега: показываются ВСЕ товары/комплекты (для возможности ручной очистки)
### 4. API endpoint для переключения статуса
- Новый endpoint toggle_tag_status_api в api_views.py
- POST /products/api/tags/<id>/toggle/
- Переключает is_active и возвращает новый статус
### 5. AJAX toggle switch в таблице тегов
- Заменены бейджи на toggle switch в tag_list.html
- Переключатель в 1.3x больше (масштабирование через CSS)
- Мгновенное обновление без перезагрузки страницы
- Показывает сообщение об успехе/ошибке
### 6. Связь в БД остаётся неизменной
- При деактивации тег остаётся привязан к товарам в БД
- Просто скрывается в интерфейсе
- При реактивации вновь становится видимым
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Упрощена модель ProductTag:
- Удалены поля soft delete (is_deleted, deleted_at, deleted_by)
- Добавлено поле is_active для управления статусом
- Упрощены менеджеры и методы модели
Создан CRUD функционал:
- ProductTagForm: форма с автогенерацией slug
- Views: список, создание, просмотр, редактирование, удаление
- URL маршруты: /products/tags/*
- Шаблоны: list, form, detail, confirm_delete
Особенности:
- Поиск по названию и slug
- Фильтрация по статусу активности
- Статистика использования тегов в товарах/комплектах
- Пагинация (20 на страницу)
- Предупреждение при удалении с отображением связанных объектов
- Добавлена ссылка "Теги" в навигацию
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Изменения:
- Удалена функция create_temporary_kit из myproject/orders/views.py
- Перенесена в новый сервис myproject/products/services/kit_service.py
- Добавлен API endpoint products:api-temporary-kit-create для создания временных комплектов
- Обновлены URL-ы соответственно
Преимущества:
- Логика временных комплектов теперь находится в соответствующем приложении (products)
- Упрощена архитектура orders приложения
- Сервис может быть переиспользован в других контекстах
- Лучшее разделение ответственности между приложениями
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Удалено ненужное поле 'notes' из формы создания/редактирования комплектов:
- Удалено из модели KitItem
- Удалено из формы KitItemForm
- Удалено из template kititem_formset.html
- Удалено из formset'ов KitItemFormSetCreate и KitItemFormSetUpdate
- Создана миграция БД для удаления поля из базы данных
Теперь каждый товар в комплекте отображается с 4 полями:
- Товар (или Группа вариантов)
- Количество
- Кнопка удаления
- ID (скрытое)
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Реализована логика чтобы только одно из четырёх полей корректировки цены
можно было заполнить одновременно:
JavaScript валидация:
- При заполнении одного поля остальные 3 автоматически отключаются
- При попытке заполнить два поля одновременно:
- Оставляется только первое заполненное
- Остальные очищаются и помечаются как ошибка
- При очистке всех полей они снова активируются
CSS стили:
- Disabled поля: серый фон, пониженная прозрачность, запрещённый курсор
- Invalid поля: красная граница и shadow (Bootstrap стиль)
Валидация работает на обе стороны:
- Frontend JavaScript (instant feedback)
- Backend Python валидация (безопасность)
Файлы:
- products/templates/products/productkit_create.html
- products/templates/products/productkit_edit.html
- products/forms.py (документация)
Исправлены 4 проблемы:
1. Расчёт цены первого товара - улучшена валидация в getProductPrice и calculateFinalPrice
2. Отображение actual_price в Select2 вместо обычной цены
3. Количество по умолчанию = 1 для новых форм компонентов
4. Auto-select текста при клике на поле количества для удобства редактирования
Изменённые файлы:
- products/forms.py: добавлен __init__ в KitItemForm для quantity.initial = 1
- products/templates/includes/select2-product-init.html: обновлена formatSelectResult
- products/templates/productkit_create.html: добавлен focus handler для auto-select
- products/templates/productkit_edit.html: добавлен focus handler для auto-select
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
ПРОБЛЕМА:
При создании комплекта с несколькими товарами сохранялся только первый товар.
ПРИЧИНЫ И РЕШЕНИЯ:
1. Неправильный префикс в JavaScript (productkit_create.html)
- Динамически добавляемые формы создавались с префиксом kititem_set-
- Django ожидает префикс kititem-
- ИСПРАВЛЕНО: изменены все name атрибуты с kititem_set- на kititem-
2. NULL constraint для quantity (models.py)
- Поле KitItem.quantity было NOT NULL
- Пустые формы пытались сохраняться с NULL
- ИСПРАВЛЕНО: добавлены null=True, blank=True к полю quantity
3. Неправильная валидация пустых форм (forms.py)
- Не было логики для обработки пустых компонентов
- ИСПРАВЛЕНО: пустые формы получают quantity=None, заполненные требуют quantity>0
4. Неправильный порядок сохранения (productkit_views.py)
- Формсет не имел правильного prefixсе
- ИСПРАВЛЕНО: явно установлен prefix='kititem' везде (get_context_data, form_valid)
✅ РЕЗУЛЬТАТ: Теперь можно создавать комплекты с неограниченным количеством товаров
🧪 ТЕСТИРОВАНО:
- Комплект 0 товаров ✓
- Комплект 1 товар ✓
- Комплект 3 товара ✓
🤖 Generated with Claude Code
- Added 'sku' field to ProductKitForm meta fields list
- Added SKU label in form labels
- Added SKU widget styling in __init__ method with helpful placeholder
- Updated productkit_form.html template to display SKU field after name, before description
- Updated form field filtering to exclude 'sku' from dynamic loop to prevent duplication
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>