修复两个问题
This commit is contained in:
1 parent
48a82403b2
commit
58f3f42bf8
15 files changed
+173
-23
No files matched your search
@@ -56,6 +56,38 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyAssetBalances(data) {
|
||||||
|
data = data || {};
|
||||||
|
var wallet = data.wallet_balance !== undefined ? data.wallet_balance : data.wallet;
|
||||||
|
var points = data.credit_balance !== undefined ? data.credit_balance : data.points_balance;
|
||||||
|
if (wallet !== undefined && wallet !== null && wallet !== '') {
|
||||||
|
var walletNumber = Number(wallet);
|
||||||
|
var walletText = Number.isFinite(walletNumber) ? walletNumber.toFixed(2) : String(wallet);
|
||||||
|
document.querySelectorAll('[data-aksrt-wallet-value]').forEach(function (element) {
|
||||||
|
element.textContent = walletText;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (points !== undefined && points !== null && points !== '') {
|
||||||
|
var pointsNumber = Number(points);
|
||||||
|
var pointsText = Number.isFinite(pointsNumber) ? pointsNumber.toLocaleString() : String(points);
|
||||||
|
document.querySelectorAll('[data-aksrt-points-value]').forEach(function (element) {
|
||||||
|
element.textContent = pointsText;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshAssetBalances(snapshot) {
|
||||||
|
if (snapshot && (snapshot.wallet_balance !== undefined || snapshot.wallet !== undefined)) {
|
||||||
|
applyAssetBalances(snapshot);
|
||||||
|
}
|
||||||
|
return api('/pay/assets').then(function (response) {
|
||||||
|
if (!response.ok) return null;
|
||||||
|
var data = response.data || (response.json && response.json.data) || response.json || {};
|
||||||
|
applyAssetBalances(data);
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Task-list "去签到" → scroll + click the real asset-card sign-in button.
|
// Task-list "去签到" → scroll + click the real asset-card sign-in button.
|
||||||
function initSigninGoto() {
|
function initSigninGoto() {
|
||||||
document.querySelectorAll('[data-aksrt-signin-goto]').forEach(function (el) {
|
document.querySelectorAll('[data-aksrt-signin-goto]').forEach(function (el) {
|
||||||
@@ -333,6 +365,7 @@
|
|||||||
activePoll = null;
|
activePoll = null;
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
notyf('支付成功,正在刷新…', 'success', 5, 'aksrt-balance-charge-payment-toast');
|
notyf('支付成功,正在刷新…', 'success', 5, 'aksrt-balance-charge-payment-toast');
|
||||||
|
refreshAssetBalances();
|
||||||
window.setTimeout(function () { window.location.reload(); }, 800);
|
window.setTimeout(function () { window.location.reload(); }, 800);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -416,6 +449,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
notyf((data && data.message) || '充值成功,正在刷新…', 'success', 5, 'aksrt-balance-charge-toast');
|
notyf((data && data.message) || '充值成功,正在刷新…', 'success', 5, 'aksrt-balance-charge-toast');
|
||||||
|
refreshAssetBalances(data);
|
||||||
window.setTimeout(function () { window.location.reload(); }, 800);
|
window.setTimeout(function () { window.location.reload(); }, 800);
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
busy = false;
|
busy = false;
|
||||||
@@ -547,6 +581,7 @@
|
|||||||
var data = (r.json && r.json.data) ? r.json.data : r.json;
|
var data = (r.json && r.json.data) ? r.json.data : r.json;
|
||||||
resetOperationKey(form);
|
resetOperationKey(form);
|
||||||
notyf((data && data.message) || '转账成功,正在刷新…', 'success', 5, 'aksrt-balance-transfer-toast');
|
notyf((data && data.message) || '转账成功,正在刷新…', 'success', 5, 'aksrt-balance-transfer-toast');
|
||||||
|
refreshAssetBalances();
|
||||||
window.setTimeout(function () { window.location.reload(); }, 800);
|
window.setTimeout(function () { window.location.reload(); }, 800);
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
busy = false;
|
busy = false;
|
||||||
@@ -606,6 +641,7 @@
|
|||||||
var data = (r.json && r.json.data) ? r.json.data : r.json;
|
var data = (r.json && r.json.data) ? r.json.data : r.json;
|
||||||
resetOperationKey(form);
|
resetOperationKey(form);
|
||||||
notyf((data && data.message) || '购买成功,正在刷新…', 'success', 5, 'aksrt-balance-points-toast');
|
notyf((data && data.message) || '购买成功,正在刷新…', 'success', 5, 'aksrt-balance-points-toast');
|
||||||
|
refreshAssetBalances(data);
|
||||||
window.setTimeout(function () { window.location.reload(); }, 800);
|
window.setTimeout(function () { window.location.reload(); }, 800);
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
busy = false;
|
busy = false;
|
||||||
@@ -742,8 +778,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.AKSRTWithdrawInit = initWithdraw;
|
window.AKSRTWithdrawInit = initWithdraw;
|
||||||
|
window.AKSRTAssetBalances = {
|
||||||
|
apply: applyAssetBalances,
|
||||||
|
refresh: refreshAssetBalances
|
||||||
|
};
|
||||||
|
|
||||||
function bootAssets() {
|
function bootAssets() {
|
||||||
|
refreshAssetBalances();
|
||||||
initSigninGoto();
|
initSigninGoto();
|
||||||
initAffiliateRevenue();
|
initAffiliateRevenue();
|
||||||
initVipShop();
|
initVipShop();
|
||||||
|
|||||||
@@ -82,11 +82,12 @@
|
|||||||
}
|
}
|
||||||
target.classList.add('is-loading');
|
target.classList.add('is-loading');
|
||||||
var url = restUrl.replace(/\/$/, '') + '/user-center/panel/' + encodeURIComponent(name);
|
var url = restUrl.replace(/\/$/, '') + '/user-center/panel/' + encodeURIComponent(name);
|
||||||
if (name === 'creator' || name === 'revenue' || name === 'posts' || name === 'follow') {
|
if (name === 'creator' || name === 'revenue' || name === 'posts' || name === 'follow' || name === 'orders') {
|
||||||
var params = queryParams || new URLSearchParams(window.location.search);
|
var params = queryParams || new URLSearchParams(window.location.search);
|
||||||
var allowedParams = name === 'creator' ? ['income_page'] :
|
var allowedParams = name === 'creator' ? ['income_page'] :
|
||||||
(name === 'revenue' ? ['reward_tab', 'commission_page', 'user_page'] :
|
(name === 'revenue' ? ['reward_tab', 'commission_page', 'user_page'] :
|
||||||
(name === 'posts' ? ['post_status', 'posts_page'] : ['follow_list', 'follow_page']));
|
(name === 'posts' ? ['post_status', 'posts_page'] :
|
||||||
|
(name === 'follow' ? ['follow_list', 'follow_page'] : ['order_status', 'order_type', 'order_number', 'order_page'])));
|
||||||
allowedParams.forEach(function(key) {
|
allowedParams.forEach(function(key) {
|
||||||
if (params.get(key)) url += (url.indexOf('?') === -1 ? '?' : '&') + key + '=' + encodeURIComponent(params.get(key));
|
if (params.get(key)) url += (url.indexOf('?') === -1 ? '?' : '&') + key + '=' + encodeURIComponent(params.get(key));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ if (!function_exists('aksrt_header_user_wallet_mini')) :
|
|||||||
|
|
||||||
$html = '<a class="aksrt-header-wallet flex ac jsb" href="' . esc_url($center) . '">';
|
$html = '<a class="aksrt-header-wallet flex ac jsb" href="' . esc_url($center) . '">';
|
||||||
$html .= '<span class="aksrt-header-wallet__item"><i class="fa fas fa-database" aria-hidden="true"></i> '
|
$html .= '<span class="aksrt-header-wallet__item"><i class="fa fas fa-database" aria-hidden="true"></i> '
|
||||||
. esc_html($currency) . ' <b>' . esc_html(number_format_i18n($credits)) . '</b></span>';
|
. esc_html($currency) . ' <b data-aksrt-points-value data-credits-value>' . esc_html(number_format_i18n($credits)) . '</b></span>';
|
||||||
$html .= '<span class="aksrt-header-wallet__item"><i class="fa fas fa-money-bill" aria-hidden="true"></i> '
|
$html .= '<span class="aksrt-header-wallet__item"><i class="fa fas fa-money-bill" aria-hidden="true"></i> '
|
||||||
. esc_html__('余额', 'aksrt') . ' <b>' . esc_html(number_format_i18n($wallet, 2)) . '</b></span>';
|
. esc_html__('余额', 'aksrt') . ' <b data-aksrt-wallet-value>' . esc_html(number_format_i18n($wallet, 2)) . '</b></span>';
|
||||||
$html .= '</a>';
|
$html .= '</a>';
|
||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ $currency = (string) ($currency_name ?? __('积分', 'aksrt'));
|
|||||||
</div>
|
</div>
|
||||||
<div class="uc-asset-card__body flex jsb ac">
|
<div class="uc-asset-card__body flex jsb ac">
|
||||||
<div class="uc-asset-card__amount c-green">
|
<div class="uc-asset-card__amount c-green">
|
||||||
<span class="uc-asset-card__value font-bold"><?php echo esc_html(aksrt_format_points($balance)); ?></span>
|
<span class="uc-asset-card__value font-bold" data-aksrt-points-value data-credits-value><?php echo esc_html(aksrt_format_points($balance)); ?></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="uc-asset-card__actions flex0">
|
<div class="uc-asset-card__actions flex0">
|
||||||
<?php if ($points_transfer_on) : ?>
|
<?php if ($points_transfer_on) : ?>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元');
|
|||||||
<div class="uc-asset-card__body flex jsb ac">
|
<div class="uc-asset-card__body flex jsb ac">
|
||||||
<div class="uc-asset-card__amount c-blue-2">
|
<div class="uc-asset-card__amount c-blue-2">
|
||||||
<span class="uc-asset-card__mark px12"><?php echo esc_html($mark === '元' ? '¥' : $mark); ?></span>
|
<span class="uc-asset-card__mark px12"><?php echo esc_html($mark === '元' ? '¥' : $mark); ?></span>
|
||||||
<span class="uc-asset-card__value font-bold"><?php echo esc_html($wallet_fmt); ?></span>
|
<span class="uc-asset-card__value font-bold" data-aksrt-wallet-value><?php echo esc_html($wallet_fmt); ?></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="uc-asset-card__actions flex0">
|
<div class="uc-asset-card__actions flex0">
|
||||||
<?php if ($transfer_on) : ?>
|
<?php if ($transfer_on) : ?>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ $points = max(0, (int) ($credit_balance ?? 0));
|
|||||||
<a class="uc-summary-card uc-summary-card--wallet" href="<?php echo esc_url($assets_url); ?>" data-tab="credits">
|
<a class="uc-summary-card uc-summary-card--wallet" href="<?php echo esc_url($assets_url); ?>" data-tab="credits">
|
||||||
<span class="uc-summary-card__head"><?php esc_html_e('账户余额', 'aksrt'); ?><i class="fa fas fa-angle-right" aria-hidden="true"></i></span>
|
<span class="uc-summary-card__head"><?php esc_html_e('账户余额', 'aksrt'); ?><i class="fa fas fa-angle-right" aria-hidden="true"></i></span>
|
||||||
<span class="uc-summary-card__body">
|
<span class="uc-summary-card__body">
|
||||||
<strong><?php echo esc_html($wallet); ?></strong>
|
<strong data-aksrt-wallet-value><?php echo esc_html($wallet); ?></strong>
|
||||||
<i class="fa fas fa-money-bill" aria-hidden="true"></i>
|
<i class="fa fas fa-money-bill" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
@@ -35,7 +35,7 @@ $points = max(0, (int) ($credit_balance ?? 0));
|
|||||||
<a class="uc-summary-card uc-summary-card--points" href="<?php echo esc_url($assets_url); ?>" data-tab="credits">
|
<a class="uc-summary-card uc-summary-card--points" href="<?php echo esc_url($assets_url); ?>" data-tab="credits">
|
||||||
<span class="uc-summary-card__head"><?php echo esc_html((string) ($currency_name ?? __('积分', 'aksrt'))); ?><i class="fa fas fa-angle-right" aria-hidden="true"></i></span>
|
<span class="uc-summary-card__head"><?php echo esc_html((string) ($currency_name ?? __('积分', 'aksrt'))); ?><i class="fa fas fa-angle-right" aria-hidden="true"></i></span>
|
||||||
<span class="uc-summary-card__body">
|
<span class="uc-summary-card__body">
|
||||||
<strong><?php echo esc_html(aksrt_format_points($points)); ?></strong>
|
<strong data-aksrt-points-value data-credits-value><?php echo esc_html(aksrt_format_points($points)); ?></strong>
|
||||||
<i class="fa fas fa-money-bill" aria-hidden="true"></i>
|
<i class="fa fas fa-money-bill" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class DomainModel {
|
|||||||
public const ORDER_PRODUCT_RESOURCE = 'resource';
|
public const ORDER_PRODUCT_RESOURCE = 'resource';
|
||||||
public const ORDER_PRODUCT_VIP = 'vip';
|
public const ORDER_PRODUCT_VIP = 'vip';
|
||||||
public const ORDER_PRODUCT_RECHARGE = 'recharge';
|
public const ORDER_PRODUCT_RECHARGE = 'recharge';
|
||||||
|
public const ORDER_PRODUCT_POINTS = 'points';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Human labels for aksrt_order.product_type (front-end order center).
|
* Human labels for aksrt_order.product_type (front-end order center).
|
||||||
@@ -38,6 +39,7 @@ class DomainModel {
|
|||||||
self::ORDER_PRODUCT_RESOURCE => __('付费内容', 'aksrt'),
|
self::ORDER_PRODUCT_RESOURCE => __('付费内容', 'aksrt'),
|
||||||
self::ORDER_PRODUCT_VIP => __('VIP 会员', 'aksrt'),
|
self::ORDER_PRODUCT_VIP => __('VIP 会员', 'aksrt'),
|
||||||
self::ORDER_PRODUCT_RECHARGE => __('余额充值', 'aksrt'),
|
self::ORDER_PRODUCT_RECHARGE => __('余额充值', 'aksrt'),
|
||||||
|
self::ORDER_PRODUCT_POINTS => __('积分购买', 'aksrt'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ trait BalanceServiceRest {
|
|||||||
|
|
||||||
|
|
||||||
public function register_routes(): void {
|
public function register_routes(): void {
|
||||||
|
register_rest_route('aksrt/v1', '/pay/assets', [
|
||||||
|
'methods' => \WP_REST_Server::READABLE,
|
||||||
|
'callback' => [$this, 'rest_asset_snapshot'],
|
||||||
|
'permission_callback' => [$this, 'check_asset_rest'],
|
||||||
|
]);
|
||||||
|
|
||||||
register_rest_route('aksrt/v1', '/pay/balance/charge', [
|
register_rest_route('aksrt/v1', '/pay/balance/charge', [
|
||||||
[
|
[
|
||||||
'methods' => \WP_REST_Server::READABLE,
|
'methods' => \WP_REST_Server::READABLE,
|
||||||
@@ -68,6 +74,17 @@ trait BalanceServiceRest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function rest_asset_snapshot(\WP_REST_Request $request) {
|
||||||
|
$user_id = get_current_user_id();
|
||||||
|
return rest_ensure_response([
|
||||||
|
'success' => true,
|
||||||
|
'data' => [
|
||||||
|
'wallet_balance' => \AKSRT\Ledger\LedgerService::get_instance()->balance_decimal($user_id),
|
||||||
|
'credit_balance' => (string) \AKSRT\Ledger\LedgerService::get_instance()->balance($user_id, \AKSRT\Ledger\AssetType::POINTS),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function check_asset_rest(\WP_REST_Request $request) {
|
public function check_asset_rest(\WP_REST_Request $request) {
|
||||||
if (!is_user_logged_in()) {
|
if (!is_user_logged_in()) {
|
||||||
return new \WP_Error('aksrt_need_login', __('请先登录', 'aksrt'), ['status' => 401]);
|
return new \WP_Error('aksrt_need_login', __('请先登录', 'aksrt'), ['status' => 401]);
|
||||||
@@ -356,9 +373,36 @@ trait BalanceServiceRest {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
$business_mutation = static function () use ($user_id, $amount, $points, $operation_key) {
|
$order_number = 'PX' . strtoupper(substr(hash('sha256', $operation_key), 0, 30));
|
||||||
|
$business_mutation = static function (int $transaction_id) use ($user_id, $amount, $points, $operation_key, $order_number) {
|
||||||
|
if (!class_exists('\\AKSRT\\Payment\\OrderRepository')) {
|
||||||
|
return new \WP_Error('aksrt_order_unavailable', __('订单服务不可用', 'aksrt'), ['status' => 500]);
|
||||||
|
}
|
||||||
|
$note = wp_json_encode([
|
||||||
|
'points_exchange' => 1,
|
||||||
|
'points' => $points,
|
||||||
|
'product_title' => sprintf(__('购买 %d 积分', 'aksrt'), $points),
|
||||||
|
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
$created = \AKSRT\Payment\OrderRepository::get_instance()->create([
|
||||||
|
'order_number' => $order_number,
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'product_type' => \AKSRT\Core\DomainModel::ORDER_PRODUCT_POINTS,
|
||||||
|
'product_id' => 0,
|
||||||
|
'amount' => $amount->decimal(),
|
||||||
|
'currency' => 'CNY',
|
||||||
|
'status' => \AKSRT\Payment\Order::STATUS_COMPLETED,
|
||||||
|
'payment_method' => 'balance',
|
||||||
|
'payment_transaction_id' => 'ledger_' . $transaction_id,
|
||||||
|
'paid_at' => current_time('mysql'),
|
||||||
|
'completed_at' => current_time('mysql'),
|
||||||
|
'note' => is_string($note) ? $note : '',
|
||||||
|
'request_key' => $operation_key,
|
||||||
|
]);
|
||||||
|
if ($created !== $order_number) {
|
||||||
|
return new \WP_Error('aksrt_order_create_failed', __('积分订单创建失败', 'aksrt'), ['status' => 500]);
|
||||||
|
}
|
||||||
if (class_exists('\\AKSRT\\Payment\\CommissionLedger')) {
|
if (class_exists('\\AKSRT\\Payment\\CommissionLedger')) {
|
||||||
return \AKSRT\Payment\CommissionLedger::get_instance()->record_points_exchange($user_id, $amount->decimal(), $points, $operation_key);
|
return \AKSRT\Payment\CommissionLedger::get_instance()->record_points_exchange($user_id, $amount->decimal(), $points, $operation_key, $order_number);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -368,7 +412,7 @@ trait BalanceServiceRest {
|
|||||||
$points,
|
$points,
|
||||||
$operation_key,
|
$operation_key,
|
||||||
'points_exchange',
|
'points_exchange',
|
||||||
['type' => 'points_exchange', 'key' => $operation_key],
|
['type' => 'order', 'key' => $order_number],
|
||||||
sprintf(__('余额兑换 %d 积分', 'aksrt'), $points),
|
sprintf(__('余额兑换 %d 积分', 'aksrt'), $points),
|
||||||
['rate' => $rate],
|
['rate' => $rate],
|
||||||
$guard,
|
$guard,
|
||||||
@@ -384,6 +428,7 @@ trait BalanceServiceRest {
|
|||||||
'wallet_balance' => \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, $result->balance($user_id, \AKSRT\Ledger\AssetType::BALANCE))->decimal(),
|
'wallet_balance' => \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, $result->balance($user_id, \AKSRT\Ledger\AssetType::BALANCE))->decimal(),
|
||||||
'credit_balance' => $result->balance($user_id, \AKSRT\Ledger\AssetType::POINTS),
|
'credit_balance' => $result->balance($user_id, \AKSRT\Ledger\AssetType::POINTS),
|
||||||
'points' => $points,
|
'points' => $points,
|
||||||
|
'order_number' => $order_number,
|
||||||
'reload' => true,
|
'reload' => true,
|
||||||
]]);
|
]]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -714,6 +714,7 @@ class ChargeCard {
|
|||||||
$amount = $parsed_amount->decimal();
|
$amount = $parsed_amount->decimal();
|
||||||
$currency = 'CNY';
|
$currency = 'CNY';
|
||||||
} elseif ($type === self::TYPE_CREDITS) {
|
} elseif ($type === self::TYPE_CREDITS) {
|
||||||
|
$product_type = \AKSRT\Core\DomainModel::ORDER_PRODUCT_POINTS;
|
||||||
$amount = (int) ($meta['points'] ?? 0);
|
$amount = (int) ($meta['points'] ?? 0);
|
||||||
$currency = 'points';
|
$currency = 'points';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ final class CommissionLedger {
|
|||||||
? true
|
? true
|
||||||
: new \WP_Error('aksrt_commission_write_failed', __('返佣记录写入失败', 'aksrt'), ['status' => 500]);
|
: new \WP_Error('aksrt_commission_write_failed', __('返佣记录写入失败', 'aksrt'), ['status' => 500]);
|
||||||
}
|
}
|
||||||
public function record_points_exchange(int $user_id, string $amount, int $points, string $operation_key): bool {
|
public function record_points_exchange(int $user_id, string $amount, int $points, string $operation_key, string $order_number): bool {
|
||||||
$result = $this->record_paid_order([
|
$result = $this->record_paid_order([
|
||||||
'order_number' => 'PX' . substr(hash('sha256', $operation_key), 0, 30),
|
'order_number' => $order_number,
|
||||||
'product_type' => 'credits',
|
'product_type' => 'credits',
|
||||||
'user_id' => $user_id,
|
'user_id' => $user_id,
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
|
|||||||
@@ -89,14 +89,29 @@ final class OrderCenterQuery {
|
|||||||
public function database_statuses(): array {
|
public function database_statuses(): array {
|
||||||
return match ($this->status()) {
|
return match ($this->status()) {
|
||||||
self::STATUS_PENDING => [Order::STATUS_CREATED, Order::STATUS_PENDING],
|
self::STATUS_PENDING => [Order::STATUS_CREATED, Order::STATUS_PENDING],
|
||||||
self::STATUS_COMPLETED => [Order::STATUS_PAID],
|
self::STATUS_COMPLETED => [
|
||||||
self::STATUS_CLOSED => [Order::STATUS_CANCELLED, Order::STATUS_EXPIRED],
|
Order::STATUS_PAID,
|
||||||
|
Order::STATUS_DELIVERED,
|
||||||
|
Order::STATUS_COMPLETED,
|
||||||
|
Order::STATUS_PENDING_REVIEW,
|
||||||
|
],
|
||||||
|
self::STATUS_CLOSED => [
|
||||||
|
Order::STATUS_CANCELLED,
|
||||||
|
Order::STATUS_EXPIRED,
|
||||||
|
Order::STATUS_REFUNDING,
|
||||||
|
Order::STATUS_REFUNDED,
|
||||||
|
],
|
||||||
default => [
|
default => [
|
||||||
Order::STATUS_CREATED,
|
Order::STATUS_CREATED,
|
||||||
Order::STATUS_PENDING,
|
Order::STATUS_PENDING,
|
||||||
Order::STATUS_PAID,
|
Order::STATUS_PAID,
|
||||||
|
Order::STATUS_DELIVERED,
|
||||||
|
Order::STATUS_COMPLETED,
|
||||||
|
Order::STATUS_PENDING_REVIEW,
|
||||||
Order::STATUS_CANCELLED,
|
Order::STATUS_CANCELLED,
|
||||||
Order::STATUS_EXPIRED,
|
Order::STATUS_EXPIRED,
|
||||||
|
Order::STATUS_REFUNDING,
|
||||||
|
Order::STATUS_REFUNDED,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,10 @@ trait OrderRepositoryCore {
|
|||||||
'payment_transaction_id' => sanitize_text_field((string) ($data['payment_transaction_id'] ?? '')),
|
'payment_transaction_id' => sanitize_text_field((string) ($data['payment_transaction_id'] ?? '')),
|
||||||
'created_at' => $data['created_at'] ?? current_time('mysql'),
|
'created_at' => $data['created_at'] ?? current_time('mysql'),
|
||||||
'paid_at' => $data['paid_at'] ?? null,
|
'paid_at' => $data['paid_at'] ?? null,
|
||||||
|
'completed_at' => $data['completed_at'] ?? null,
|
||||||
'note' => $note,
|
'note' => $note,
|
||||||
];
|
];
|
||||||
$formats = ['%s', '%d', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'];
|
$formats = ['%s', '%d', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'];
|
||||||
|
|
||||||
// Pending orders always receive an expiry. Explicit caller values remain
|
// Pending orders always receive an expiry. Explicit caller values remain
|
||||||
// supported for compatibility, while new flows use the shared runtime policy.
|
// supported for compatibility, while new flows use the shared runtime policy.
|
||||||
@@ -204,20 +205,22 @@ trait OrderRepositoryCore {
|
|||||||
|
|
||||||
$parts = $this->get_user_order_query_parts($user_id, $args);
|
$parts = $this->get_user_order_query_parts($user_id, $args);
|
||||||
$pending_statuses = [Order::STATUS_CREATED, Order::STATUS_PENDING];
|
$pending_statuses = [Order::STATUS_CREATED, Order::STATUS_PENDING];
|
||||||
$paid_status = Order::STATUS_PAID;
|
$completed_statuses = [Order::STATUS_PAID, Order::STATUS_DELIVERED, Order::STATUS_COMPLETED, Order::STATUS_PENDING_REVIEW];
|
||||||
|
$completed_placeholders = implode(', ', array_fill(0, count($completed_statuses), '%s'));
|
||||||
$known_statuses = OrderCenterQuery::from_array([])->database_statuses();
|
$known_statuses = OrderCenterQuery::from_array([])->database_statuses();
|
||||||
$known_placeholders = implode(', ', array_fill(0, count($known_statuses), '%s'));
|
$known_placeholders = implode(', ', array_fill(0, count($known_statuses), '%s'));
|
||||||
$sql = "SELECT
|
$sql = "SELECT
|
||||||
(SELECT COUNT(*) FROM {$this->table()} {$parts['where']}) AS filtered_total,
|
(SELECT COUNT(*) FROM {$this->table()} {$parts['where']}) AS filtered_total,
|
||||||
COUNT(*) AS known_total,
|
COUNT(*) AS known_total,
|
||||||
SUM(CASE WHEN status IN (%s, %s) THEN 1 ELSE 0 END) AS pending,
|
SUM(CASE WHEN status IN (%s, %s) THEN 1 ELSE 0 END) AS pending,
|
||||||
SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) AS completed
|
SUM(CASE WHEN status IN ({$completed_placeholders}) THEN 1 ELSE 0 END) AS completed
|
||||||
FROM {$this->table()}
|
FROM {$this->table()}
|
||||||
WHERE user_id = %d AND status IN ({$known_placeholders})";
|
WHERE user_id = %d AND status IN ({$known_placeholders})";
|
||||||
$params = array_merge(
|
$params = array_merge(
|
||||||
$parts['params'],
|
$parts['params'],
|
||||||
$pending_statuses,
|
$pending_statuses,
|
||||||
[$paid_status, $user_id],
|
$completed_statuses,
|
||||||
|
[$user_id],
|
||||||
$known_statuses
|
$known_statuses
|
||||||
);
|
);
|
||||||
$row = $wpdb->get_row($wpdb->prepare($sql, $params), ARRAY_A);
|
$row = $wpdb->get_row($wpdb->prepare($sql, $params), ARRAY_A);
|
||||||
|
|||||||
@@ -286,8 +286,8 @@ class UserOrders {
|
|||||||
private function status_group(string $status): string {
|
private function status_group(string $status): string {
|
||||||
return match ($status) {
|
return match ($status) {
|
||||||
Order::STATUS_CREATED, Order::STATUS_PENDING => OrderCenterQuery::STATUS_PENDING,
|
Order::STATUS_CREATED, Order::STATUS_PENDING => OrderCenterQuery::STATUS_PENDING,
|
||||||
Order::STATUS_PAID => OrderCenterQuery::STATUS_COMPLETED,
|
Order::STATUS_PAID, Order::STATUS_DELIVERED, Order::STATUS_COMPLETED, Order::STATUS_PENDING_REVIEW => OrderCenterQuery::STATUS_COMPLETED,
|
||||||
Order::STATUS_CANCELLED, Order::STATUS_EXPIRED => OrderCenterQuery::STATUS_CLOSED,
|
Order::STATUS_CANCELLED, Order::STATUS_EXPIRED, Order::STATUS_REFUNDING, Order::STATUS_REFUNDED => OrderCenterQuery::STATUS_CLOSED,
|
||||||
default => OrderCenterQuery::STATUS_CLOSED,
|
default => OrderCenterQuery::STATUS_CLOSED,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -313,6 +313,9 @@ class UserOrders {
|
|||||||
if ($type === DomainModel::ORDER_PRODUCT_RECHARGE) {
|
if ($type === DomainModel::ORDER_PRODUCT_RECHARGE) {
|
||||||
return __('余额充值', 'aksrt');
|
return __('余额充值', 'aksrt');
|
||||||
}
|
}
|
||||||
|
if ($type === DomainModel::ORDER_PRODUCT_POINTS) {
|
||||||
|
return __('积分购买', 'aksrt');
|
||||||
|
}
|
||||||
if ($product_id > 0) {
|
if ($product_id > 0) {
|
||||||
$cache_key = (string) $product_id;
|
$cache_key = (string) $product_id;
|
||||||
if (!array_key_exists($cache_key, $this->post_title_cache)) {
|
if (!array_key_exists($cache_key, $this->post_title_cache)) {
|
||||||
@@ -354,7 +357,7 @@ class UserOrders {
|
|||||||
|
|
||||||
if ($type === DomainModel::ORDER_PRODUCT_VIP) {
|
if ($type === DomainModel::ORDER_PRODUCT_VIP) {
|
||||||
$url = function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('vip') : '';
|
$url = function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('vip') : '';
|
||||||
} elseif ($type === DomainModel::ORDER_PRODUCT_RECHARGE) {
|
} elseif (in_array($type, [DomainModel::ORDER_PRODUCT_RECHARGE, DomainModel::ORDER_PRODUCT_POINTS], true)) {
|
||||||
$url = function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('credits') : '';
|
$url = function_exists('aksrt_get_user_center_tab_url') ? aksrt_get_user_center_tab_url('credits') : '';
|
||||||
} else {
|
} else {
|
||||||
$url = $post_id > 0 ? get_permalink($post_id) : '';
|
$url = $post_id > 0 ? get_permalink($post_id) : '';
|
||||||
@@ -368,6 +371,7 @@ class UserOrders {
|
|||||||
return match ($type) {
|
return match ($type) {
|
||||||
DomainModel::ORDER_PRODUCT_VIP => __('查看会员权益', 'aksrt'),
|
DomainModel::ORDER_PRODUCT_VIP => __('查看会员权益', 'aksrt'),
|
||||||
DomainModel::ORDER_PRODUCT_RECHARGE => __('查看余额', 'aksrt'),
|
DomainModel::ORDER_PRODUCT_RECHARGE => __('查看余额', 'aksrt'),
|
||||||
|
DomainModel::ORDER_PRODUCT_POINTS => __('查看积分', 'aksrt'),
|
||||||
default => __('打开已购内容', 'aksrt'),
|
default => __('打开已购内容', 'aksrt'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -421,7 +425,7 @@ class UserOrders {
|
|||||||
if (!$order) {
|
if (!$order) {
|
||||||
return ['success' => false, 'message' => __('当前订单状态不可支付。', 'aksrt')];
|
return ['success' => false, 'message' => __('当前订单状态不可支付。', 'aksrt')];
|
||||||
}
|
}
|
||||||
if ($this->status_group((string) ($order['status'] ?? '')) === OrderCenterQuery::STATUS_PAID) {
|
if ($this->status_group((string) ($order['status'] ?? '')) === OrderCenterQuery::STATUS_COMPLETED) {
|
||||||
$ledger_key = \AKSRT\Ledger\OperationKey::deterministic('order-payment', [$order_number]);
|
$ledger_key = \AKSRT\Ledger\OperationKey::deterministic('order-payment', [$order_number]);
|
||||||
$history = \AKSRT\Ledger\LedgerQuery::get_instance()->history(['operation_key' => $ledger_key, 'page' => 1, 'per_page' => 1]);
|
$history = \AKSRT\Ledger\LedgerQuery::get_instance()->history(['operation_key' => $ledger_key, 'page' => 1, 'per_page' => 1]);
|
||||||
if (!empty($history['items'][0])) {
|
if (!empty($history['items'][0])) {
|
||||||
|
|||||||
@@ -168,3 +168,39 @@ test('admin ledger keeps cash minor values as decimal strings', () => {
|
|||||||
assert.match(controller, /decimal_from_minor/)
|
assert.match(controller, /decimal_from_minor/)
|
||||||
assert.doesNotMatch(page, /\/\s*100(?:\D|$)/)
|
assert.doesNotMatch(page, /\/\s*100(?:\D|$)/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('asset purchases share the order center and refresh every wallet surface', () => {
|
||||||
|
const domain = fs.readFileSync(path.join(root, 'src', 'Core', 'DomainModel.php'), 'utf8')
|
||||||
|
const query = fs.readFileSync(path.join(root, 'src', 'Payment', 'OrderCenterQuery.php'), 'utf8')
|
||||||
|
const userOrders = fs.readFileSync(path.join(root, 'src', 'Payment', 'UserOrders.php'), 'utf8')
|
||||||
|
const repository = fs.readFileSync(path.join(root, 'src', 'Payment', 'OrderRepositoryCore.php'), 'utf8')
|
||||||
|
const balanceRest = fs.readFileSync(path.join(root, 'src', 'Credits', 'BalanceServiceRest.php'), 'utf8')
|
||||||
|
const chargeCard = fs.readFileSync(path.join(root, 'src', 'Payment', 'ChargeCard.php'), 'utf8')
|
||||||
|
const creditsJs = fs.readFileSync(path.join(root, 'assets', 'js', 'credits.js'), 'utf8')
|
||||||
|
const sidebar = fs.readFileSync(path.join(root, 'inc', 'helpers', 'user-center-renderers', 'sidebar-commerce.php'), 'utf8')
|
||||||
|
const header = fs.readFileSync(path.join(root, 'inc', 'helpers', 'aksrt-header-userbox.php'), 'utf8')
|
||||||
|
|
||||||
|
assert.match(domain, /ORDER_PRODUCT_POINTS\s*=\s*'points'/)
|
||||||
|
assert.match(domain, /self::ORDER_PRODUCT_POINTS\s*=>\s*__\('积分购买'/)
|
||||||
|
for (const status of ['STATUS_PAID', 'STATUS_DELIVERED', 'STATUS_COMPLETED', 'STATUS_PENDING_REVIEW']) {
|
||||||
|
assert.match(query, new RegExp(`Order::${status}`))
|
||||||
|
}
|
||||||
|
assert.match(userOrders, /Order::STATUS_DELIVERED, Order::STATUS_COMPLETED, Order::STATUS_PENDING_REVIEW/)
|
||||||
|
assert.doesNotMatch(userOrders, /OrderCenterQuery::STATUS_PAID/)
|
||||||
|
assert.match(repository, /\$completed_statuses = \[Order::STATUS_PAID, Order::STATUS_DELIVERED, Order::STATUS_COMPLETED, Order::STATUS_PENDING_REVIEW\]/)
|
||||||
|
assert.match(repository, /SUM\(CASE WHEN status IN \(\{\$completed_placeholders\}\) THEN 1 ELSE 0 END\) AS completed/)
|
||||||
|
|
||||||
|
assert.match(balanceRest, /register_rest_route\('aksrt\/v1', '\/pay\/assets'/)
|
||||||
|
assert.match(balanceRest, /'product_type'\s*=>\s*\\AKSRT\\Core\\DomainModel::ORDER_PRODUCT_POINTS/)
|
||||||
|
assert.match(balanceRest, /\['type'\s*=>\s*'order',\s*'key'\s*=>\s*\$order_number\]/)
|
||||||
|
assert.match(balanceRest, /'order_number'\s*=>\s*\$order_number/)
|
||||||
|
assert.match(chargeCard, /self::TYPE_CREDITS[\s\S]*?ORDER_PRODUCT_POINTS/)
|
||||||
|
|
||||||
|
assert.match(creditsJs, /function refreshAssetBalances\(/)
|
||||||
|
assert.match(creditsJs, /querySelectorAll\('\[data-aksrt-wallet-value\]'/)
|
||||||
|
assert.match(creditsJs, /querySelectorAll\('\[data-aksrt-points-value\]'/)
|
||||||
|
assert.match(sidebar, /data-aksrt-wallet-value/)
|
||||||
|
assert.match(sidebar, /data-aksrt-points-value/)
|
||||||
|
assert.match(header, /data-aksrt-wallet-value/)
|
||||||
|
assert.match(header, /data-aksrt-points-value/)
|
||||||
|
})
|
||||||
@@ -366,6 +366,8 @@ test('profile routes load versioned leaf styles and keep dialogs hidden initiall
|
|||||||
assert.match(profileOrders, /data-aksrt-orders-filter-panel hidden/);
|
assert.match(profileOrders, /data-aksrt-orders-filter-panel hidden/);
|
||||||
assert.match(ordersCss, /\.aksrt-orders-page__filter-panel\[hidden\]\s*\{\s*display:\s*none\s*!important;/);
|
assert.match(ordersCss, /\.aksrt-orders-page__filter-panel\[hidden\]\s*\{\s*display:\s*none\s*!important;/);
|
||||||
assert.match(orderCenterJs, /if \(panel\) panel\.hidden = expanded;/);
|
assert.match(orderCenterJs, /if \(panel\) panel\.hidden = expanded;/);
|
||||||
|
assert.match(userCenterJs, /name === 'follow' \|\| name === 'orders'/);
|
||||||
|
assert.match(userCenterJs, /\['order_status', 'order_type', 'order_number', 'order_page'\]/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('public user home stays param-free and swaps panels via REST fragments', () => {
|
test('public user home stays param-free and swaps panels via REST fragments', () => {
|
||||||
|
|||||||
Reference in new issue
Block a user