Files
wordpress-theme-aksrt/src/Payment/BalanceGateway.php
T
kate522 8c5b1555c9 refactor: flatten src/AKSRT → src (drop theme-identifier dir)
Move all domain folders from src/AKSRT/{Domain} to src/{Domain}; remap
Composer PSR-4 "AKSRT\\": "src/"; update audit script + README + ADR
paths; remove dead tools/build-psr4-map.php (scanned deleted inc/classes).
2026-08-02 22:06:06 +08:00

148 lines
5.6 KiB
PHP

<?php
/**
* @package AKSRT
*/
namespace AKSRT\Payment;
defined('ABSPATH') || exit;
/**
* 站内余额支付网关(内置实现)。
*
* 仅扣现金钱包(\AKSRT\Credits\Balance / pay_balance_s),不再回退到积分。
*/
class BalanceGateway implements GatewayInterface {
public function get_id(): string {
return 'balance';
}
public function get_name(): string {
return __('站内余额', 'aksrt');
}
public function is_configured(): bool {
// Cash wallet only — do not treat points as 余额.
if (!class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
return false;
}
if (class_exists('\AKSRT\Settings\PaymentRuntime')) {
return \AKSRT\Settings\PaymentRuntime::is_gateway_enabled('balance');
}
return true;
}
public function create_payment(array $order): array {
$user_id = (int) ($order['user_id'] ?? 0);
$amount = round((float) ($order['amount'] ?? 0), 2);
$order_number = (string) ($order['order_number'] ?? '');
if (!class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
return ['success' => false, 'message' => __('余额功能未启用', 'aksrt')];
}
if ($user_id <= 0) {
return ['success' => false, 'message' => __('请先登录', 'aksrt')];
}
$balance = \AKSRT\Credits\Balance::balance($user_id);
if ($balance < $amount) {
return ['success' => false, 'message' => __('余额不足', 'aksrt')];
}
$result = \AKSRT\Credits\Balance::deduct(
$user_id,
$amount,
'order_payment',
['type' => 'order', 'id' => 0, 'order' => $order_number],
sprintf(__('订单 %s 支付', 'aksrt'), $order_number)
);
if (is_wp_error($result)) {
return ['success' => false, 'message' => $result->get_error_message() ?: __('扣款失败', 'aksrt')];
}
return [
'success' => true,
'transaction_id' => 'BAL_' . ($order_number !== '' ? $order_number : (string) time()),
'message' => __('余额支付成功', 'aksrt'),
];
}
public function verify_callback(\WP_REST_Request $request): array {
// Balance payment is synchronous — no callback needed
return ['success' => false, 'message' => __('余额支付无需回调验证', 'aksrt')];
}
public function query_status(string $order_number): array {
$order_repo = OrderRepository::get_instance();
$order = $order_repo->get($order_number);
if (!$order) {
return ['success' => false, 'message' => __('订单不存在', 'aksrt')];
}
return [
'success' => true,
'status' => $order['status'],
'transaction_id' => $order['payment_transaction_id'] ?? '',
];
}
public function refund(string $order_number, float $amount, string $request_id = ''): array {
$order_repo = OrderRepository::get_instance();
$order = $order_repo->get($order_number);
if (!$order) {
return ['success' => false, 'message' => __('订单不存在', 'aksrt')];
}
$user_id = (int) $order['user_id'];
$amount = round((float) $amount, 2);
if (!class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
return ['success' => false, 'message' => __('余额功能未启用', 'aksrt')];
}
$request_id = sanitize_text_field($request_id);
$refund_key = $request_id !== '' ? $request_id : 'order:' . $order_number;
$lock_key = 'aksrt_balance_refund_' . hash('sha256', $refund_key);
$existing = get_option($lock_key, []);
if (is_array($existing) && ($existing['status'] ?? '') === 'succeeded') {
return [
'success' => true,
'refund_id' => 'BAL_REF_' . $order_number,
'message' => __('退款已处理(幂等)', 'aksrt'),
];
}
if (is_array($existing) && ($existing['status'] ?? '') === 'pending') {
return ['success' => false, 'status' => 'pending', 'message' => __('退款正在处理中,请稍后查询', 'aksrt')];
}
$marker = ['status' => 'pending', 'token' => wp_generate_uuid4(), 'created_at' => time()];
if (!add_option($lock_key, $marker, '', false)) {
return ['success' => false, 'status' => 'pending', 'message' => __('退款正在处理中,请稍后查询', 'aksrt')];
}
try {
$result = \AKSRT\Credits\Balance::add(
$user_id,
$amount,
'order_refund',
['type' => 'order', 'order' => $order_number, 'request_id' => $request_id],
sprintf(__('订单 %s 退款', 'aksrt'), $order_number)
);
if (is_wp_error($result)) {
delete_option($lock_key);
return ['success' => false, 'message' => $result->get_error_message() ?: __('退款失败', 'aksrt')];
}
update_option($lock_key, [
'status' => 'succeeded',
'refund_id' => 'BAL_REF_' . $order_number,
'completed_at' => time(),
], false);
return ['success' => true, 'refund_id' => 'BAL_REF_' . $order_number, 'message' => __('退款成功', 'aksrt')];
} catch (\Throwable $e) {
delete_option($lock_key);
return ['success' => false, 'message' => $e->getMessage()];
}
}
}