Реализована система управления стоимостью доставки и исправлен баг выбора клиента
Изменения: 1. **Стоимость доставки (автоматическая/ручная)**: - Добавлено поле `is_custom_delivery_cost` в модель Order для отслеживания ручной стоимости - Создан сервис DeliveryCostCalculator для автоматического расчета стоимости доставки - Реализована логика: бесплатная доставка от 100 руб., иначе 15 руб. - В форме поле "Ручная стоимость доставки" - если заполнено, используется ручная стоимость, если пустое - автоматический расчет - Добавлены методы Order.get_delivery_cost(), set_delivery_cost(), reset_delivery_cost(), recalculate_delivery_cost() 2. **Исправление бага выбора клиента в Select2**: - Удален избыточный обработчик события select2:opening, который блокировал клики - Добавлены проверки на наличие e.params.data в обработчиках select2:selecting и select2:select - Теперь выбор клиента работает корректно, создается черновик заказа и происходит редирект 3. **Опциональные поля адреса**: - Поля recipient_name, street, building_number в модели Address сделаны необязательными (blank=True, null=True) - Обновлены методы __str__ и full_address для безопасной работы с None значениями 4. **UI улучшения**: - Удалена звездочка обязательности с полей адреса - Добавлена подсказка под полем ручной стоимости доставки о правилах автоматического расчета 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
95
myproject/orders/services/delivery_cost_calculator.py
Normal file
95
myproject/orders/services/delivery_cost_calculator.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Сервис для расчета стоимости доставки.
|
||||
Содержит расширяемую логику вычисления на основе различных условий.
|
||||
"""
|
||||
from decimal import Decimal
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from orders.models import Order
|
||||
|
||||
|
||||
class DeliveryCostCalculator:
|
||||
"""
|
||||
Калькулятор стоимости доставки.
|
||||
Применяет различные правила для автоматического расчета.
|
||||
"""
|
||||
|
||||
# Константы для правил расчета
|
||||
FREE_DELIVERY_THRESHOLD = Decimal('100.00') # Бесплатная доставка от суммы
|
||||
BASE_DELIVERY_COST = Decimal('15.00') # Базовая стоимость доставки
|
||||
MIN_DELIVERY_COST = Decimal('0.00') # Минимальная стоимость
|
||||
|
||||
@classmethod
|
||||
def calculate(cls, order: 'Order') -> Decimal:
|
||||
"""
|
||||
Рассчитывает стоимость доставки на основе условий заказа.
|
||||
|
||||
Args:
|
||||
order: Заказ для расчета
|
||||
|
||||
Returns:
|
||||
Decimal: Рассчитанная стоимость доставки
|
||||
"""
|
||||
# Самовывоз - доставка бесплатная
|
||||
if not order.is_delivery:
|
||||
return cls.MIN_DELIVERY_COST
|
||||
|
||||
# Рассчитываем сумму товаров
|
||||
items_total = sum(
|
||||
item.get_total_price()
|
||||
for item in order.items.all()
|
||||
)
|
||||
|
||||
# Применяем правила расчета
|
||||
cost = cls._apply_calculation_rules(order, items_total)
|
||||
|
||||
return cost
|
||||
|
||||
@classmethod
|
||||
def _apply_calculation_rules(cls, order: 'Order', items_total: Decimal) -> Decimal:
|
||||
"""
|
||||
Применяет правила расчета стоимости доставки.
|
||||
Этот метод легко расширить для добавления новых правил.
|
||||
|
||||
Args:
|
||||
order: Заказ
|
||||
items_total: Сумма товаров в заказе
|
||||
|
||||
Returns:
|
||||
Decimal: Стоимость доставки
|
||||
"""
|
||||
# Правило 1: Бесплатная доставка при заказе от определенной суммы
|
||||
if items_total >= cls.FREE_DELIVERY_THRESHOLD:
|
||||
return cls.MIN_DELIVERY_COST
|
||||
|
||||
# Правило 2: Базовая стоимость доставки
|
||||
cost = cls.BASE_DELIVERY_COST
|
||||
|
||||
# Правило 3: Можно добавить расчет по адресу
|
||||
# if order.delivery_address:
|
||||
# cost += cls._calculate_distance_cost(order.delivery_address)
|
||||
|
||||
# Правило 4: Можно добавить надбавку за срочность
|
||||
# if cls._is_urgent_delivery(order):
|
||||
# cost *= Decimal('1.5')
|
||||
|
||||
return cost
|
||||
|
||||
@classmethod
|
||||
def _calculate_distance_cost(cls, address) -> Decimal:
|
||||
"""
|
||||
Рассчитывает надбавку за расстояние.
|
||||
Placeholder для будущей реализации с геокодингом.
|
||||
"""
|
||||
# TODO: Интеграция с картами для расчета расстояния
|
||||
return Decimal('0.00')
|
||||
|
||||
@classmethod
|
||||
def _is_urgent_delivery(cls, order: 'Order') -> bool:
|
||||
"""
|
||||
Проверяет, является ли доставка срочной.
|
||||
"""
|
||||
# TODO: Логика определения срочности
|
||||
return False
|
||||
Reference in New Issue
Block a user