IntakePayload 新增 14 个字段覆盖完整志愿填报偏好: - 学校地域/类型偏好 (school_region_preferences / school_preference_types) - 目标学校/不喜欢的专业 (target_schools / disliked_majors) - 优先策略/毕业计划/学费偏好/就业地区偏好 - 家庭背景/行业资源/额外备注 - 兴趣评估三字段 (type/result/notes) - candidate_province 提交时必填(与 portal 表单对齐) public_flow / deletion_service 同步更新字段引用 requirements-dev: 补 httpx2 (HTTP/2 测试支持)
118 lines
3.2 KiB
Python
118 lines
3.2 KiB
Python
"""用户端 Web 自助订单创建流程(T12.3)。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Literal, Optional
|
||
|
||
from pydantic import BaseModel, Field, model_validator
|
||
|
||
from data.orders.dao import OrdersDAO
|
||
from data.orders.models import Order, generate_order_id
|
||
|
||
|
||
ServiceVersion = Literal["audit", "basic", "standard", "premium"]
|
||
_SERVICE_PRICES: dict[ServiceVersion, int] = {
|
||
"audit": 4900,
|
||
"basic": 4900,
|
||
"standard": 9900,
|
||
"premium": 19900,
|
||
}
|
||
|
||
|
||
_SUPPORTED_PUBLIC_PROVINCES = {
|
||
"北京",
|
||
"天津",
|
||
"上海",
|
||
"重庆",
|
||
"河北",
|
||
"河南",
|
||
"山东",
|
||
"山西",
|
||
"陕西",
|
||
"辽宁",
|
||
"吉林",
|
||
"黑龙江",
|
||
"江苏",
|
||
"浙江",
|
||
"安徽",
|
||
"福建",
|
||
"江西",
|
||
"湖北",
|
||
"湖南",
|
||
"广东",
|
||
"海南",
|
||
"四川",
|
||
"贵州",
|
||
"云南",
|
||
"甘肃",
|
||
"青海",
|
||
"新疆",
|
||
}
|
||
|
||
|
||
def service_price_for(service_version: ServiceVersion) -> int:
|
||
return _SERVICE_PRICES[service_version]
|
||
|
||
|
||
class PublicOrderCreate(BaseModel):
|
||
service_version: ServiceVersion
|
||
amount_cents: int = Field(ge=0)
|
||
customer_name: Optional[str] = None
|
||
customer_phone: Optional[str] = Field(default=None, min_length=1)
|
||
customer_wechat: Optional[str] = None
|
||
customer_email: Optional[str] = None
|
||
candidate_name: str = Field(min_length=1)
|
||
candidate_province: Optional[str] = None
|
||
notes: Optional[str] = None
|
||
|
||
@model_validator(mode="after")
|
||
def _validate_minimal_checkout(self) -> "PublicOrderCreate":
|
||
expected_amount = service_price_for(self.service_version)
|
||
if self.amount_cents != expected_amount:
|
||
raise ValueError("amount_cents 与套餐价格不一致")
|
||
if not self.customer_phone and not self.customer_wechat:
|
||
raise ValueError("customer_phone / customer_wechat 至少填写一个")
|
||
if self.candidate_province and self.candidate_province not in _SUPPORTED_PUBLIC_PROVINCES:
|
||
raise ValueError("candidate_province 当前暂不支持")
|
||
return self
|
||
|
||
|
||
|
||
class PublicOrderCreated(BaseModel):
|
||
order_id: str
|
||
source: str
|
||
status: str
|
||
service_version: str
|
||
amount_cents: int
|
||
next_step: str
|
||
|
||
|
||
def create_public_order(dao: OrdersDAO, request: PublicOrderCreate) -> Order:
|
||
order = Order(
|
||
id=generate_order_id(),
|
||
source="web",
|
||
service_version=request.service_version,
|
||
amount_cents=service_price_for(request.service_version),
|
||
status="pending",
|
||
customer_name=request.customer_name,
|
||
customer_phone=request.customer_phone,
|
||
customer_wechat=request.customer_wechat,
|
||
customer_email=request.customer_email,
|
||
candidate_name=request.candidate_name,
|
||
candidate_province=request.candidate_province,
|
||
notes=request.notes,
|
||
tags=["web-self-service", f"package:{request.service_version}"],
|
||
)
|
||
return dao.create(order, actor="public_web", reason="public_create")
|
||
|
||
|
||
def to_created_payload(order: Order) -> PublicOrderCreated:
|
||
return PublicOrderCreated(
|
||
order_id=order.id,
|
||
source=order.source,
|
||
status=order.status,
|
||
service_version=order.service_version,
|
||
amount_cents=order.amount_cents,
|
||
next_step="payment",
|
||
)
|