from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy.ext.asyncio import AsyncSession from pydantic import BaseModel from typing import Optional from app.database import get_db from app.services.payment import PaymentService from app.services.wechat_pay import WeChatPayService from app.api.v1.deps import get_current_user_id router = APIRouter() class CreateOrderRequest(BaseModel): plan: str pay_type: str = "jsapi" class PaymentCallbackRequest(BaseModel): payment_id: str success: bool @router.get("/plans") async def get_plans(): svc = PaymentService(None) return await svc.get_plans() @router.get("/subscription") async def get_subscription( user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = PaymentService(db) return await svc.get_current_subscription(user_id) @router.post("/create-order") async def create_order( data: CreateOrderRequest, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = PaymentService(db) try: return await svc.create_order(user_id, data.plan, data.pay_type) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) @router.post("/callback") async def payment_callback( data: PaymentCallbackRequest, db: AsyncSession = Depends(get_db), ): svc = PaymentService(db) success = await svc.handle_payment_callback(data.payment_id, data.success) if not success: raise HTTPException(status_code=404, detail="Order not found") return {"status": "ok"} @router.post("/notify") async def wechat_pay_notify(request: Request, db: AsyncSession = Depends(get_db)): body = await request.body() body_str = body.decode("utf-8") headers = dict(request.headers) wxpay = WeChatPayService() if not wxpay.verify_callback(headers, body_str): raise HTTPException(status_code=401, detail="签名验证失败") import json data = json.loads(body_str) resource = data.get("resource", {}) ciphertext = resource.get("ciphertext", "") nonce = resource.get("nonce", "") associated_data = resource.get("associated_data", "") plaintext = wxpay.decrypt_callback(ciphertext, nonce, associated_data) pay_data = json.loads(plaintext) out_trade_no = pay_data.get("out_trade_no", "") trade_state = pay_data.get("trade_state", "") success = trade_state == "SUCCESS" svc = PaymentService(db) await svc.handle_payment_callback(out_trade_no, success) return {"code": "SUCCESS", "message": "OK"}