微信支付,支持所有订单类型。

This commit is contained in:
aaron 2025-01-26 22:42:21 +08:00
parent 925592944b
commit 6141f6b033
4 changed files with 72 additions and 23 deletions

View File

@ -128,7 +128,7 @@ async def create_payment(
if not order: if not order:
return error_response(code=404, message="订单不存在或状态不正确") return error_response(code=404, message="订单不存在或状态不正确")
amount = order.pay_amount amount = order.pay_amount
description = "商家商品订单" description = "商家团购订单"
elif request.order_type == OrderType.ONLINE_PAY: elif request.order_type == OrderType.ONLINE_PAY:
order = db.query(MerchantPayOrderDB).filter( order = db.query(MerchantPayOrderDB).filter(
@ -140,6 +140,16 @@ async def create_payment(
return error_response(code=404, message="订单不存在或状态不正确") return error_response(code=404, message="订单不存在或状态不正确")
amount = order.amount amount = order.amount
description = "商家在线买单" description = "商家在线买单"
elif request.order_type == OrderType.DELIVERY:
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == request.order_id,
ShippingOrderDB.userid == current_user.userid,
ShippingOrderDB.status == OrderStatus.UNPAID
).first()
if not order:
return error_response(code=404, message="订单不存在或状态不正确")
amount = order.final_amount
description = "小区配送订单"
else: else:
return error_response(code=400, message="不支持的订单类型") return error_response(code=400, message="不支持的订单类型")
@ -167,7 +177,7 @@ async def create_payment(
except Exception as e: except Exception as e:
return error_response(code=500, message=f"创建支付订单失败: {str(e)}") return error_response(code=500, message=f"创建支付订单失败: {str(e)}")
@router.post("/payment-notify") @router.post("/payment/notify")
async def payment_notify( async def payment_notify(
request: Request, request: Request,
db: Session = Depends(get_db) db: Session = Depends(get_db)
@ -177,7 +187,6 @@ async def payment_notify(
# 初始化微信支付客户端 # 初始化微信支付客户端
wechat = WeChatClient() wechat = WeChatClient()
# 验证并解析回调数据
data = await wechat.verify_payment_notify(request) data = await wechat.verify_payment_notify(request)
if not data: if not data:
print(f"回调数据验证失败: {data}") print(f"回调数据验证失败: {data}")
@ -190,30 +199,63 @@ async def payment_notify(
trade_state = data.get("trade_state") trade_state = data.get("trade_state")
success_time = data.get("success_time") success_time = data.get("success_time")
if trade_state != "SUCCESS": if not all([out_trade_no, transaction_id, trade_state]) or trade_state != "SUCCESS":
return error_response(code=400, message="支付未成功") return error_response(code=400, message="缺少必要的订单信息或支付未成功")
# 更新订单状态 # 判断订单类型并处理
if out_trade_no.startswith("M"): # 商家商品订单 if out_trade_no.startswith('D'): # 配送订单
# 查询配送订单
order = db.query(ShippingOrderDB).filter(
ShippingOrderDB.orderid == out_trade_no
).first()
if not order:
return error_response(code=404, message="订单不存在")
if trade_state == "SUCCESS":
# 更新订单状态
order.pay_status = True
order.status = OrderStatus.COMPLETED # 支付成功后状态为已完成
order.transaction_id = transaction_id
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
elif out_trade_no.startswith("M"): # 商家商品订单
# 查询商户订单
order = db.query(MerchantOrderDB).filter( order = db.query(MerchantOrderDB).filter(
MerchantOrderDB.order_id == out_trade_no MerchantOrderDB.order_id == out_trade_no
).first() ).first()
if order:
if not order:
return error_response(code=404, message="订单不存在")
if trade_state == "SUCCESS":
# 更新订单状态
order.pay_status = True
order.status = MerchantOrderStatus.UNVERIFIED order.status = MerchantOrderStatus.UNVERIFIED
order.pay_time = datetime.fromisoformat(success_time)
order.transaction_id = transaction_id order.transaction_id = transaction_id
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
elif out_trade_no.startswith("P"): # 商家在线买单 elif out_trade_no.startswith("P"): # 商家在线买单
order = db.query(MerchantPayOrderDB).filter( order = db.query(MerchantPayOrderDB).filter(
MerchantPayOrderDB.order_id == out_trade_no MerchantPayOrderDB.order_id == out_trade_no
).first() ).first()
if order:
if not order:
return error_response(code=404, message="订单不存在")
if trade_state == "SUCCESS":
# 更新订单状态
order.pay_status = True
order.status = MerchantPayOrderStatus.PAID order.status = MerchantPayOrderStatus.PAID
order.pay_time = datetime.fromisoformat(success_time)
order.transaction_id = transaction_id order.transaction_id = transaction_id
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
else:
return error_response(code=400, message="未知的订单类型")
db.commit() db.commit()
# 返回成功
return success_response(message="支付成功") return success_response(message="支付成功")
except Exception as e: except Exception as e:

View File

@ -185,7 +185,7 @@ class WeChatClient:
"mchid": self.mch_id, "mchid": self.mch_id,
"description": description, "description": description,
"out_trade_no": out_trade_no, "out_trade_no": out_trade_no,
"notify_url": f"{settings.API_BASE_URL}/api/wechat/payment-notify", "notify_url": f"{settings.API_BASE_URL}/api/wechat/payment/notify",
"amount": { "amount": {
"total": total_amount, "total": total_amount,
"currency": "CNY" "currency": "CNY"
@ -286,14 +286,14 @@ class WeChatClient:
aesgcm = AESGCM(key_bytes) aesgcm = AESGCM(key_bytes)
print("解密参数:") # print("解密参数:")
print(f"密钥长度: {len(key_bytes)} bytes") # print(f"密钥长度: {len(key_bytes)} bytes")
print(f"Nonce长度: {len(nonce_bytes)} bytes") # print(f"Nonce长度: {len(nonce_bytes)} bytes")
print(f"密文长度: {len(ciphertext_bytes)} bytes") # print(f"密文长度: {len(ciphertext_bytes)} bytes")
print(f"附加数据: {associated_data_bytes}") # print(f"附加数据: {associated_data_bytes}")
print(f"使用的密钥: {self.api_v3_key}") # 仅用于调试,生产环境需要移除 # print(f"使用的密钥: {self.api_v3_key}") # 仅用于调试,生产环境需要移除
print(f"原始nonce: {nonce}") # print(f"原始nonce: {nonce}")
print(f"原始associated_data: {associated_data}") # print(f"原始associated_data: {associated_data}")
# 解密数据 # 解密数据
decrypted_data = aesgcm.decrypt( decrypted_data = aesgcm.decrypt(

View File

@ -1,4 +1,4 @@
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Enum from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Enum, Boolean
from sqlalchemy.dialects.mysql import DECIMAL from sqlalchemy.dialects.mysql import DECIMAL
from sqlalchemy.sql import func from sqlalchemy.sql import func
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@ -26,11 +26,14 @@ class MerchantOrderDB(Base):
order_amount = Column(DECIMAL(10,2), nullable=False) order_amount = Column(DECIMAL(10,2), nullable=False)
pay_amount = Column(DECIMAL(10,2), nullable=False, default=0) pay_amount = Column(DECIMAL(10,2), nullable=False, default=0)
status = Column(Enum(MerchantOrderStatus), nullable=False, default=MerchantOrderStatus.CREATED) status = Column(Enum(MerchantOrderStatus), nullable=False, default=MerchantOrderStatus.CREATED)
pay_status = Column(Boolean, nullable=False, default=False)
order_verify_code = Column(String(21), unique=True, nullable=False) order_verify_code = Column(String(21), unique=True, nullable=False)
verify_time = Column(DateTime(timezone=True), nullable=True) verify_time = Column(DateTime(timezone=True), nullable=True)
verify_user_id = Column(Integer, ForeignKey("users.userid"), nullable=True) verify_user_id = Column(Integer, ForeignKey("users.userid"), nullable=True)
create_time = Column(DateTime(timezone=True), server_default=func.now()) create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now())
transaction_id = Column(String(64)) # 微信支付交易号
pay_time = Column(DateTime(timezone=True), nullable=True)
class MerchantOrderCreate(BaseModel): class MerchantOrderCreate(BaseModel):
merchant_product_id: int merchant_product_id: int

View File

@ -1,4 +1,4 @@
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Enum, DECIMAL from sqlalchemy import Column, String, Integer, DateTime, ForeignKey, Enum, DECIMAL, Boolean
from sqlalchemy.sql import func from sqlalchemy.sql import func
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from typing import Optional from typing import Optional
@ -10,6 +10,8 @@ import enum
class MerchantPayOrderStatus(str, enum.Enum): class MerchantPayOrderStatus(str, enum.Enum):
UNPAID = "UNPAID" # 未支付 UNPAID = "UNPAID" # 未支付
PAID = "PAID" # 已支付 PAID = "PAID" # 已支付
REFUNDING = "REFUNDING" # 退款中
REFUNDED = "REFUNDED" # 已退款
class MerchantPayOrderDB(Base): class MerchantPayOrderDB(Base):
__tablename__ = "merchant_pay_orders" __tablename__ = "merchant_pay_orders"
@ -21,9 +23,11 @@ class MerchantPayOrderDB(Base):
amount = Column(DECIMAL(10,2), nullable=False) amount = Column(DECIMAL(10,2), nullable=False)
gift_points = Column(DECIMAL(10,1), nullable=False, default=0) gift_points = Column(DECIMAL(10,1), nullable=False, default=0)
status = Column(Enum(MerchantPayOrderStatus), nullable=False, default=MerchantPayOrderStatus.UNPAID) status = Column(Enum(MerchantPayOrderStatus), nullable=False, default=MerchantPayOrderStatus.UNPAID)
pay_status = Column(Boolean, nullable=False, default=False)
create_time = Column(DateTime(timezone=True), server_default=func.now()) create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now())
pay_time = Column(DateTime(timezone=True), nullable=True) pay_time = Column(DateTime(timezone=True), nullable=True)
transaction_id = Column(String(64)) # 微信支付交易号
class MerchantPayOrderCreate(BaseModel): class MerchantPayOrderCreate(BaseModel):
merchant_id: int merchant_id: int