feat(discounts, orders): рефакторинг системы скидок - единый источник правды
- Добавлен combine_mode в форму создания/редактирования скидок - Добавлена колонка "Объединение" в список скидок с иконками - Добавлен фильтр по режиму объединения скидок - Добавлена валидация: только одна exclusive скидка на заказ - Удалены дублирующие поля из Order и OrderItem: - applied_discount, applied_promo_code, discount_amount - Скидки теперь хранятся только в DiscountApplication - Добавлены свойства для обратной совместимости Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -69,29 +69,10 @@ class Order(models.Model):
|
||||
help_text="Общая сумма заказа"
|
||||
)
|
||||
|
||||
# Скидки
|
||||
applied_discount = models.ForeignKey(
|
||||
'discounts.Discount',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='orders',
|
||||
verbose_name="Примененная скидка"
|
||||
)
|
||||
|
||||
discount_amount = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
default=0,
|
||||
verbose_name="Сумма скидки"
|
||||
)
|
||||
|
||||
applied_promo_code = models.CharField(
|
||||
max_length=50,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Использованный промокод"
|
||||
)
|
||||
# === СКИДКИ ===
|
||||
# Скидки хранятся в модели DiscountApplication (через related_name='discount_applications')
|
||||
# Старые поля applied_discount, discount_amount, applied_promo_code УДАЛЕНЫ
|
||||
# Используйте свойства ниже для доступа к скидкам
|
||||
|
||||
# Частичная оплата
|
||||
amount_paid = models.DecimalField(
|
||||
@@ -407,6 +388,7 @@ class Order(models.Model):
|
||||
"""
|
||||
Пересчитывает итоговую сумму заказа.
|
||||
total_amount = subtotal + delivery_cost - discount_amount
|
||||
Скидка берётся из DiscountApplication
|
||||
"""
|
||||
from decimal import Decimal
|
||||
|
||||
@@ -417,7 +399,7 @@ class Order(models.Model):
|
||||
if hasattr(self, 'delivery'):
|
||||
delivery_cost = self.delivery.cost
|
||||
|
||||
# Вычитаем скидку на весь заказ (если есть)
|
||||
# Вычитаем скидку на весь заказ (из DiscountApplication через свойство)
|
||||
order_discount = Decimal(str(self.discount_amount)) if self.discount_amount else Decimal('0')
|
||||
|
||||
self.total_amount = subtotal + delivery_cost - order_discount
|
||||
@@ -432,6 +414,42 @@ class Order(models.Model):
|
||||
self.delivery.cost = 0
|
||||
self.delivery.save(update_fields=['cost'])
|
||||
|
||||
# === Свойства для доступа к скидкам (через DiscountApplication) ===
|
||||
|
||||
@property
|
||||
def order_discounts(self):
|
||||
"""Скидки на заказ (QuerySet DiscountApplication с target='order')"""
|
||||
from discounts.models import DiscountApplication
|
||||
return self.discount_applications.filter(target='order').select_related('discount', 'promo_code')
|
||||
|
||||
@property
|
||||
def item_discounts(self):
|
||||
"""Скидки на позиции (QuerySet DiscountApplication с target='order_item')"""
|
||||
from discounts.models import DiscountApplication
|
||||
return self.discount_applications.filter(target='order_item').select_related('discount', 'order_item')
|
||||
|
||||
@property
|
||||
def discount_amount(self):
|
||||
"""Общая сумма скидки на заказ"""
|
||||
from decimal import Decimal
|
||||
return self.order_discounts.aggregate(
|
||||
total=models.Sum('discount_amount')
|
||||
)['total'] or Decimal('0')
|
||||
|
||||
@property
|
||||
def applied_discount(self):
|
||||
"""Первая применённая скидка (для обратной совместимости)"""
|
||||
first = self.order_discounts.first()
|
||||
return first.discount if first else None
|
||||
|
||||
@property
|
||||
def applied_promo_code(self):
|
||||
"""Промокод из первой записи (для обратной совместимости)"""
|
||||
first = self.order_discounts.first()
|
||||
if first and first.promo_code:
|
||||
return first.promo_code.code
|
||||
return None
|
||||
|
||||
# === Свойства обратной совместимости для доступа к полям доставки ===
|
||||
# Эти свойства обеспечивают доступ к полям Delivery через Order для обратной совместимости
|
||||
# после рефакторинга, когда поля доставки были перенесены в отдельную модель Delivery
|
||||
|
||||
Reference in New Issue
Block a user