feat(products): маркетинговые флаги is_new, is_popular, is_special
- Добавлены поля в BaseProductEntity (наследуются в Product, ProductKit) - Исправлен формат флагов в Recommerce mappers (1/0 вместо true/false) - Добавлены чекбоксы в админку Product и ProductKit - special = is_special OR has_discount (ручное + автоматическое) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,13 +90,16 @@ def to_api_product(
|
|||||||
if photo.image:
|
if photo.image:
|
||||||
data[f'images[{idx}]'] = photo.image.url
|
data[f'images[{idx}]'] = photo.image.url
|
||||||
|
|
||||||
# Обработка флагов товара (как строки "true"/"false" согласно документации API)
|
# Обработка флагов товара (формат: 1/0 для Recommerce API)
|
||||||
if hasattr(product, 'is_new'):
|
if hasattr(product, 'is_new'):
|
||||||
data['is_new'] = "true" if product.is_new else "false"
|
data['is_new'] = 1 if product.is_new else 0
|
||||||
if hasattr(product, 'is_popular'):
|
if hasattr(product, 'is_popular'):
|
||||||
data['is_popular'] = "true" if product.is_popular else "false"
|
data['is_popular'] = 1 if product.is_popular else 0
|
||||||
# special - автоматически при наличии скидки (формат: 1/0, не is_special)
|
# special - из модели is_special ИЛИ автоматически при скидке
|
||||||
data['special'] = 1 if has_discount else 0
|
if hasattr(product, 'is_special'):
|
||||||
|
data['special'] = 1 if (product.is_special or has_discount) else 0
|
||||||
|
else:
|
||||||
|
data['special'] = 1 if has_discount else 0
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ class ProductAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
|||||||
'description': 'Себестоимость рассчитывается автоматически на основе партий товара (FIFO метод). Редактировать вручную невозможно.'
|
'description': 'Себестоимость рассчитывается автоматически на основе партий товара (FIFO метод). Редактировать вручную невозможно.'
|
||||||
}),
|
}),
|
||||||
('Дополнительно', {
|
('Дополнительно', {
|
||||||
'fields': ('tags', 'variant_groups', 'status')
|
'fields': ('tags', 'variant_groups', 'status', 'is_new', 'is_popular', 'is_special')
|
||||||
}),
|
}),
|
||||||
('Архивирование', {
|
('Архивирование', {
|
||||||
'fields': ('archived_at', 'archived_by'),
|
'fields': ('archived_at', 'archived_by'),
|
||||||
@@ -608,7 +608,7 @@ class ProductKitAdmin(TenantAdminOnlyMixin, admin.ModelAdmin):
|
|||||||
'description': 'Временные комплекты создаются для конкретных заказов и не показываются в каталоге.'
|
'description': 'Временные комплекты создаются для конкретных заказов и не показываются в каталоге.'
|
||||||
}),
|
}),
|
||||||
('Дополнительно', {
|
('Дополнительно', {
|
||||||
'fields': ('tags', 'status')
|
'fields': ('tags', 'status', 'is_new', 'is_popular', 'is_special')
|
||||||
}),
|
}),
|
||||||
('Архивирование', {
|
('Архивирование', {
|
||||||
'fields': ('archived_at', 'archived_by'),
|
'fields': ('archived_at', 'archived_by'),
|
||||||
|
|||||||
58
myproject/products/migrations/0003_add_marketing_flags.py
Normal file
58
myproject/products/migrations/0003_add_marketing_flags.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Generated by Django 5.0.10 on 2026-01-12 21:26
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('products', '0002_alter_configurableproduct_archived_by_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='configurableproduct',
|
||||||
|
name='is_new',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как новый товар', verbose_name='Новинка'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='configurableproduct',
|
||||||
|
name='is_popular',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как популярный товар', verbose_name='Популярный'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='configurableproduct',
|
||||||
|
name='is_special',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как спецпредложение (акция)', verbose_name='Спецпредложение'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='is_new',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как новый товар', verbose_name='Новинка'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='is_popular',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как популярный товар', verbose_name='Популярный'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='product',
|
||||||
|
name='is_special',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как спецпредложение (акция)', verbose_name='Спецпредложение'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='productkit',
|
||||||
|
name='is_new',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как новый товар', verbose_name='Новинка'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='productkit',
|
||||||
|
name='is_popular',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как популярный товар', verbose_name='Популярный'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='productkit',
|
||||||
|
name='is_special',
|
||||||
|
field=models.BooleanField(default=False, help_text='Отображать как спецпредложение (акция)', verbose_name='Спецпредложение'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -165,6 +165,23 @@ class BaseProductEntity(models.Model):
|
|||||||
verbose_name="Статус"
|
verbose_name="Статус"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Маркетинговые флаги для внешних площадок (Recommerce и др.)
|
||||||
|
is_new = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name="Новинка",
|
||||||
|
help_text="Отображать как новый товар"
|
||||||
|
)
|
||||||
|
is_popular = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name="Популярный",
|
||||||
|
help_text="Отображать как популярный товар"
|
||||||
|
)
|
||||||
|
is_special = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name="Спецпредложение",
|
||||||
|
help_text="Отображать как спецпредложение (акция)"
|
||||||
|
)
|
||||||
|
|
||||||
# Временные метки
|
# Временные метки
|
||||||
created_at = models.DateTimeField(
|
created_at = models.DateTimeField(
|
||||||
auto_now_add=True,
|
auto_now_add=True,
|
||||||
|
|||||||
Reference in New Issue
Block a user