refactor: Создать базовый класс BaseProductEntity и реструктурировать Product/ProductKit

Основные изменения:

## Модели (models.py)
- Создан абстрактный класс BaseProductEntity с общими полями:
  * Идентификация: name, sku, slug
  * Описания: description, short_description (новое поле)
  * Статус: is_active, timestamps, soft delete
  * Managers: objects, all_objects, active

- Product:
  * Унаследован от BaseProductEntity
  * sale_price переименован в price (основная цена)
  * Добавлено новое поле sale_price (цена со скидкой, nullable)
  * Добавлено property actual_price

- ProductKit:
  * Унаследован от BaseProductEntity
  * fixed_price переименован в price (ручная цена)
  * pricing_method: 'fixed' → 'manual'
  * Добавлено поле sale_price (цена со скидкой)
  * Добавлено поле cost_price (nullable)
  * Добавлены properties: calculated_price, actual_price
  * Обновлен calculate_price_with_substitutions()

## Forms (forms.py)
- ProductForm: добавлено short_description, price, sale_price
- ProductKitForm: добавлено short_description, cost_price, price, sale_price

## Admin (admin.py)
- ProductAdmin: обновлены list_display и fieldsets с новыми полями
- ProductKitAdmin: добавлены fieldsets, метод get_price_display()

## Templates
- product_form.html: добавлены поля price, sale_price, short_description
- product_detail.html: показывает зачеркнутую цену + скидку + бейджик "Акция"
- product_list.html: отображение цен со скидкой и бейджиком "Акция"
- all_products_list.html: единообразное отображение цен
- productkit_detail.html: отображение скидок с бейджиком "Акция"

## API (api_views.py)
- Обновлены все endpoints для использования поля price вместо sale_price

Результат: единообразная архитектура с поддержкой скидок, DRY-принцип,
логичные названия полей, красивое отображение акций в UI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-31 00:49:01 +03:00
parent aec884240e
commit d92045c4c4
9 changed files with 555 additions and 209 deletions

View File

@@ -45,7 +45,7 @@ def search_products_and_variants(request):
'id': product.id,
'text': f"{product.name} ({product.sku})" if product.sku else product.name,
'sku': product.sku,
'price': str(product.sale_price) if product.sale_price else None,
'price': str(product.price) if product.price else None,
'in_stock': product.in_stock,
'type': 'product'
}],
@@ -74,7 +74,7 @@ def search_products_and_variants(request):
# Показываем последние добавленные активные товары
products = Product.objects.filter(is_active=True)\
.order_by('-created_at')[:page_size]\
.values('id', 'name', 'sku', 'sale_price', 'in_stock')
.values('id', 'name', 'sku', 'price', 'in_stock')
for product in products:
text = product['name']
@@ -85,7 +85,7 @@ def search_products_and_variants(request):
'id': product['id'],
'text': text,
'sku': product['sku'],
'price': str(product['sale_price']) if product['sale_price'] else None,
'price': str(product['price']) if product['price'] else None,
'in_stock': product['in_stock']
})
@@ -147,7 +147,7 @@ def search_products_and_variants(request):
start = (page - 1) * page_size
end = start + page_size
products = products_query[start:end].values('id', 'name', 'sku', 'sale_price', 'in_stock')
products = products_query[start:end].values('id', 'name', 'sku', 'price', 'in_stock')
for product in products:
text = product['name']
@@ -158,7 +158,7 @@ def search_products_and_variants(request):
'id': product['id'],
'text': text,
'sku': product['sku'],
'price': str(product['sale_price']) if product['sale_price'] else None,
'price': str(product['price']) if product['price'] else None,
'in_stock': product['in_stock'],
'type': 'product'
})