- Introduced Recipient model to manage order recipients separately from customers. - Updated Order model to link to Recipient, replacing recipient_name and recipient_phone fields. - Enhanced OrderForm to include recipient selection modes: customer, history, and new. - Added AJAX endpoint to fetch recipient history for customers. - Updated admin interface to manage recipients and display recipient information in order details. - Refactored address handling to accommodate new recipient logic. - Improved demo order creation to include random recipients.
225 lines
8.9 KiB
Python
225 lines
8.9 KiB
Python
"""
|
||
Сервис для работы с адресами и получателями заказов.
|
||
Содержит логику создания, обновления и управления адресами доставки и получателями.
|
||
"""
|
||
from ..models import Order, Address, Recipient
|
||
|
||
|
||
class AddressService:
|
||
"""Сервис для управления адресами доставки и получателями в заказах"""
|
||
|
||
@staticmethod
|
||
def create_address_from_form_data(form_data):
|
||
"""
|
||
Создает объект Address из данных формы.
|
||
|
||
Args:
|
||
form_data (dict): Словарь с данными из формы
|
||
- address_street
|
||
- address_building_number
|
||
- address_apartment_number (опционально)
|
||
- address_entrance (опционально)
|
||
- address_floor (опционально)
|
||
- address_intercom_code (опционально)
|
||
- address_delivery_instructions (опционально)
|
||
|
||
Returns:
|
||
Address: Новый объект адреса (не сохраненный в БД)
|
||
"""
|
||
address = Address(
|
||
street=form_data.get('address_street', ''),
|
||
building_number=form_data.get('address_building_number', ''),
|
||
apartment_number=form_data.get('address_apartment_number', ''),
|
||
entrance=form_data.get('address_entrance', ''),
|
||
floor=form_data.get('address_floor', ''),
|
||
intercom_code=form_data.get('address_intercom_code', ''),
|
||
delivery_instructions=form_data.get('address_delivery_instructions', ''),
|
||
confirm_address_with_recipient=form_data.get('address_confirm_with_recipient', False),
|
||
)
|
||
return address
|
||
|
||
@staticmethod
|
||
def create_recipient_from_form_data(form_data):
|
||
"""
|
||
Создает объект Recipient из данных формы.
|
||
|
||
Args:
|
||
form_data (dict): Словарь с данными из формы
|
||
- recipient_name
|
||
- recipient_phone
|
||
|
||
Returns:
|
||
Recipient: Новый объект получателя (не сохраненный в БД)
|
||
"""
|
||
recipient = Recipient(
|
||
name=form_data.get('recipient_name', ''),
|
||
phone=form_data.get('recipient_phone', ''),
|
||
)
|
||
return recipient
|
||
|
||
@staticmethod
|
||
def process_recipient_from_form(order, form_data):
|
||
"""
|
||
Обрабатывает получателя из данных формы заказа.
|
||
Создает нового Recipient или использует существующего в зависимости от режима.
|
||
|
||
Args:
|
||
order (Order): Объект заказа
|
||
form_data (dict): Все данные из формы
|
||
|
||
Returns:
|
||
Recipient or None: Получатель для привязки к заказу или None
|
||
"""
|
||
recipient_mode = form_data.get('recipient_mode')
|
||
|
||
# Если режим "покупатель = получатель" - возвращаем None
|
||
if recipient_mode == 'customer':
|
||
return None
|
||
|
||
# Если режим "выбрать из истории" - возвращаем выбранного получателя
|
||
if recipient_mode == 'history':
|
||
recipient_id = form_data.get('recipient_from_history')
|
||
if recipient_id:
|
||
try:
|
||
return Recipient.objects.get(pk=recipient_id)
|
||
except Recipient.DoesNotExist:
|
||
return None
|
||
|
||
# Если режим "новый получатель"
|
||
if recipient_mode == 'new':
|
||
name = form_data.get('recipient_name', '').strip()
|
||
phone = form_data.get('recipient_phone', '').strip()
|
||
|
||
if not name or not phone:
|
||
return None
|
||
|
||
# Проверяем, есть ли уже такой получатель в БД
|
||
existing_recipient = Recipient.objects.filter(
|
||
name=name,
|
||
phone=phone
|
||
).first()
|
||
|
||
if existing_recipient:
|
||
return existing_recipient
|
||
|
||
# Создаем нового получателя
|
||
recipient = AddressService.create_recipient_from_form_data(form_data)
|
||
return recipient
|
||
|
||
return None
|
||
|
||
@staticmethod
|
||
def process_address_from_form(order, form_data):
|
||
"""
|
||
Обрабатывает адрес из данных формы заказа.
|
||
Создает новый Address или использует существующий в зависимости от режима.
|
||
|
||
Args:
|
||
order (Order): Объект заказа
|
||
form_data (dict): Все данные из формы
|
||
|
||
Returns:
|
||
Address or None: Адрес для привязки к заказу или None
|
||
"""
|
||
address_mode = form_data.get('address_mode')
|
||
|
||
# Если режим "без адреса" - возвращаем None
|
||
if address_mode == 'empty':
|
||
return None
|
||
|
||
# Если режим "выбрать из истории" - возвращаем выбранный адрес
|
||
if address_mode == 'history':
|
||
address_id = form_data.get('address_from_history')
|
||
if address_id:
|
||
try:
|
||
return Address.objects.get(pk=address_id)
|
||
except Address.DoesNotExist:
|
||
return None
|
||
|
||
# Если режим "ввести новый адрес"
|
||
if address_mode == 'new':
|
||
# Проверяем обязательные поля
|
||
street = form_data.get('address_street', '').strip()
|
||
building_number = form_data.get('address_building_number', '').strip()
|
||
|
||
# Для автосохранения разрешаем сохранять адрес даже если не все поля заполнены
|
||
# Проверяем только что хотя бы одно поле адреса заполнено
|
||
has_any_address_data = any([
|
||
street,
|
||
building_number,
|
||
form_data.get('address_apartment_number', '').strip(),
|
||
form_data.get('address_entrance', '').strip(),
|
||
form_data.get('address_floor', '').strip(),
|
||
form_data.get('address_intercom_code', '').strip(),
|
||
form_data.get('address_delivery_instructions', '').strip(),
|
||
])
|
||
|
||
if not has_any_address_data:
|
||
# Если все поля адреса пустые, возвращаем None
|
||
return None
|
||
|
||
# Проверяем, есть ли уже такой адрес в БД (по основным полям)
|
||
existing_address = Address.objects.filter(
|
||
street=street,
|
||
building_number=building_number,
|
||
apartment_number=form_data.get('address_apartment_number', '').strip()
|
||
).first()
|
||
|
||
if existing_address:
|
||
return existing_address
|
||
|
||
# Создаем новый адрес
|
||
address = AddressService.create_address_from_form_data(form_data)
|
||
return address
|
||
|
||
return None
|
||
|
||
@staticmethod
|
||
def get_customer_address_history(customer):
|
||
"""
|
||
Получает список адресов из истории заказов клиента.
|
||
|
||
Args:
|
||
customer (Customer): Клиент
|
||
|
||
Returns:
|
||
QuerySet: Адреса, отсортированные по дате создания (новые первыми)
|
||
"""
|
||
customer_orders = Order.objects.filter(
|
||
customer=customer,
|
||
delivery_address__isnull=False
|
||
).order_by('-created_at')
|
||
|
||
addresses = Address.objects.filter(
|
||
orders__in=customer_orders
|
||
).distinct().order_by('-created_at')
|
||
|
||
return addresses
|
||
|
||
@staticmethod
|
||
def format_address_for_display(address):
|
||
"""
|
||
Форматирует адрес для отображения в списке.
|
||
|
||
Args:
|
||
address (Address): Объект адреса
|
||
|
||
Returns:
|
||
str: Форматированная строка адреса
|
||
"""
|
||
address_line = f"{address.street}, {address.building_number}"
|
||
|
||
if address.apartment_number:
|
||
address_line += f", кв. {address.apartment_number}"
|
||
|
||
details = []
|
||
if address.entrance:
|
||
details.append(f"подъезд {address.entrance}")
|
||
if address.floor:
|
||
details.append(f"этаж {address.floor}")
|
||
|
||
if details:
|
||
address_line += f" ({', '.join(details)})"
|
||
|
||
return address_line
|