feat: 更新支付模块 (Stripe/PayPal/PingPong) 和 uni-app 配置
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, Query
|
||||
import json
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, Query, Header
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from app.database import get_db
|
||||
from app.services.payment import PaymentService
|
||||
from app.services.payment import PaymentService, GATEWAY_MAP
|
||||
from app.services.unified_pay import UnifiedPayService
|
||||
from app.models.payment_transaction import PaymentTransaction
|
||||
from app.api.v1.deps import get_current_user_id
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
@@ -144,3 +147,134 @@ async def unified_webhook(request: Request, db: AsyncSession = Depends(get_db)):
|
||||
amount, body_str,
|
||||
)
|
||||
return {"code": 0, "message": "OK"}
|
||||
|
||||
|
||||
@router.post("/stripe-webhook")
|
||||
async def stripe_webhook(
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
body = await request.body()
|
||||
body_str = body.decode("utf-8")
|
||||
|
||||
stripe_gw = GATEWAY_MAP.get("stripe")
|
||||
if not stripe_gw:
|
||||
raise HTTPException(status_code=501, detail="Stripe 未配置")
|
||||
|
||||
if not stripe_gw.verify_callback(dict(request.headers), body_str):
|
||||
raise HTTPException(status_code=403, detail="Stripe 签名验证失败")
|
||||
|
||||
parsed = stripe_gw.parse_callback(body_str, dict(request.headers))
|
||||
if parsed.get("success"):
|
||||
svc = PaymentService(db)
|
||||
await svc.handle_callback(
|
||||
parsed["order_no"],
|
||||
parsed["gateway_order_id"],
|
||||
parsed["gateway_order_no"],
|
||||
True,
|
||||
parsed["amount"],
|
||||
body_str,
|
||||
)
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@router.post("/paypal-capture")
|
||||
async def paypal_capture(
|
||||
request: Request,
|
||||
user_id: str = Depends(get_current_user_id),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
body = await request.json()
|
||||
order_no = body.get("order_no", "")
|
||||
token = body.get("token", "")
|
||||
|
||||
if not order_no or not token:
|
||||
raise HTTPException(status_code=400, detail="缺少参数")
|
||||
|
||||
txn_result = await db.execute(
|
||||
select(PaymentTransaction).where(
|
||||
PaymentTransaction.order_no == order_no,
|
||||
PaymentTransaction.user_id == user_id,
|
||||
)
|
||||
)
|
||||
txn = txn_result.scalar_one_or_none()
|
||||
if not txn:
|
||||
raise HTTPException(status_code=404, detail="订单不存在")
|
||||
if txn.status != "pending":
|
||||
return {"status": "ok", "message": "已处理"}
|
||||
|
||||
paypal_gw = GATEWAY_MAP.get("paypal")
|
||||
if not paypal_gw:
|
||||
raise HTTPException(status_code=501, detail="PayPal 未配置")
|
||||
|
||||
try:
|
||||
result = await paypal_gw.capture_order(token)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
if result.get("completed"):
|
||||
capture_id = result.get("capture_id", token)
|
||||
svc = PaymentService(db)
|
||||
await svc.handle_callback(
|
||||
order_no, token, capture_id, True, txn.amount, json.dumps(result)
|
||||
)
|
||||
return {"status": "completed", "order_no": order_no}
|
||||
raise HTTPException(status_code=400, detail=f"PayPal capture failed: {result.get('status')}")
|
||||
|
||||
|
||||
@router.post("/paypal-webhook")
|
||||
async def paypal_webhook(
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
body = await request.body()
|
||||
body_str = body.decode("utf-8")
|
||||
|
||||
paypal_gw = GATEWAY_MAP.get("paypal")
|
||||
if not paypal_gw:
|
||||
raise HTTPException(status_code=501, detail="PayPal 未配置")
|
||||
|
||||
if not paypal_gw.verify_callback(dict(request.headers), body_str):
|
||||
raise HTTPException(status_code=403, detail="PayPal 签名验证失败")
|
||||
|
||||
parsed = paypal_gw.parse_callback(body_str, dict(request.headers))
|
||||
if parsed.get("success"):
|
||||
svc = PaymentService(db)
|
||||
await svc.handle_callback(
|
||||
parsed["order_no"],
|
||||
parsed["gateway_order_id"],
|
||||
parsed["gateway_order_no"],
|
||||
True,
|
||||
parsed["amount"],
|
||||
body_str,
|
||||
)
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@router.post("/pingpong-webhook")
|
||||
async def pingpong_webhook(
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
body = await request.body()
|
||||
body_str = body.decode("utf-8")
|
||||
|
||||
pp_gw = GATEWAY_MAP.get("pingpong")
|
||||
if not pp_gw:
|
||||
raise HTTPException(status_code=501, detail="PingPong 未配置")
|
||||
|
||||
if not pp_gw.verify_callback(dict(request.headers), body_str):
|
||||
raise HTTPException(status_code=403, detail="PingPong 签名验证失败")
|
||||
|
||||
parsed = pp_gw.parse_callback(body_str, dict(request.headers))
|
||||
if parsed.get("success"):
|
||||
svc = PaymentService(db)
|
||||
await svc.handle_callback(
|
||||
parsed["order_no"],
|
||||
parsed["gateway_order_id"],
|
||||
parsed["gateway_order_no"],
|
||||
True,
|
||||
parsed["amount"],
|
||||
body_str,
|
||||
)
|
||||
return {"status": "ok"}
|
||||
|
||||
Reference in New Issue
Block a user