Files
octopus/myproject/orders/services/order_status_service.py
Andrey Smakotin c7875f147c Implement flexible order status management system
Features:
- Created OrderStatus model for managing statuses per tenant
- Added system-level statuses: draft, new, confirmed, in_assembly, in_delivery, completed, return, cancelled
- Implemented CRUD views for managing order statuses
- Created OrderStatusService with status transitions and business logic hooks
- Updated Order model to use ForeignKey to OrderStatus
- Added is_returned flag for tracking returned orders
- Updated filters to work with new OrderStatus model
- Created management command for status initialization
- Added HTML templates for status list, form, and confirmation
- Fixed views.py to use OrderStatus instead of removed STATUS_CHOICES

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 16:29:50 +03:00

221 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Сервис для управления статусами заказов.
Содержит бизнес-логику для работы со статусами и их переходами.
"""
from django.db import transaction
from orders.models import OrderStatus, Order
class OrderStatusService:
"""Сервис для работы со статусами заказов"""
@staticmethod
def get_default_status():
"""
Возвращает статус по умолчанию для новых заказов ('new')
"""
try:
return OrderStatus.objects.get(code='new', is_system=True)
except OrderStatus.DoesNotExist:
return None
@staticmethod
def get_draft_status():
"""Возвращает системный статус 'draft' (черновик)"""
try:
return OrderStatus.objects.get(code='draft', is_system=True)
except OrderStatus.DoesNotExist:
return None
@staticmethod
def get_system_status(code):
"""Получить системный статус по коду"""
try:
return OrderStatus.objects.get(code=code, is_system=True)
except OrderStatus.DoesNotExist:
return None
@staticmethod
def create_default_statuses():
"""
Создает системные статусы для тенанта.
Вызывается при первом использовании или миграции.
"""
default_statuses = [
{
'code': 'draft',
'name': 'Черновик',
'label': 'Черновик',
'is_system': True,
'order': 0,
'color': '#9E9E9E',
'description': 'Заказ находится в процессе создания/редактирования'
},
{
'code': 'new',
'name': 'Новый',
'label': 'Новый',
'is_system': True,
'order': 10,
'color': '#2196F3',
'description': 'Новый заказ, ожидающий обработки'
},
{
'code': 'confirmed',
'name': 'Подтвержден',
'label': 'Подтвержден',
'is_system': True,
'order': 20,
'color': '#FF9800',
'description': 'Заказ подтвержден и одобрен'
},
{
'code': 'in_assembly',
'name': 'В сборке',
'label': 'В сборке',
'is_system': True,
'order': 30,
'color': '#FF9800',
'description': 'Заказ находится в процессе сборки/подготовки'
},
{
'code': 'in_delivery',
'name': 'В доставке',
'label': 'В доставке',
'is_system': True,
'order': 40,
'color': '#9C27B0',
'description': 'Заказ в пути к клиенту'
},
{
'code': 'completed',
'name': 'Выполнен',
'label': 'Выполнен',
'is_system': True,
'is_positive_end': True,
'order': 50,
'color': '#4CAF50',
'description': 'Заказ успешно доставлен/выполнен'
},
{
'code': 'return',
'name': 'Возврат',
'label': 'Возврат',
'is_system': True,
'order': 60,
'color': '#FF5722',
'description': 'Заказ возвращен клиентом'
},
{
'code': 'cancelled',
'name': 'Отменен',
'label': 'Отменен',
'is_system': True,
'is_negative_end': True,
'order': 70,
'color': '#F44336',
'description': 'Заказ отменен'
},
]
for status_data in default_statuses:
OrderStatus.objects.get_or_create(
code=status_data['code'],
defaults=status_data
)
@staticmethod
@transaction.atomic
def change_order_status(order, new_status, user, notes=""):
"""
Меняет статус заказа и выполняет соответствующую бизнес-логику.
Args:
order (Order): Экземпляр заказа
new_status (OrderStatus): Новый статус
user (CustomUser): Пользователь, делающий изменение
notes (str): Опциональные заметки
Returns:
Order: Обновленный экземпляр заказа
Raises:
ValueError: Если статус не может быть применен
"""
old_status = order.status
order.status = new_status
order.modified_by = user
order.save()
# Запустить бизнес-логику в зависимости от нового статуса
if new_status.code == 'completed':
_handle_order_completion(order, user)
elif new_status.code == 'cancelled':
_handle_order_cancellation(order, old_status, user)
elif new_status.code == 'return':
_handle_order_return(order, user)
return order
@staticmethod
def get_all_statuses():
"""Возвращает все статусы, отсортированные по порядку"""
return OrderStatus.objects.all().order_by('order', 'name')
@staticmethod
def get_system_statuses():
"""Возвращает только системные статусы"""
return OrderStatus.objects.filter(is_system=True).order_by('order')
@staticmethod
def get_custom_statuses():
"""Возвращает только пользовательские статусы"""
return OrderStatus.objects.filter(is_system=False).order_by('order', 'name')
def _handle_order_completion(order, user):
"""
Обработка при переводе в статус 'Выполнен'.
Здесь происходит списание товаров со склада.
TODO: Интеграция с inventory приложением
"""
# from inventory.services import InventoryService
# InventoryService.process_order_completion(order)
pass
def _handle_order_cancellation(order, old_status, user):
"""
Обработка при переводе в статус 'Отменен'.
Если заказ был выполнен - возвращаем товары и деньги.
"""
if old_status and old_status.code == 'completed':
# Заказ был выполнен - нужно вернуть товары и деньги
order.is_returned = True
order.save()
# TODO: Интеграция с inventory - возврат товаров
# InventoryService.process_order_return(order)
# TODO: Интеграция с платежами - создать возврат
# PaymentService.create_refund(order)
else:
# Заказ отменен до выполнения - просто отменить резервы
# TODO: InventoryService.cancel_order_reservation(order)
pass
def _handle_order_return(order, user):
"""
Обработка при переводе в статус 'Возврат'.
Это промежуточный статус перед окончательной отменой.
"""
order.is_returned = True
order.save()
# TODO: Интеграция с inventory - вернуть товары на склад
# InventoryService.process_order_return(order)