feat: add software subscription orders

This commit is contained in:
QiuSW
2026-07-21 11:52:49 +08:00
parent 341864dc70
commit bc9d1aa0f7
25 changed files with 1179 additions and 47 deletions
+16
View File
@@ -39,6 +39,8 @@ T-304 已实现充值回调基线:`POST /api/v1/recharge/callback/wechat` 与
T-305 已实现扫码充值下单与轮询基线:`POST /api/v1/recharge/create` 与 `GET /api/v1/recharge/status` 走用户端 `SessionAuthentication + CSRF`,不接受 API Key;下单创建 pending 订单并锁定汇率/点数,再返回微信 `code_url` 或支付宝 `qr_code`;状态查询只允许订单所属用户访问,并在 pending 时尝试主动查单补入账,查单不可用时保持 pending 等回调。
T-629 已完成:软件套餐订单使用独立 `SoftwareOrder`、`POST /api/v1/software-orders/callback/wechat` 与 `GET /api/v1/software-orders/status`,只发放/续订软件权益,绝不兑换点数或触碰 `RechargeOrder` / `PointsLedger`。订阅微信下单必须配置独立 `SOFTWARE_WECHAT_PAY_NOTIFY_URL`,不得复用充值回调地址。
T-306 已实现对外 API 安全加固:`image_url` 下载只允许 `http` / `https` 公网地址,拒绝私有/回环/链路本地/保留等地址,重定向后重新校验并限制响应大小;全局 DRF 默认认证为空且默认权限为 `IsAuthenticated`,外部 API 与用户端 API 必须显式 opt-in 认证类;生成接口按 API Key / 用户限流,认证失败按 IP 限流;充值创建有 `RECHARGE_MAX_AMOUNT_CNY` 单笔上限。
T-604 目标口径:生成接口在 serializer 基础校验后先执行 prompt 本地敏感词检查;命中返回 `400 content_blocked`,且不得下载 `image_url`、不得预扣点、不得写 `CallRecord` / `PointsLedger`、不得调用上游。T-604 不启用输出审核和图片审核;详细规则见 [`moderation.md`](moderation.md)。
@@ -686,6 +688,20 @@ query_and_apply_recharge_payment(order_no: str, query_func) -> RechargeResult
- 若订单仍为 `pending`,服务端会尝试主动查单并复用 `query_and_apply_recharge_payment()` 补入账;查单不可用或尚未支付时仍返回当前本地状态。
- 到账以服务端回调或主动查单后的本地订单状态为准;`is_expired` 仅是二维码本地有效期提示,不自动阻断延迟到达的真实支付回调。
## 软件套餐订阅支付
`/subscription` 是已登录用户的虾皮圈套餐购买/续订页,使用 session + CSRF 创建软件订单并展示二维码。第一版只开放微信主动月度续订,不接受 API Key,不支持自动代扣。
### `POST /api/v1/software-orders/callback/wechat`
微信服务端回调,`@csrf_exempt`、无登录态。先按既有微信 V3/mock 协议验签,再锁 `SoftwareOrder`,校验 `out_trade_no`、支付通道、金额和交易号;同订单同交易号重复回调返回成功但不重复发放,已支付订单收到不同交易号返回 `400 bad_request`。成功时创建/续订 `SoftwareEntitlement` 并写 `LicenseEvent(order_fulfilled)`,不写 `UserWallet` 或 `PointsLedger`。
### `GET /api/v1/software-orders/status?order_no=...`
仅当前登录用户可读取自己的软件订单。pending 订单先检查二维码本地过期状态,再尝试主动查单并走与回调相同的权益发放服务。响应字段为 `order_no`、`product_code`、`plan_name`、`amount`、`currency`、`pay_method`、`status`、`code_url`、`expires_at`、`paid_at` 与 `fulfilled_at`。
退款不属于该接口或自动化范围:已支付订单的退款和权益撤销由运营按订单人工处理;不得根据某一笔旧订单直接回滚累计权益到期时间。
## AI 调用模块合约(`apps/ai`)
分两层:**别名解析** + **Provider 适配器**。API 层只传别名,由本模块解析到具体模型并选适配器。