feat(pay): 支付支持代付——任意登录用户均可为订单支付,余额到账订单创建者
移除所有支付相关接口的订单归属校验和 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 用户
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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():
|
||||
|
||||
+8
-7
@@ -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 {
|
||||
|
||||
+3
-4
@@ -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():
|
||||
|
||||
Reference in New Issue
Block a user