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

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:
return error_response(code=404, message="订单不存在或状态不正确")
amount = order.pay_amount
description = "商家商品订单"
description = "商家团购订单"
elif request.order_type == OrderType.ONLINE_PAY:
order = db.query(MerchantPayOrderDB).filter(
@ -140,6 +140,16 @@ async def create_payment(
return error_response(code=404, message="订单不存在或状态不正确")
amount = order.amount
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:
return error_response(code=400, message="不支持的订单类型")
@ -167,7 +177,7 @@ async def create_payment(
except Exception as e:
return error_response(code=500, message=f"创建支付订单失败: {str(e)}")
@router.post("/payment-notify")
@router.post("/payment/notify")
async def payment_notify(
request: Request,
db: Session = Depends(get_db)
@ -176,8 +186,7 @@ async def payment_notify(
try:
# 初始化微信支付客户端
wechat = WeChatClient()
# 验证并解析回调数据
data = await wechat.verify_payment_notify(request)
if not data:
print(f"回调数据验证失败: {data}")
@ -190,30 +199,63 @@ async def payment_notify(
trade_state = data.get("trade_state")
success_time = data.get("success_time")
if trade_state != "SUCCESS":
return error_response(code=400, message="支付未成功")
if not all([out_trade_no, transaction_id, trade_state]) or trade_state != "SUCCESS":
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(
MerchantOrderDB.order_id == out_trade_no
).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.pay_time = datetime.fromisoformat(success_time)
order.transaction_id = transaction_id
order.pay_time = datetime.fromisoformat(success_time.replace('Z', '+00:00'))
elif out_trade_no.startswith("P"): # 商家在线买单
order = db.query(MerchantPayOrderDB).filter(
MerchantPayOrderDB.order_id == out_trade_no
).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.pay_time = datetime.fromisoformat(success_time)
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()
# 返回成功
return success_response(message="支付成功")
except Exception as e:

View File

@ -185,7 +185,7 @@ class WeChatClient:
"mchid": self.mch_id,
"description": description,
"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": {
"total": total_amount,
"currency": "CNY"
@ -286,14 +286,14 @@ class WeChatClient:
aesgcm = AESGCM(key_bytes)
print("解密参数:")
print(f"密钥长度: {len(key_bytes)} bytes")
print(f"Nonce长度: {len(nonce_bytes)} bytes")
print(f"密文长度: {len(ciphertext_bytes)} bytes")
print(f"附加数据: {associated_data_bytes}")
print(f"使用的密钥: {self.api_v3_key}") # 仅用于调试,生产环境需要移除
print(f"原始nonce: {nonce}")
print(f"原始associated_data: {associated_data}")
# print("解密参数:")
# print(f"密钥长度: {len(key_bytes)} bytes")
# print(f"Nonce长度: {len(nonce_bytes)} bytes")
# print(f"密文长度: {len(ciphertext_bytes)} bytes")
# print(f"附加数据: {associated_data_bytes}")
# print(f"使用的密钥: {self.api_v3_key}") # 仅用于调试,生产环境需要移除
# print(f"原始nonce: {nonce}")
# print(f"原始associated_data: {associated_data}")
# 解密数据
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.sql import func
from pydantic import BaseModel, Field
@ -26,11 +26,14 @@ class MerchantOrderDB(Base):
order_amount = Column(DECIMAL(10,2), nullable=False)
pay_amount = Column(DECIMAL(10,2), nullable=False, default=0)
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)
verify_time = Column(DateTime(timezone=True), nullable=True)
verify_user_id = Column(Integer, ForeignKey("users.userid"), nullable=True)
create_time = Column(DateTime(timezone=True), server_default=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):
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 pydantic import BaseModel, Field
from typing import Optional
@ -10,6 +10,8 @@ import enum
class MerchantPayOrderStatus(str, enum.Enum):
UNPAID = "UNPAID" # 未支付
PAID = "PAID" # 已支付
REFUNDING = "REFUNDING" # 退款中
REFUNDED = "REFUNDED" # 已退款
class MerchantPayOrderDB(Base):
__tablename__ = "merchant_pay_orders"
@ -21,9 +23,11 @@ class MerchantPayOrderDB(Base):
amount = Column(DECIMAL(10,2), nullable=False)
gift_points = Column(DECIMAL(10,1), nullable=False, default=0)
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())
update_time = Column(DateTime(timezone=True), onupdate=func.now())
pay_time = Column(DateTime(timezone=True), nullable=True)
transaction_id = Column(String(64)) # 微信支付交易号
class MerchantPayOrderCreate(BaseModel):
merchant_id: int