fix(payment): re-pay with fresh provider out_trade_no
WeChat/Alipay/Epay reject reusing the same merchant order number when params change. Allocate attempt-suffixed out_trade_no on resume pay, map callbacks back to the local order, and best-effort close prior trades. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
723dd180e4
commit
ed55d302e9
7 files changed
+322
-24
No files matched your search
@@ -226,6 +226,28 @@ class CheckoutService {
|
||||
return $this->pay_with_points($user_id, $order_number, $order);
|
||||
}
|
||||
|
||||
// External gateways: allocate a fresh out_trade_no so re-pay works when
|
||||
// the provider rejects "same order number with changed params".
|
||||
$needs_attempt = !in_array($payment_method, ['balance', 'points'], true);
|
||||
if ($needs_attempt && class_exists('\AKSRT\Payment\OrderRepository')) {
|
||||
$attempt = $repo->allocate_payment_attempt($order_number);
|
||||
if ($attempt === null) {
|
||||
return ['success' => false, 'message' => __('无法生成支付单号,请稍后重试。', 'aksrt')];
|
||||
}
|
||||
$order = $repo->get_user_order($user_id, $order_number) ?: $order;
|
||||
$order['out_trade_no'] = (string) $attempt['out_trade_no'];
|
||||
// Close previous provider trade when possible (WeChat/Alipay) so the new attempt is clean.
|
||||
if (!empty($attempt['previous'])
|
||||
&& $attempt['previous'] !== $attempt['out_trade_no']
|
||||
&& method_exists($gateway, 'close_trade')) {
|
||||
try {
|
||||
$gateway->close_trade((string) $attempt['previous']);
|
||||
} catch (\Throwable $e) {
|
||||
// best-effort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$payment_result = $gateway->create_payment($order);
|
||||
if (empty($payment_result['success'])) {
|
||||
return ['success' => false, 'message' => $payment_result['message'] ?? __('支付失败。', 'aksrt')];
|
||||
|
||||
Reference in new issue
Block a user