fix(payment): harden payment and refund chains
This commit is contained in:
1 parent
c70fbe9835
commit
53ff99f343
24 files changed
+993
-251
No files matched your search
@@ -308,7 +308,17 @@ class UserOrders {
|
||||
return ['success' => false, 'message' => __('订单不存在。', 'aksrt')];
|
||||
}
|
||||
|
||||
$payment_method = sanitize_key($payment_method ?: (string) ($order['payment_method'] ?? 'balance'));
|
||||
$status = (string) ($order['status'] ?? '');
|
||||
if (!in_array($status, [Order::STATUS_CREATED, Order::STATUS_PENDING], true)) {
|
||||
return ['success' => false, 'message' => __('当前订单状态不可支付。', 'aksrt')];
|
||||
}
|
||||
|
||||
$stored_method = sanitize_key((string) ($order['payment_method'] ?? ''));
|
||||
$payment_method = sanitize_key($payment_method ?: ($stored_method ?: 'balance'));
|
||||
if ($stored_method !== '' && $payment_method !== $stored_method) {
|
||||
return ['success' => false, 'message' => __('支付方式与订单不一致,请重新下单。', 'aksrt')];
|
||||
}
|
||||
|
||||
$gateway_manager = class_exists(Gateway::class) ? Gateway::get_instance() : null;
|
||||
$gateway = $gateway_manager ? $gateway_manager->get_gateway($payment_method) : null;
|
||||
if (!$gateway) {
|
||||
@@ -318,39 +328,68 @@ class UserOrders {
|
||||
return ['success' => false, 'message' => __('该支付方式尚未配置,请联系站长。', 'aksrt')];
|
||||
}
|
||||
|
||||
$order['subject'] = $order['subject'] ?? sprintf(__('订单 %s', 'aksrt'), $order_number);
|
||||
$payment_result = $gateway->create_payment($order);
|
||||
if (empty($payment_result['success'])) {
|
||||
return ['success' => false, 'message' => $payment_result['message'] ?? __('支付失败。', 'aksrt')];
|
||||
$lock = class_exists(PaymentAttemptLock::class)
|
||||
? PaymentAttemptLock::acquire($order_number)
|
||||
: false;
|
||||
if ($lock === false) {
|
||||
return ['success' => false, 'message' => __('该订单正在发起支付,请稍后重试。', 'aksrt')];
|
||||
}
|
||||
|
||||
$code_url = $payment_result['payment_data']['code_url'] ?? '';
|
||||
if (!empty($payment_result['payment_url']) || $code_url !== '') {
|
||||
try {
|
||||
$order['subject'] = $order['subject'] ?? sprintf(__('订单 %s', 'aksrt'), $order_number);
|
||||
$payment_result = $gateway->create_payment($order);
|
||||
if (empty($payment_result['success'])) {
|
||||
return ['success' => false, 'message' => $payment_result['message'] ?? __('支付失败。', 'aksrt')];
|
||||
}
|
||||
|
||||
$code_url = $payment_result['payment_data']['code_url'] ?? '';
|
||||
if (!empty($payment_result['payment_url']) || $code_url !== '') {
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'redirect' => true,
|
||||
'payment_url' => (string) ($payment_result['payment_url'] ?? ''),
|
||||
'qr_content' => (string) $code_url,
|
||||
'order_number' => $order_number,
|
||||
'message' => $payment_result['message'] ?? __('请在新页面完成支付。', 'aksrt'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$paid = $repo->update_status($order_number, Order::STATUS_PAID, [
|
||||
'payment_method' => $payment_method,
|
||||
'payment_transaction_id' => sanitize_text_field((string) ($payment_result['transaction_id'] ?? '')),
|
||||
'note' => __('用户在前台完成支付。', 'aksrt'),
|
||||
'require_transition' => true,
|
||||
]);
|
||||
if (!$paid) {
|
||||
$compensation = $gateway->refund(
|
||||
$order_number,
|
||||
(float) ($order['amount'] ?? 0),
|
||||
'PAY_ROLLBACK_' . substr(hash('sha256', $order_number), 0, 24)
|
||||
);
|
||||
if (empty($compensation['success'])) {
|
||||
error_log(sprintf(
|
||||
'[AKSRT Payment] rollback failed order=%s gateway=%s: %s',
|
||||
$order_number,
|
||||
$payment_method,
|
||||
(string) ($compensation['message'] ?? 'unknown error')
|
||||
));
|
||||
return ['success' => false, 'message' => __('订单状态已变化,扣款补偿失败,请联系管理员处理。', 'aksrt')];
|
||||
}
|
||||
return ['success' => false, 'message' => __('订单状态已变化,扣款已退回。', 'aksrt')];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'redirect' => true,
|
||||
'payment_url' => (string) ($payment_result['payment_url'] ?? ''),
|
||||
'qr_content' => (string) $code_url,
|
||||
'order_number' => $order_number,
|
||||
'message' => $payment_result['message'] ?? __('请在新页面完成支付。', 'aksrt'),
|
||||
'order' => $this->get_order_detail_view($user_id, $order_number),
|
||||
'message' => $payment_result['message'] ?? __('支付成功。', 'aksrt'),
|
||||
],
|
||||
];
|
||||
} finally {
|
||||
PaymentAttemptLock::release($order_number, $lock);
|
||||
}
|
||||
|
||||
$repo->update_status($order_number, Order::STATUS_PAID, [
|
||||
'payment_method' => $payment_method,
|
||||
'payment_transaction_id' => sanitize_text_field((string) ($payment_result['transaction_id'] ?? '')),
|
||||
'note' => __('用户在前台完成支付。', 'aksrt'),
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'order' => $this->get_order_detail_view($user_id, $order_number),
|
||||
'message' => $payment_result['message'] ?? __('支付成功。', 'aksrt'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function empty_stats(): array {
|
||||
|
||||
Reference in new issue
Block a user