Files
group_fqcd_jr/app/api/controllers/advisor_service_requests.py
T
张胜宇 9675df8453 chore(sync): zsy_developcc 全量同步至 qyqy_develop(W26 口径)
- 分支内容对齐 qyqy_develop b6ec3aa,树完全一致(同步后 git diff 为空)
- 覆盖本轮全部交付:客服 Agent 重构(安全路由 / 五出口 / 记忆与画像 / RAG 全链路)
  + 开发文档 62 份编号体系(D1.1 v1.17 索引)
  + 新增 D2.10-客服Agent端到端答辩文档-2026-09-21.html
- 基线:e239eb7(2026-09-17 品牌口径统一快照),本提交为其直接后继
2026-09-21 21:26:30 +08:00

86 lines
3.6 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.
"""客户申报投顾方案 + 投顾受理审批 的 HTTP 入口(`docs/05` 未登记的 AD 段新端点)。
| 段 | 端点 | 权限码 | 摘要 |
|---|---|---|---|
| 客户 | `POST /api/v1/users/me/advisor-requests` | `advisor-request:write:self` | 提交申报 |
| 客户 | `GET /api/v1/users/me/advisor-requests` | `advisor-request:read:self` | 我的申报(含状态) |
| 投顾 | `GET /api/v1/advisor/service-requests` | `advisor-request:read` | 名下客户的申报队列 |
| 投顾 | `POST /api/v1/advisor/service-requests/{request_no}/reviews` | `advisor-request:review` | 受理 / 驳回 |
客户侧刻意**不挂投顾灰度闸门**(`enforce_advisor_rollout`)—— 那是投顾业务的灰度,
客户提交自己的服务申请不该被它拦下;投顾侧照旧挂上。
"""
from __future__ import annotations
from fastapi import APIRouter, Depends, Header, Path
from app.api.dependencies.auth import build_request_context
from app.api.dependencies.rate_limit import enforce_rate_limit
from app.core.contracts import RequestContext
from app.core.errors import ValidationAgentError
from app.service.advisor_rollout_service import enforce_advisor_rollout
from app.service.advisor_service_request_service import (
AdvisorServiceRequestCreate,
AdvisorServiceRequestService,
)
client_router = APIRouter(
prefix="/api/v1/users/me",
tags=["advisor-service-requests"],
dependencies=[Depends(enforce_rate_limit)],
)
advisor_router = APIRouter(
prefix="/api/v1/advisor",
tags=["advisor-service-requests"],
dependencies=[Depends(enforce_rate_limit), Depends(enforce_advisor_rollout)],
)
@client_router.post("/advisor-requests")
async def create_advisor_request(
payload: AdvisorServiceRequestCreate,
context: RequestContext = Depends(build_request_context), # noqa: B008
key: str | None = Header(default=None, alias="Idempotency-Key"),
) -> dict[str, object]:
"""客户主动申报投顾方案(需已完成且未过期的风险测评)。"""
return await AdvisorServiceRequestService().create(payload, context, key)
@client_router.get("/advisor-requests")
async def my_advisor_requests(
context: RequestContext = Depends(build_request_context), # noqa: B008
) -> dict[str, object]:
"""我的申报单(待受理 / 已受理 / 已发送 / 已驳回)。"""
return await AdvisorServiceRequestService().list_mine(context)
@advisor_router.get("/service-requests")
async def advisor_service_request_queue(
context: RequestContext = Depends(build_request_context), # noqa: B008
) -> dict[str, object]:
"""名下客户提交的申报队列(待受理排前面)。"""
return await AdvisorServiceRequestService().queue(context)
@advisor_router.post("/service-requests/{request_no}/reviews")
async def review_advisor_service_request(
payload: dict[str, object],
request_no: str = Path(min_length=8, max_length=32),
context: RequestContext = Depends(build_request_context), # noqa: B008
key: str | None = Header(default=None, alias="Idempotency-Key"),
) -> dict[str, object]:
"""受理(**自动生成方案草稿**)或驳回客户的申报。
受理后投顾仍需走既有的「审核通过 → 发送给客户」,方案才会到客户手里。
"""
decision = payload.get("decision")
if decision not in {"accepted", "rejected"}:
raise ValidationAgentError("decision 必须为 accepted 或 rejected")
comment = payload.get("comment", "")
if not isinstance(comment, str):
raise ValidationAgentError("comment 必须是字符串")
return await AdvisorServiceRequestService().review(
request_no, str(decision), comment, context, key
)