From 5db03936f9cf8e2ab3cb27a11f2e9d7a50fa433d Mon Sep 17 00:00:00 2001 From: Pine Date: Wed, 2 Sep 2026 12:13:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(pay):=20=E6=94=AF=E4=BB=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=BB=A3=E4=BB=98=E2=80=94=E2=80=94=E4=BB=BB=E6=84=8F?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E7=94=A8=E6=88=B7=E5=9D=87=E5=8F=AF=E4=B8=BA?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E6=94=AF=E4=BB=98=EF=BC=8C=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E5=88=B0=E8=B4=A6=E8=AE=A2=E5=8D=95=E5=88=9B=E5=BB=BA=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除所有支付相关接口的订单归属校验和 opc_member 角色限制: 【算力充值 pay/service.py + pay/routers.py】 - build_pay_params: 移除 order.user_id != user.id 归属校验 - recharge_pay_params: require_roles(opc_member) → get_current_user(任意登录用户) - recharge_status: 移除归属校验,角色放宽为任意登录用户 【市场购买 market/service.py + market/routers.py】 - build_pay_params: 移除归属校验 - query_status: 移除归属校验 - market_pay_params / market_order_status: 角色放宽为任意登录用户 【到账逻辑不变】 - process_paid_order 按订单 engine_user_id(订单创建者)加款 - 支付者 B 的 openid 仅用于 JSAPI 下单,不影响到账目标 - 审计日志 user_id 记录订单创建者 场景:A 用户 web 端创建充值订单 → B 用户小程序扫码 → B 登录并支付 → 余额到账 A 用户 --- app/market/routers.py | 9 +++++---- app/market/service.py | 7 +++---- app/pay/routers.py | 15 ++++++++------- app/pay/service.py | 7 +++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/market/routers.py b/app/market/routers.py index 060d699..293e4cc 100644 --- a/app/market/routers.py +++ b/app/market/routers.py @@ -156,12 +156,13 @@ async def market_create_order( raise HTTPException(status_code=503, detail=str(exc)) from exc -@router.get("/orders/{order_no}/pay-params", summary="小程序扫码确认支付(JSAPI 参数)") +@router.get("/orders/{order_no}/pay-params", summary="小程序扫码确认支付(JSAPI 参数,支持代付)") async def market_pay_params( order_no: str, db: Database = Depends(get_db), - user: dict = Depends(require_roles("opc_member")), + user: dict = Depends(get_current_user), ): + """支持代付:任意登录用户均可为该订单支付,商品发放到订单创建者。""" try: return await service.build_pay_params(db, user, order_no) except ValueError as exc: @@ -170,11 +171,11 @@ async def market_pay_params( raise HTTPException(status_code=503, detail=str(exc)) from exc -@router.post("/orders/{order_no}/status", summary="查询购买订单状态(含对账补单)") +@router.post("/orders/{order_no}/status", summary="查询购买订单状态(含对账补单,支持代付查询)") async def market_order_status( order_no: str, db: Database = Depends(get_db), - user: dict = Depends(require_roles("opc_member")), + user: dict = Depends(get_current_user), ): try: return await service.query_status(db, user, order_no) diff --git a/app/market/service.py b/app/market/service.py index 3df6e02..83ca93a 100644 --- a/app/market/service.py +++ b/app/market/service.py @@ -322,15 +322,14 @@ async def _expires_iso(seconds: int) -> str: async def build_pay_params(db, user: dict, order_no: str) -> dict: - """小程序扫码进入确认支付页:校验归属后 JSAPI 下单,返回 wx.requestPayment 参数。""" + """小程序扫码进入确认支付页:按当前小程序用户 openid 发起 JSAPI 下单, + 返回 wx.requestPayment 参数。支持代付:任意登录用户均可支付,商品发放到订单创建者。""" from ..pay import wxpay from ..infrastructure.repositories import utcnow_iso as _now r = await db.session.scalar(select(MarketPurchaseOrder).where(MarketPurchaseOrder.order_no == order_no)) if r is None: raise ValueError("订单不存在") - if r.user_id != user["id"]: - raise ValueError("请使用下单账号登录的小程序扫码(订单归属不一致)") if r.status != "pending": return {"order": _order_view(r), "pay_params": None, "finished": True} if r.expires_at and r.expires_at < _now(): @@ -356,7 +355,7 @@ async def query_status(db, user: dict, order_no: str) -> dict: from ..infrastructure.repositories import utcnow_iso as _now r = await db.session.scalar(select(MarketPurchaseOrder).where(MarketPurchaseOrder.order_no == order_no)) - if r is None or r.user_id != user["id"]: + if r is None: raise ValueError("订单不存在") if r.status == "pending": if r.expires_at and r.expires_at < _now(): diff --git a/app/pay/routers.py b/app/pay/routers.py index eb7e4ec..7906b90 100644 --- a/app/pay/routers.py +++ b/app/pay/routers.py @@ -14,7 +14,7 @@ import tempfile from fastapi import APIRouter, Depends, File, HTTPException, Request, Response, UploadFile from pydantic import BaseModel, Field -from ..api.dependencies import get_db +from ..api.dependencies import get_current_user, get_db from ..infrastructure.repositories import Database from ..rbac import require_roles from . import profitsharing, service, wxpay @@ -87,13 +87,14 @@ async def recharge_create( return order -@router.get("/opc/compute/recharge/orders/{order_no}/pay-params", summary="小程序扫码确认支付(归属校验 + JSAPI 参数)") +@router.get("/opc/compute/recharge/orders/{order_no}/pay-params", summary="小程序扫码确认支付(JSAPI 参数,支持代付)") async def recharge_pay_params( order_no: str, db: Database = Depends(get_db), - user: dict = Depends(require_roles("opc_member")), + user: dict = Depends(get_current_user), ): - """微信扫桌面端小程序码 → 打开小程序本接口取 wx.requestPayment 参数。""" + """微信扫桌面端小程序码 → 打开小程序本接口取 wx.requestPayment 参数。 + 支持代付:任意登录用户均可为该订单支付,余额到账到订单创建者。""" try: return await service.build_pay_params(db, user, order_no) except ValueError as exc: @@ -102,15 +103,15 @@ async def recharge_pay_params( raise HTTPException(status_code=503, detail=str(exc)) from exc -@router.post("/opc/compute/recharge/orders/{order_no}/status", summary="查询充值订单状态(含主动对账补单)") +@router.post("/opc/compute/recharge/orders/{order_no}/status", summary="查询充值订单状态(含主动对账补单,支持代付查询)") async def recharge_status( order_no: str, db: Database = Depends(get_db), - user: dict = Depends(require_roles("opc_member")), + user: dict = Depends(get_current_user), ): repo = _repo(db) order = await repo.get_by_order_no(order_no) - if order is None or order["user_id"] != user["id"]: + if order is None: raise HTTPException(status_code=404, detail="订单不存在") order = await service.reconcile(db, order) return { diff --git a/app/pay/service.py b/app/pay/service.py index 9fd65a8..2233a3c 100644 --- a/app/pay/service.py +++ b/app/pay/service.py @@ -204,13 +204,12 @@ async def create_order(db: Database, user: dict, *, client_type: str, async def build_pay_params(db: Database, user: dict, order_no: str) -> dict: - """小程序扫码进入「确认支付」页:校验归属后按当前小程序用户 openid 发起 JSAPI 下单, - 返回订单摘要 + wx.requestPayment 参数。""" + """小程序扫码进入「确认支付」页:按当前小程序用户 openid 发起 JSAPI 下单, + 返回订单摘要 + wx.requestPayment 参数。支持代付:任意登录用户均可支付, + 余额到账到订单创建者(按订单 user_id)。""" order = await db.compute_recharges.get_by_order_no(order_no) if order is None: raise ValueError("订单不存在") - if order["user_id"] != user["id"]: - raise ValueError("请使用下单账号登录的小程序扫码(订单归属不一致)") if order["status"] != "pending": return {"order": _order_view(order), "pay_params": None, "finished": True} if order["expires_at"] and order["expires_at"] < utcnow_iso():