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:
@@ -34,8 +34,7 @@ class DiscountApplier:
|
||||
from discounts.services.calculator import DiscountCalculator
|
||||
|
||||
# Удаляем предыдущую скидку на заказ
|
||||
if order.applied_promo_code:
|
||||
DiscountApplier._remove_order_discount_only(order)
|
||||
DiscountApplier._remove_order_discount_only(order)
|
||||
|
||||
# Рассчитываем скидку
|
||||
result = DiscountCalculator.calculate_order_discount(order, promo_code)
|
||||
@@ -50,21 +49,7 @@ class DiscountApplier:
|
||||
discounts_data = result['discounts']
|
||||
total_amount = result['total_amount']
|
||||
|
||||
# Применяем первую скидку в applied_discount (для обратной совместимости с Order)
|
||||
if discounts_data:
|
||||
first_discount = discounts_data[0]['discount']
|
||||
order.applied_discount = first_discount
|
||||
order.applied_promo_code = promo.code
|
||||
order.discount_amount = total_amount
|
||||
order.save(update_fields=['applied_discount', 'applied_promo_code', 'discount_amount'])
|
||||
|
||||
# Пересчитываем total_amount
|
||||
order.calculate_total()
|
||||
|
||||
# Регистрируем использование промокода
|
||||
promo.record_usage(order.customer)
|
||||
|
||||
# Создаем записи о применении для каждой скидки
|
||||
# Создаем записи о применении для каждой скидки в DiscountApplication
|
||||
for disc_data in discounts_data:
|
||||
discount = disc_data['discount']
|
||||
amount = disc_data['amount']
|
||||
@@ -85,6 +70,12 @@ class DiscountApplier:
|
||||
discount.current_usage_count += 1
|
||||
discount.save(update_fields=['current_usage_count'])
|
||||
|
||||
# Пересчитываем total_amount (использует DiscountApplication)
|
||||
order.calculate_total()
|
||||
|
||||
# Регистрируем использование промокода
|
||||
promo.record_usage(order.customer)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'discounts': discounts_data,
|
||||
@@ -124,12 +115,6 @@ class DiscountApplier:
|
||||
if order_result['discounts'] and not order_result['error']:
|
||||
total_order_amount = order_result['total_amount']
|
||||
|
||||
# Сохраняем первую скидку в applied_discount (для совместимости)
|
||||
first_discount_data = order_result['discounts'][0]
|
||||
order.applied_discount = first_discount_data['discount']
|
||||
order.discount_amount = total_order_amount
|
||||
order.save(update_fields=['applied_discount', 'discount_amount'])
|
||||
|
||||
# Создаем записи о применении для всех скидок
|
||||
for disc_data in order_result['discounts']:
|
||||
discount = disc_data['discount']
|
||||
@@ -167,12 +152,6 @@ class DiscountApplier:
|
||||
if item_result['discounts']:
|
||||
total_item_amount = item_result['total_amount']
|
||||
|
||||
# Сохраняем первую скидку в applied_discount (для совместимости)
|
||||
first_discount_data = item_result['discounts'][0]
|
||||
item.applied_discount = first_discount_data['discount']
|
||||
item.discount_amount = total_item_amount
|
||||
item.save(update_fields=['applied_discount', 'discount_amount'])
|
||||
|
||||
# Создаем записи о применении для всех скидок
|
||||
base_amount = item.price * item.quantity
|
||||
for disc_data in item_result['discounts']:
|
||||
@@ -186,7 +165,7 @@ class DiscountApplier:
|
||||
target='order_item',
|
||||
base_amount=base_amount,
|
||||
discount_amount=amount,
|
||||
final_amount=item.get_total_price(),
|
||||
final_amount=base_amount - amount,
|
||||
customer=order.customer,
|
||||
applied_by=user
|
||||
)
|
||||
@@ -216,14 +195,6 @@ class DiscountApplier:
|
||||
Args:
|
||||
order: Order
|
||||
"""
|
||||
DiscountApplier._remove_order_discount_only(order)
|
||||
|
||||
# Удаляем скидки с позиций
|
||||
order.items.update(
|
||||
applied_discount=None,
|
||||
discount_amount=Decimal('0')
|
||||
)
|
||||
|
||||
# Удаляем записи о применении
|
||||
from discounts.models import DiscountApplication
|
||||
DiscountApplication.objects.filter(order=order).delete()
|
||||
@@ -265,14 +236,6 @@ class DiscountApplier:
|
||||
# Рассчитываем сумму
|
||||
discount_amount = discount.calculate_discount_amount(Decimal(order.subtotal))
|
||||
|
||||
# Применяем к заказу
|
||||
order.applied_discount = discount
|
||||
order.discount_amount = discount_amount
|
||||
order.save(update_fields=['applied_discount', 'discount_amount'])
|
||||
|
||||
# Пересчитываем total_amount
|
||||
order.calculate_total()
|
||||
|
||||
# Создаем запись о применении
|
||||
DiscountApplication.objects.create(
|
||||
order=order,
|
||||
@@ -289,6 +252,9 @@ class DiscountApplier:
|
||||
discount.current_usage_count += 1
|
||||
discount.save(update_fields=['current_usage_count'])
|
||||
|
||||
# Пересчитываем total_amount
|
||||
order.calculate_total()
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'discount_amount': discount_amount
|
||||
@@ -307,7 +273,5 @@ class DiscountApplier:
|
||||
# Удаляем записи о применении скидок к заказу
|
||||
DiscountApplication.objects.filter(order=order, target='order').delete()
|
||||
|
||||
order.applied_discount = None
|
||||
order.applied_promo_code = None
|
||||
order.discount_amount = Decimal('0')
|
||||
order.save(update_fields=['applied_discount', 'applied_promo_code', 'discount_amount'])
|
||||
# Пересчитываем (order.discount_amount теперь свойство, берущее из DiscountApplication)
|
||||
order.calculate_total()
|
||||
|
||||
Reference in New Issue
Block a user