chore(release): bump version to 1.9.1 and apply pending changes
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import UTC, datetime
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
@@ -14,6 +14,7 @@ from fastapi.responses import JSONResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.deps import get_current_user, get_db
|
||||
from app.core.exceptions import InsufficientPointsException
|
||||
from app.crud.point_recharge_order import point_recharge_order
|
||||
from app.crud.point_transaction import point_transaction
|
||||
from app.models.user import User
|
||||
@@ -35,6 +36,7 @@ router = APIRouter(prefix="/points", tags=["Points"])
|
||||
|
||||
# ── 余额查询 ──────────────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/balance", response_model=ApiResponse[PointBalanceResponse])
|
||||
async def get_balance(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -47,6 +49,7 @@ async def get_balance(
|
||||
|
||||
# ── 流水查询 ──────────────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/transactions", response_model=ApiResponse[PointTransactionListResponse])
|
||||
async def list_transactions(
|
||||
pagination: PaginationParams = Depends(),
|
||||
@@ -127,12 +130,13 @@ async def list_transactions(
|
||||
|
||||
# ── 充值 ──────────────────────────────────────────────
|
||||
|
||||
|
||||
@router.post("/recharge", response_model=ApiResponse[RechargeResponse])
|
||||
async def create_recharge_order(
|
||||
request: RechargeRequest,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
http_request: Request = None,
|
||||
http_request: Request = None, # type: ignore[assignment]
|
||||
):
|
||||
"""
|
||||
创建积分充值订单(微信支付 Native 扫码)
|
||||
@@ -213,6 +217,7 @@ async def create_recharge_order(
|
||||
logger.error(f"[Points] 微信统一下单未返回 code_url: {wx_result}")
|
||||
order.status = "failed"
|
||||
order.error_msg = "微信未返回二维码链接"
|
||||
await db.commit()
|
||||
raise HTTPException(status_code=500, detail="微信支付下单失败")
|
||||
|
||||
order.prepay_id = wx_result.get("prepay_id")
|
||||
@@ -303,9 +308,7 @@ async def handle_wxpay_notify(
|
||||
return _wx_response()
|
||||
|
||||
# 查找订单
|
||||
order = await point_recharge_order.get_by_out_trade_no(
|
||||
db, out_trade_no=out_trade_no
|
||||
)
|
||||
order = await point_recharge_order.get_by_out_trade_no(db, out_trade_no=out_trade_no)
|
||||
if not order:
|
||||
logger.error(f"[WechatPay] 回调订单不存在: {out_trade_no}")
|
||||
return _wx_response()
|
||||
@@ -371,6 +374,7 @@ async def handle_wxpay_notify(
|
||||
await db.rollback()
|
||||
logger.exception(f"[WechatPay] 订单 {out_trade_no} 充值积分失败: {e}")
|
||||
# 记录错误但不抛出,返回 SUCCESS 避免微信重试
|
||||
order.status = "failed"
|
||||
order.error_msg = f"充值积分失败: {e}"
|
||||
await db.commit()
|
||||
|
||||
@@ -400,9 +404,7 @@ async def query_recharge_status(
|
||||
|
||||
wxpay = get_wxpay_service()
|
||||
async with httpx.AsyncClient(timeout=httpx.Timeout(30.0, connect=10.0)) as client:
|
||||
wx_result = await wxpay.query_order(
|
||||
client, out_trade_no=order.out_trade_no
|
||||
)
|
||||
wx_result = await wxpay.query_order(client, out_trade_no=order.out_trade_no)
|
||||
|
||||
order.query_result = str(wx_result)
|
||||
trade_state = wx_result.get("trade_state", "")
|
||||
@@ -465,6 +467,7 @@ async def query_recharge_status(
|
||||
|
||||
# ── 充值档位查询 ──────────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/recharge-options", response_model=ApiResponse[list[dict]])
|
||||
async def get_recharge_options(
|
||||
current_user: User = Depends(get_current_user),
|
||||
@@ -480,6 +483,7 @@ async def get_recharge_options(
|
||||
|
||||
# ── 扣费业务类型查询 ──────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/chargeable-types", response_model=ApiResponse[list[str]])
|
||||
async def get_chargeable_types(
|
||||
current_user: User = Depends(get_current_user),
|
||||
@@ -496,6 +500,7 @@ async def get_chargeable_types(
|
||||
|
||||
# ── 积分规则查询 ──────────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/rules", response_model=ApiResponse[list[dict]])
|
||||
async def get_points_rules(
|
||||
current_user: User = Depends(get_current_user),
|
||||
@@ -530,9 +535,9 @@ async def get_points_rules(
|
||||
# ── 积分预估查询 ──────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
# ── 今日消费统计 ──────────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/today-consumed", response_model=ApiResponse[dict])
|
||||
async def get_today_consumed(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
@@ -545,6 +550,7 @@ async def get_today_consumed(
|
||||
|
||||
# ── 直接消费扣费(前端/Rust 层调用)───────────────────
|
||||
|
||||
|
||||
@router.post("/consume", response_model=ApiResponse[dict])
|
||||
async def consume_points(
|
||||
request: ConsumeRequest,
|
||||
@@ -569,12 +575,12 @@ async def consume_points(
|
||||
source_type=request.source_type,
|
||||
source_id=request.source_id,
|
||||
description=f"【{request.description or request.source_type}】",
|
||||
allow_negative=False,
|
||||
allow_negative=request.allow_negative,
|
||||
)
|
||||
except ValueError as e:
|
||||
except InsufficientPointsException:
|
||||
# 余额不足(在同一事务内判断,避免竞态)
|
||||
if "积分不足" in str(e):
|
||||
raise HTTPException(status_code=402, detail=str(e))
|
||||
raise
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
await db.commit()
|
||||
|
||||
@@ -587,5 +593,3 @@ async def consume_points(
|
||||
},
|
||||
message="消费成功",
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user