# -*- coding = utf-8 -*- # @Time : 2025/2/24 上午9:03 # @File : routes.py # @Software : PyCharm # @Author : xingc # @Desc : import logging import xmltodict from fastapi import APIRouter, Request, HTTPException, status, Depends, BackgroundTasks from sqlalchemy.ext.asyncio import AsyncSession from core.base import schema as base_schema from core.db.crud import CRUD from core.db.engine import get_async_session from core.db.models import Order from core.routers.auth.schema import LoginUser from core.routers.auth.services import get_current_user from core.utils.helper import generate_keyname, generate_order_number from core.wechat.api import wechat_pay_api from . import schema from .actions import actions_after_payment logger = logging.getLogger(__name__) pay_router = APIRouter(prefix='/pay', tags=['支付模块']) @pay_router.post( '/order/create', summary='订单创建', response_model=base_schema.BaseResponse[schema.CreateOrderOut] ) async def create_order( request: Request, payload: schema.CreateOrderIn, login_user: LoginUser = Depends(get_current_user), db_session: AsyncSession = Depends(get_async_session), ): client_ip = ( request.headers.get('X-Real-IP') or request.headers.get('x-real-ip') or request.client.host ) out_trade_no = generate_order_number() prepay_id = wechat_pay_api.create_unified_order( **payload.dict(exclude_none=True), out_trade_no=out_trade_no, spbill_create_ip=client_ip ) payment_params = wechat_pay_api.generate_payment_params(prepay_id) db_crud = CRUD(db_session, Order) order: Order = await db_crud.create( data={ 'order_id': out_trade_no, 'user_id': login_user.user_id, 'product_id': payload.product_id, 'total_fee': payload.total_fee, 'status': base_schema.OrderStatusType.WAIT_PAYMENT }, filters={ 'out_trade_no': out_trade_no, } ) return {'data': {'payment_params': payment_params, 'order_id': order.order_id}} @pay_router.post('/wechat/notify', summary='处理支付结果通知', response_model=base_schema.BaseResponse) async def wechat_notify( request: Request, background_tasks: BackgroundTasks, db_session: AsyncSession = Depends(get_async_session) ): body = await request.body() logger.debug(body.decode()) result = xmltodict.parse(body.decode()) # 验证签名 params = result['xml'] sign = params.pop('sign') local_sign = wechat_pay_api.generate_sign(params) if sign != local_sign: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail='签名验证失败' ) # 处理支付结果 db_crud = CRUD(db_session, Order) record = { 'out_trade_no': params['out_trade_no'], 'transaction_id': params['transaction_id'] } if params['return_code'] == 'SUCCESS' and params['result_code'] == 'SUCCESS': record.update({ 'notify_total_fee': params['total_fee'], 'status': base_schema.OrderStatusType.OK }) result = {'code': 200, 'message': 'OK'} background_tasks.add_task(actions_after_payment, notify_params=params) else: result = {'code': 400, 'message': '支付失败'} record.update({ 'status': base_schema.OrderStatusType.FAIL, }) await db_crud.update(data=record, filters={'order_id': record['out_trade_no']}) return result