Files
shopship/apps/orders/api/services.py
T
2026-08-24 15:54:08 +03:30

84 lines
3.3 KiB
Python

import re
import uuid
from django.db import transaction
from apps.account.models import User
from apps.banker.models import Contact
from apps.messaging.api.services import BulkMessageService
from apps.messaging.models import Channel
from apps.orders.models import Order, OrderStage, OrderStageLog
_FIELD_PATTERN = re.compile(r"\{(.*?)\}")
class OrderStageService:
@staticmethod
def _render(order: Order, stage: OrderStage, extra_input_value: str = "") -> str:
body = stage.template.body if stage.template else ""
values = {
"نام": order.customer_name,
"شماره": order.customer_phone,
"کد پیگیری": order.tracking_code,
"مرحله": stage.label,
"ورودی": extra_input_value,
}
return _FIELD_PATTERN.sub(lambda m: values.get(m.group(1), m.group(0)), body)
@staticmethod
def _upsert_contact(user: User, order: Order) -> Contact:
contact = Contact.objects.filter(user=user, phone=order.customer_phone).first()
if contact:
return contact
return Contact.objects.create(
id=str(uuid.uuid4()), user=user, name=order.customer_name, phone=order.customer_phone
)
@staticmethod
@transaction.atomic
def advance(user: User, order_id: str, extra_input_value: str = "") -> Order:
order = Order.objects.select_for_update().get(pk=order_id, user=user)
if order.is_completed:
raise ValueError("این سفارش قبلا به آخرین مرحله رسیده است.")
stages = list(OrderStage.objects.filter(user=user).order_by("sort_order"))
if not stages:
raise ValueError("اول باید حداقل یک مرحله برای پیگیری سفارش تعریف کنی.")
if order.current_stage_id is None:
next_stage = stages[0]
else:
current_index = next((i for i, s in enumerate(stages) if s.id == order.current_stage_id), None)
if current_index is None or current_index + 1 >= len(stages):
raise ValueError("این سفارش قبلا به آخرین مرحله رسیده است.")
next_stage = stages[current_index + 1]
extra_input_value = (extra_input_value or "").strip()
if next_stage.requires_extra_input and not extra_input_value:
label = next_stage.extra_input_label or "ورودی این مرحله"
raise ValueError(f"برای این مرحله باید «{label}» را وارد کنی.")
contact = OrderStageService._upsert_contact(user, order)
rendered = OrderStageService._render(order, next_stage, extra_input_value)
if rendered:
BulkMessageService.create_and_dispatch(
user=user,
channels=[Channel.SMS],
contact_ids=[contact.id],
body_override=rendered,
)
order.current_stage = next_stage
order.is_completed = next_stage.id == stages[-1].id
order.save(update_fields=["current_stage", "is_completed", "updated_at"])
OrderStageLog.objects.create(
id=str(uuid.uuid4()),
order=order,
stage=next_stage,
stage_label=next_stage.label,
message_body=rendered,
extra_input_value=extra_input_value,
)
return order