1
This commit is contained in:
@@ -149,6 +149,7 @@ def _get_alipay_client(app_id: str, private_key: str, public_key: str, gateway:
|
|||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
config = AlipayClientConfig()
|
config = AlipayClientConfig()
|
||||||
config.server_url = gateway or "https://openapi.alipay.com/gateway.do"
|
config.server_url = gateway or "https://openapi.alipay.com/gateway.do"
|
||||||
config.app_id = app_id
|
config.app_id = app_id
|
||||||
@@ -156,9 +157,10 @@ def _get_alipay_client(app_id: str, private_key: str, public_key: str, gateway:
|
|||||||
config.alipay_public_key = public_key
|
config.alipay_public_key = public_key
|
||||||
config.sign_type = "RSA2"
|
config.sign_type = "RSA2"
|
||||||
config.charset = "utf-8"
|
config.charset = "utf-8"
|
||||||
try:
|
|
||||||
_alipay_client = DefaultAlipayClient(config, logger)
|
_alipay_client = DefaultAlipayClient(alipay_client_config=config)
|
||||||
_alipay_client_app_id = app_id
|
_alipay_client_app_id = app_id
|
||||||
|
logger.info(f"Alipay client initialized successfully for app_id={app_id}")
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Failed to initialize Alipay client")
|
logger.exception("Failed to initialize Alipay client")
|
||||||
_alipay_client = None
|
_alipay_client = None
|
||||||
@@ -204,10 +206,27 @@ async def create_recharge_order(
|
|||||||
raise ValueError("微信支付未完成配置,请联系管理员")
|
raise ValueError("微信支付未完成配置,请联系管理员")
|
||||||
|
|
||||||
total_credits = credits + bonus_credits
|
total_credits = credits + bonus_credits
|
||||||
|
|
||||||
|
# Generate order number once
|
||||||
|
order_no = generate_order_no()
|
||||||
|
|
||||||
|
# For real payment methods, create payment request BEFORE saving order to DB
|
||||||
|
qr_url = None
|
||||||
|
if not mock_mode and method == "alipay":
|
||||||
|
# Try to create Alipay order first
|
||||||
|
qr_url = _create_alipay_order_with_params(
|
||||||
|
order_no=order_no,
|
||||||
|
amount=price,
|
||||||
|
credits=total_credits,
|
||||||
|
db_configs=db_configs,
|
||||||
|
)
|
||||||
|
if not qr_url:
|
||||||
|
raise ValueError("支付宝预下单失败,请检查配置或稍后重试")
|
||||||
|
|
||||||
order = PaymentOrder(
|
order = PaymentOrder(
|
||||||
id=generate_id(),
|
id=generate_id(),
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
order_no=generate_order_no(),
|
order_no=order_no,
|
||||||
amount=price,
|
amount=price,
|
||||||
credits=total_credits,
|
credits=total_credits,
|
||||||
payment_method=method,
|
payment_method=method,
|
||||||
@@ -239,14 +258,9 @@ async def create_recharge_order(
|
|||||||
# Real payment: delegate to WeChat or Alipay
|
# Real payment: delegate to WeChat or Alipay
|
||||||
if method == "wechat":
|
if method == "wechat":
|
||||||
_create_wechat_order(order, db_configs)
|
_create_wechat_order(order, db_configs)
|
||||||
elif method == "alipay":
|
elif method == "alipay" and qr_url:
|
||||||
qr_url = _create_alipay_order(order, db_configs)
|
|
||||||
if qr_url:
|
|
||||||
# Attach QR URL to the order instance (transient, not persisted)
|
# Attach QR URL to the order instance (transient, not persisted)
|
||||||
order.qr_url = qr_url # type: ignore[attr-defined]
|
order.qr_url = qr_url # type: ignore[attr-defined]
|
||||||
else:
|
|
||||||
# Precreate failed — do not leave a pending order that can never be paid
|
|
||||||
raise ValueError("支付宝预下单失败,请检查配置或稍后重试")
|
|
||||||
|
|
||||||
return order
|
return order
|
||||||
|
|
||||||
@@ -274,10 +288,17 @@ def _create_wechat_order(order: PaymentOrder, db_configs: dict[str, str]) -> Non
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def _create_alipay_order(order: PaymentOrder, db_configs: dict[str, str]) -> str | None:
|
def _create_alipay_order_with_params(
|
||||||
|
order_no: str,
|
||||||
|
amount: float,
|
||||||
|
credits: float,
|
||||||
|
db_configs: dict[str, str],
|
||||||
|
) -> str | None:
|
||||||
"""Call Alipay ``trade.precreate`` to obtain a QR code URL.
|
"""Call Alipay ``trade.precreate`` to obtain a QR code URL.
|
||||||
|
|
||||||
Reads all Alipay config from the database (admin panel).
|
This version accepts parameters directly instead of an order object,
|
||||||
|
allowing us to call it before creating the database record.
|
||||||
|
|
||||||
Returns the ``qr_code`` URL on success, or ``None`` on failure.
|
Returns the ``qr_code`` URL on success, or ``None`` on failure.
|
||||||
"""
|
"""
|
||||||
app_id = db_configs.get("payment_alipay_app_id", "")
|
app_id = db_configs.get("payment_alipay_app_id", "")
|
||||||
@@ -306,14 +327,14 @@ def _create_alipay_order(order: PaymentOrder, db_configs: dict[str, str]) -> str
|
|||||||
|
|
||||||
# 构造业务参数
|
# 构造业务参数
|
||||||
model = AlipayTradePrecreateModel()
|
model = AlipayTradePrecreateModel()
|
||||||
model.out_trade_no = order.order_no
|
model.out_trade_no = order_no
|
||||||
model.total_amount = f"{order.amount:.2f}"
|
model.total_amount = f"{amount:.2f}"
|
||||||
model.subject = f"充值订单 {order.order_no}"
|
model.subject = f"充值订单 {order_no}"
|
||||||
model.product_code = "QR_CODE_OFFLINE"
|
model.product_code = "QR_CODE_OFFLINE"
|
||||||
|
|
||||||
body_parts = []
|
body_parts = []
|
||||||
if order.credits > 0:
|
if credits > 0:
|
||||||
body_parts.append(f"{order.credits}积分")
|
body_parts.append(f"{credits}积分")
|
||||||
if body_parts:
|
if body_parts:
|
||||||
model.body = " ".join(body_parts)
|
model.body = " ".join(body_parts)
|
||||||
|
|
||||||
@@ -323,7 +344,7 @@ def _create_alipay_order(order: PaymentOrder, db_configs: dict[str, str]) -> str
|
|||||||
# 执行API调用
|
# 执行API调用
|
||||||
response_content = client.execute(request)
|
response_content = client.execute(request)
|
||||||
if not response_content:
|
if not response_content:
|
||||||
logger.error(f"Alipay precreate failed: empty response, order_no={order.order_no}")
|
logger.error(f"Alipay precreate failed: empty response, order_no={order_no}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# 解析响应结果
|
# 解析响应结果
|
||||||
@@ -333,7 +354,7 @@ def _create_alipay_order(order: PaymentOrder, db_configs: dict[str, str]) -> str
|
|||||||
if response.is_success():
|
if response.is_success():
|
||||||
qr_url = response.qr_code
|
qr_url = response.qr_code
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Alipay precreate success: order_no={order.order_no}, "
|
f"Alipay precreate success: order_no={order_no}, "
|
||||||
f"qr_url={qr_url}"
|
f"qr_url={qr_url}"
|
||||||
)
|
)
|
||||||
return qr_url
|
return qr_url
|
||||||
@@ -341,15 +362,30 @@ def _create_alipay_order(order: PaymentOrder, db_configs: dict[str, str]) -> str
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"Alipay precreate failed: code={response.code}, "
|
f"Alipay precreate failed: code={response.code}, "
|
||||||
f"msg={response.msg}, sub_code={response.sub_code}, "
|
f"msg={response.msg}, sub_code={response.sub_code}, "
|
||||||
f"sub_msg={response.sub_msg}, order_no={order.order_no}"
|
f"sub_msg={response.sub_msg}, order_no={order_no}"
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(f"Alipay precreate exception: order_no={order.order_no}")
|
logger.exception(f"Alipay precreate exception: order_no={order_no}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _create_alipay_order(order: PaymentOrder, db_configs: dict[str, str]) -> str | None:
|
||||||
|
"""Call Alipay ``trade.precreate`` to obtain a QR code URL.
|
||||||
|
|
||||||
|
Reads all Alipay config from the database (admin panel).
|
||||||
|
Returns the ``qr_code`` URL on success, or ``None`` on failure.
|
||||||
|
|
||||||
|
Deprecated: Use _create_alipay_order_with_params instead for better error handling.
|
||||||
|
"""
|
||||||
|
return _create_alipay_order_with_params(
|
||||||
|
order_no=order.order_no,
|
||||||
|
amount=order.amount,
|
||||||
|
credits=order.credits,
|
||||||
|
db_configs=db_configs,
|
||||||
|
)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Alipay callback verification
|
# Alipay callback verification
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user