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:
@@ -141,10 +141,13 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if item.item_type == 'product' %}
|
||||
{{ item.sale_price|floatformat:2 }} руб.
|
||||
{% if item.sale_price %}
|
||||
<span class="text-decoration-line-through text-muted small">{{ item.price|floatformat:2 }} руб.</span>
|
||||
<br>
|
||||
<strong class="text-danger">{{ item.sale_price|floatformat:2 }} руб.</strong>
|
||||
<span class="badge bg-danger ms-1">Акция</span>
|
||||
{% else %}
|
||||
{{ item.get_sale_price|floatformat:2 }} руб.
|
||||
<strong>{{ item.actual_price|floatformat:2 }} руб.</strong>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -158,8 +158,16 @@
|
||||
<td>{{ product.cost_price }} руб.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Цена продажи:</th>
|
||||
<td>{{ product.sale_price }} руб.</td>
|
||||
<th>Цена:</th>
|
||||
<td>
|
||||
{% if product.sale_price %}
|
||||
<span class="text-decoration-line-through text-muted">{{ product.price }} руб.</span>
|
||||
<strong class="text-danger fs-5">{{ product.sale_price }} руб.</strong>
|
||||
<span class="badge bg-danger ms-2">Акция</span>
|
||||
{% else %}
|
||||
<strong class="fs-5">{{ product.price }} руб.</strong>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>В наличии:</th>
|
||||
|
||||
@@ -79,6 +79,16 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Краткое описание -->
|
||||
<div class="mb-3">
|
||||
<label for="id_short_description" class="form-label">Краткое описание</label>
|
||||
{{ form.short_description }}
|
||||
<small class="form-text text-muted">Используется для карточек товаров, превью и площадок</small>
|
||||
{% if form.short_description.errors %}
|
||||
<div class="text-danger">{{ form.short_description.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Единица измерения и Статус в один ряд -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-8">
|
||||
@@ -114,7 +124,7 @@
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
{{ form.cost_price.label_tag }}
|
||||
<label for="id_cost_price" class="form-label">Себестоимость</label>
|
||||
{{ form.cost_price }}
|
||||
{% if form.cost_price.help_text %}
|
||||
<small class="form-text text-muted">{{ form.cost_price.help_text }}</small>
|
||||
@@ -124,11 +134,20 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ form.sale_price.label_tag }}
|
||||
{{ form.sale_price }}
|
||||
{% if form.sale_price.help_text %}
|
||||
<small class="form-text text-muted">{{ form.sale_price.help_text }}</small>
|
||||
<label for="id_price" class="form-label fw-bold">Основная цена <span class="text-danger">*</span></label>
|
||||
{{ form.price }}
|
||||
<small class="form-text text-muted">Цена продажи товара</small>
|
||||
{% if form.price.errors %}
|
||||
<div class="text-danger">{{ form.price.errors }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="id_sale_price" class="form-label">Цена со скидкой</label>
|
||||
{{ form.sale_price }}
|
||||
<small class="form-text text-muted">Необязательно. Если задана, товар будет продаваться по этой цене (дешевле основной)</small>
|
||||
{% if form.sale_price.errors %}
|
||||
<div class="text-danger">{{ form.sale_price.errors }}</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -50,7 +50,16 @@
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ product.sale_price }} руб.</td>
|
||||
<td>
|
||||
{% if product.sale_price %}
|
||||
<span class="text-decoration-line-through text-muted small">{{ product.price }} руб.</span>
|
||||
<br>
|
||||
<strong class="text-danger">{{ product.sale_price }} руб.</strong>
|
||||
<span class="badge bg-danger ms-1">Акция</span>
|
||||
{% else %}
|
||||
<strong>{{ product.price }} руб.</strong>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product.in_stock %}
|
||||
<span class="badge bg-success"><i class="bi bi-check-circle"></i> В наличии</span>
|
||||
|
||||
@@ -47,9 +47,15 @@
|
||||
</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt class="col-sm-4">Цена продажи:</dt>
|
||||
<dt class="col-sm-4">Цена:</dt>
|
||||
<dd class="col-sm-8">
|
||||
<strong class="text-success fs-5">{{ kit.get_sale_price|floatformat:2 }} ₽</strong>
|
||||
{% if kit.sale_price %}
|
||||
<span class="text-decoration-line-through text-muted">{{ kit.calculated_price|floatformat:2 }} ₽</span>
|
||||
<strong class="text-danger fs-5">{{ kit.sale_price|floatformat:2 }} ₽</strong>
|
||||
<span class="badge bg-danger ms-2">Акция</span>
|
||||
{% else %}
|
||||
<strong class="text-success fs-5">{{ kit.actual_price|floatformat:2 }} ₽</strong>
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-4">Себестоимость:</dt>
|
||||
@@ -62,9 +68,9 @@
|
||||
<span class="badge bg-info text-dark">{{ kit.get_pricing_method_display }}</span>
|
||||
</dd>
|
||||
|
||||
{% if kit.fixed_price %}
|
||||
<dt class="col-sm-4">Фиксированная цена:</dt>
|
||||
<dd class="col-sm-8">{{ kit.fixed_price }} ₽</dd>
|
||||
{% if kit.price %}
|
||||
<dt class="col-sm-4">Ручная цена:</dt>
|
||||
<dd class="col-sm-8">{{ kit.price }} ₽</dd>
|
||||
{% endif %}
|
||||
|
||||
{% if kit.markup_percent %}
|
||||
|
||||
Reference in New Issue
Block a user