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).
148 lines
5.6 KiB
PHP
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()];
|
|
}
|
|
}
|
|
}
|