积分与余额账务系统硬切重构
This commit is contained in:
@@ -48,27 +48,26 @@ if (!function_exists('aksrt_burn_order_coupon')) {
|
||||
|
||||
$coupon = is_array($meta['coupon'] ?? null) ? $meta['coupon'] : [];
|
||||
$coupon_code = sanitize_text_field((string) ($coupon['code'] ?? $meta['coupon_code'] ?? ''));
|
||||
$coupon_discount = (float) ($meta['coupon_discount'] ?? $meta['discount'] ?? ($coupon['discount'] ?? 0));
|
||||
$coupon_discount = (string) ($meta['coupon_discount'] ?? $meta['discount'] ?? ($coupon['discount'] ?? '0.00'));
|
||||
if ($coupon_code === '') {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$coupon_discount = \AKSRT\Ledger\AssetAmount::balance($coupon_discount)->decimal();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$coupon_api = \AKSRT\Payment\Coupon::get_instance();
|
||||
$coupon_api->use_coupon($coupon_code);
|
||||
|
||||
// Prefer snapshot id: post-increment validate may fail on usage_limit edge.
|
||||
$coupon_id = (int) ($coupon['id'] ?? 0);
|
||||
if ($coupon_id <= 0) {
|
||||
$validated = $coupon_api->validate($coupon_code, max(0.01, $coupon_discount), [
|
||||
'user_id' => max(0, $buyer_id),
|
||||
]);
|
||||
$coupon_id = (int) ($validated['coupon']['id'] ?? 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($coupon_id > 0) {
|
||||
$coupon_api->log_usage($coupon_id, max(0, $buyer_id), $order_number, max(0.0, $coupon_discount));
|
||||
if (!$coupon_api->log_usage($coupon_id, max(0, $buyer_id), $order_number, $coupon_discount)) {
|
||||
return aksrt_coupon_usage_exists($order_number);
|
||||
}
|
||||
|
||||
return true;
|
||||
return $coupon_api->use_coupon($coupon_code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,76 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* AKSRT Credits Helper
|
||||
*
|
||||
* 模板层使用的顶层辅助函数:
|
||||
* aksrt_user_credits($user_id = 0) 读取余额
|
||||
* aksrt_format_credits(int $n) 格式化展示
|
||||
* aksrt_credits_label(string $reason) 流水原因 → 友好文案
|
||||
* Unified asset presentation helpers.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_user_credits')) {
|
||||
/**
|
||||
* 取用户当前积分余额。
|
||||
*
|
||||
* @param int $user_id 0 表示当前登录用户
|
||||
* @return int
|
||||
*/
|
||||
function aksrt_user_credits(int $user_id = 0): int {
|
||||
if ($user_id <= 0) $user_id = get_current_user_id();
|
||||
if ($user_id <= 0) return 0;
|
||||
if (!class_exists('\AKSRT\Credits\Credits')) return 0;
|
||||
return \AKSRT\Credits\Credits::balance($user_id);
|
||||
}
|
||||
if (!function_exists('aksrt_user_points')) {
|
||||
function aksrt_user_points(int $user_id = 0): int {
|
||||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||||
return $user_id > 0
|
||||
? \AKSRT\Ledger\LedgerService::get_instance()->balance($user_id, \AKSRT\Ledger\AssetType::POINTS)
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_format_credits')) {
|
||||
function aksrt_format_credits(int $n): string {
|
||||
return number_format_i18n($n);
|
||||
}
|
||||
if (!function_exists('aksrt_user_balance_decimal')) {
|
||||
function aksrt_user_balance_decimal(int $user_id = 0): string {
|
||||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||||
return $user_id > 0
|
||||
? \AKSRT\Ledger\LedgerService::get_instance()->balance_decimal($user_id)
|
||||
: '0.00';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_credits_label')) {
|
||||
/**
|
||||
* 把 reason 字段翻译成展示文案。
|
||||
*/
|
||||
function aksrt_credits_label(string $reason): string {
|
||||
$map = [
|
||||
'register' => __('注册赠送', 'aksrt'),
|
||||
'signin' => __('每日签到', 'aksrt'),
|
||||
'comment' => __('发表评论', 'aksrt'),
|
||||
'referral' => __('推广注册奖励', 'aksrt'),
|
||||
'referral_new_user' => __('推广注册新用户奖励', 'aksrt'),
|
||||
'download' => __('下载消费', 'aksrt'),
|
||||
'admin' => __('管理员调整', 'aksrt'),
|
||||
'refund' => __('退款', 'aksrt'),
|
||||
'free_sign_up' => __('注册奖励', 'aksrt'),
|
||||
'free_sign_in' => __('每日签到', 'aksrt'),
|
||||
'free_login' => __('每日登录', 'aksrt'),
|
||||
'free_followed'=> __('被关注', 'aksrt'),
|
||||
'free_post_new'=> __('发布文章', 'aksrt'),
|
||||
'free_post_like'=> __('文章被赞', 'aksrt'),
|
||||
'free_post_favorite'=> __('文章被收藏', 'aksrt'),
|
||||
'free_comment_new'=> __('发表评论', 'aksrt'),
|
||||
'free_comment_like'=> __('评论被赞', 'aksrt'),
|
||||
'points_exchange_in' => __('余额兑换积分', 'aksrt'),
|
||||
'transfer_in' => __('积分转入', 'aksrt'),
|
||||
'transfer_out' => __('积分转出', 'aksrt'),
|
||||
'transfer_refund' => __('积分转账退款', 'aksrt'),
|
||||
];
|
||||
if (isset($map[$reason])) {
|
||||
return $map[$reason];
|
||||
}
|
||||
if (str_starts_with($reason, 'free_') && class_exists('\AKSRT\Credits\PointsFree')) {
|
||||
$key = substr($reason, 5);
|
||||
$cat = \AKSRT\Credits\PointsFree::catalog();
|
||||
if (isset($cat[$key][0])) {
|
||||
return (string) $cat[$key][0];
|
||||
}
|
||||
}
|
||||
return $reason;
|
||||
}
|
||||
if (!function_exists('aksrt_format_points')) {
|
||||
function aksrt_format_points(int $points): string {
|
||||
return number_format_i18n($points);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_asset_reason_label')) {
|
||||
function aksrt_asset_reason_label(string $reason): string {
|
||||
return \AKSRT\Ledger\LedgerPresentation::reason_label($reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) :
|
||||
'rewards_enabled' => false,
|
||||
'rewards_text' => '',
|
||||
'rewards_btn_text' => '赞赏',
|
||||
'rewards_amounts' => [5, 10, 20, 50, 100],
|
||||
'rewards_amounts' => ['5.00', '10.00', '20.00', '50.00', '100.00'],
|
||||
'rewards_custom' => true,
|
||||
'rewards_min' => 1,
|
||||
'rewards_max' => 1000,
|
||||
'rewards_min' => '1.00',
|
||||
'rewards_max' => '1000.00',
|
||||
'maxheight_enabled' => false,
|
||||
'maxheight' => 1000,
|
||||
'copyright_enabled' => true,
|
||||
|
||||
@@ -77,14 +77,11 @@ if (!function_exists('aksrt_header_user_wallet_mini')) :
|
||||
if ($user_id <= 0) {
|
||||
return '';
|
||||
}
|
||||
$credits = function_exists('aksrt_user_credits') ? (int) aksrt_user_credits($user_id) : 0;
|
||||
$credits = aksrt_user_points($user_id);
|
||||
$currency = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_currency_name()
|
||||
: __('积分', 'aksrt');
|
||||
$wallet = 0.0;
|
||||
if (class_exists('\AKSRT\Credits\Balance')) {
|
||||
$wallet = (float) \AKSRT\Credits\Balance::balance($user_id);
|
||||
}
|
||||
$wallet = aksrt_user_balance_decimal($user_id);
|
||||
$center = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url('credits') : '#';
|
||||
|
||||
$html = '<a class="aksrt-header-wallet flex ac jsb" href="' . esc_url($center) . '">';
|
||||
|
||||
+131
-57
@@ -35,6 +35,30 @@ if (!defined('AKSRT_PAY_TYPE_VIP')) {
|
||||
define('AKSRT_PAY_TYPE_VIP', \AKSRT\Core\DomainModel::PAY_TYPE_VIP);
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_asset_price_minor')) {
|
||||
function aksrt_asset_price_minor($value, string $pay_modo): int {
|
||||
if ($pay_modo === 'points') {
|
||||
return is_int($value) ? max(0, $value) : 0;
|
||||
}
|
||||
if (!is_string($value)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return \AKSRT\Ledger\AssetAmount::balance_minor($value);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_asset_price_value')) {
|
||||
function aksrt_asset_price_value(int $minor, string $pay_modo) {
|
||||
return $pay_modo === 'points'
|
||||
? max(0, $minor)
|
||||
: \AKSRT\Ledger\AssetAmount::decimal_from_minor(max(0, $minor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否为 VIP 豁免用户(免扣积分下载)。
|
||||
*
|
||||
@@ -195,18 +219,18 @@ if (!function_exists('aksrt_get_download_box_meta')) {
|
||||
if (!in_array($pay_limit, [0, 1, 2], true)) {
|
||||
$pay_limit = 0;
|
||||
}
|
||||
$over_price = max(0.0, (float) ($pay_meta['download_limit_over_price'] ?? 0));
|
||||
$over_price = $pay_meta['download_limit_over_price'] ?? ($pay_modo === 'points' ? 0 : '0.00');
|
||||
|
||||
return [
|
||||
'version' => (string) ($pay_meta['version'] ?? ''),
|
||||
'size' => (string) ($pay_meta['size'] ?? ''),
|
||||
'price' => (float) ($pay_meta['price'] ?? 0),
|
||||
'price' => (string) ($pay_meta['price'] ?? '0.00'),
|
||||
'points_price' => (int) ($pay_meta['points_price'] ?? 0),
|
||||
'pay_modo' => $pay_modo,
|
||||
'pay_limit' => $pay_limit,
|
||||
'original_price' => (float) ($pay_meta['original_price'] ?? 0),
|
||||
'vip1_price' => (float) ($pay_meta['vip1_price'] ?? 0),
|
||||
'vip2_price' => (float) ($pay_meta['vip2_price'] ?? 0),
|
||||
'original_price' => (string) ($pay_meta['original_price'] ?? '0.00'),
|
||||
'vip1_price' => (string) ($pay_meta['vip1_price'] ?? '0.00'),
|
||||
'vip2_price' => (string) ($pay_meta['vip2_price'] ?? '0.00'),
|
||||
'vip1_points' => (int) ($pay_meta['vip1_points'] ?? 0),
|
||||
'vip2_points' => (int) ($pay_meta['vip2_points'] ?? 0),
|
||||
'pay_type' => (string) ($pay_meta['pay_type'] ?? AKSRT_PAY_TYPE_NO),
|
||||
@@ -349,8 +373,8 @@ if (!function_exists('aksrt_content_order_cookie_token_key')) {
|
||||
$post_id = (int) ($order['product_id'] ?? $meta['post_id'] ?? 0);
|
||||
$num = (string) ($order['order_number'] ?? '');
|
||||
$amount = function_exists('aksrt_format_price')
|
||||
? aksrt_format_price((float) ($order['amount'] ?? 0))
|
||||
: (string) round((float) ($order['amount'] ?? 0), 2);
|
||||
? aksrt_format_price((string) ($order['amount'] ?? '0.00'))
|
||||
: (string) ($order['amount'] ?? '0.00');
|
||||
return $id . '_' . $post_id . '_' . trim($num) . '_' . $amount . '_' . trim($ip);
|
||||
}
|
||||
}
|
||||
@@ -484,7 +508,7 @@ if (!function_exists('aksrt_guest_has_paid_access')) {
|
||||
*
|
||||
* @param int|WP_Post|null $post
|
||||
* @param int $user_id
|
||||
* @return array{amount:float,base:float,vip_amount:float,modo:string,currency:string,is_free:bool,pay_limit:int,vip_level:int,original:float,vip1:float,vip2:float}
|
||||
* @return array{amount:int|string,base:int|string,vip_amount:int|string|null,modo:string,currency:string,is_free:bool,pay_limit:int,vip_level:int,original:int|string,vip1:int|string,vip2:int|string}
|
||||
*/
|
||||
if (!function_exists('aksrt_get_user_pay_price')) {
|
||||
function aksrt_get_user_pay_price($post = null, int $user_id = 0): array {
|
||||
@@ -512,49 +536,74 @@ if (!function_exists('aksrt_get_user_pay_price')) {
|
||||
}
|
||||
|
||||
if ($pay_modo === 'points') {
|
||||
$base = (float) ($meta['points_price'] ?? 0);
|
||||
$vip1 = (float) ($meta['vip1_points'] ?? 0);
|
||||
$vip2 = (float) ($meta['vip2_points'] ?? 0);
|
||||
$base_minor = max(0, (int) ($meta['points_price'] ?? 0));
|
||||
$vip1_minor = max(0, (int) ($meta['vip1_points'] ?? 0));
|
||||
$vip2_minor = max(0, (int) ($meta['vip2_points'] ?? 0));
|
||||
$currency_label = $currency;
|
||||
} else {
|
||||
$base = (float) ($meta['price'] ?? 0);
|
||||
$vip1 = (float) ($meta['vip1_price'] ?? 0);
|
||||
$vip2 = (float) ($meta['vip2_price'] ?? 0);
|
||||
$parse_cash = static function ($value): int {
|
||||
if (!is_string($value)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return \AKSRT\Ledger\AssetAmount::balance_minor($value);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
$base_minor = $parse_cash($meta['price'] ?? '0');
|
||||
$vip1_minor = $parse_cash($meta['vip1_price'] ?? '0');
|
||||
$vip2_minor = $parse_cash($meta['vip2_price'] ?? '0');
|
||||
$currency_label = $cash_symbol;
|
||||
}
|
||||
|
||||
// Positive VIP tier prices only (0 defaults mean "not configured").
|
||||
$vip_amount = -1.0;
|
||||
if ($vip_level >= 2 && $vip2 > 0) {
|
||||
$vip_amount = $vip2;
|
||||
} elseif ($vip_level >= 1 && $vip1 > 0) {
|
||||
$vip_amount = $vip1;
|
||||
$vip_minor = null;
|
||||
if ($vip_level >= 2 && $vip2_minor > 0) {
|
||||
$vip_minor = $vip2_minor;
|
||||
} elseif ($vip_level >= 1 && $vip1_minor > 0) {
|
||||
$vip_minor = $vip1_minor;
|
||||
}
|
||||
|
||||
$amount = $base;
|
||||
if ($vip_amount >= 0 && ($base <= 0 || $vip_amount < $base)) {
|
||||
$amount = $vip_amount;
|
||||
$amount_minor = $base_minor;
|
||||
if ($vip_minor !== null && ($base_minor <= 0 || $vip_minor < $base_minor)) {
|
||||
$amount_minor = $vip_minor;
|
||||
}
|
||||
|
||||
// Role/VIP free-download exemption (global setting).
|
||||
if ($amount > 0 && $uid > 0 && function_exists('aksrt_is_download_credit_exempt_user') && aksrt_is_download_credit_exempt_user($uid)) {
|
||||
$amount = 0.0;
|
||||
if ($amount_minor > 0 && $uid > 0 && function_exists('aksrt_is_download_credit_exempt_user') && aksrt_is_download_credit_exempt_user($uid)) {
|
||||
$amount_minor = 0;
|
||||
}
|
||||
|
||||
$original = (float) ($meta['original_price'] ?? 0);
|
||||
if ($pay_modo === 'points') {
|
||||
$original = max(0, (int) ($meta['original_price'] ?? 0));
|
||||
$amount = $amount_minor;
|
||||
$base = $base_minor;
|
||||
$vip1 = $vip1_minor;
|
||||
$vip2 = $vip2_minor;
|
||||
$vip_amount = $vip_minor;
|
||||
} else {
|
||||
$original_minor = $parse_cash($meta['original_price'] ?? '0');
|
||||
$amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor($amount_minor);
|
||||
$base = \AKSRT\Ledger\AssetAmount::decimal_from_minor($base_minor);
|
||||
$vip1 = \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip1_minor);
|
||||
$vip2 = \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip2_minor);
|
||||
$vip_amount = $vip_minor === null ? null : \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip_minor);
|
||||
$original = \AKSRT\Ledger\AssetAmount::decimal_from_minor($original_minor);
|
||||
}
|
||||
|
||||
return [
|
||||
'amount' => max(0.0, (float) $amount),
|
||||
'base' => max(0.0, (float) $base),
|
||||
'vip_amount' => $vip_amount >= 0 ? max(0.0, (float) $vip_amount) : -1.0,
|
||||
'amount' => $amount,
|
||||
'base' => $base,
|
||||
'vip_amount' => $vip_amount,
|
||||
'modo' => $pay_modo,
|
||||
'currency' => $currency_label,
|
||||
'is_free' => $amount <= 0,
|
||||
'is_free' => $amount_minor <= 0,
|
||||
'pay_limit' => $pay_limit,
|
||||
'vip_level' => $vip_level,
|
||||
'original' => $original,
|
||||
'vip1' => max(0.0, (float) $vip1),
|
||||
'vip2' => max(0.0, (float) $vip2),
|
||||
'vip1' => $vip1,
|
||||
'vip2' => $vip2,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -585,32 +634,33 @@ if (!function_exists('aksrt_is_content_coupon_allowed')) {
|
||||
* Cash only; mirrors aksrtpay_get_post_rebate_discount.
|
||||
*/
|
||||
if (!function_exists('aksrt_get_post_rebate_discount')) {
|
||||
function aksrt_get_post_rebate_discount($post = null, int $user_id = 0): float {
|
||||
function aksrt_get_post_rebate_discount($post = null, int $user_id = 0): string {
|
||||
$meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post) : [];
|
||||
$fixed = max(0.0, (float) ($meta['pay_rebate_discount'] ?? 0));
|
||||
if ($fixed <= 0) {
|
||||
return 0.0;
|
||||
$fixed = is_string($meta['pay_rebate_discount'] ?? null) ? (string) $meta['pay_rebate_discount'] : '0.00';
|
||||
$fixed_minor = aksrt_asset_price_minor($fixed, '0');
|
||||
if ($fixed_minor <= 0) {
|
||||
return '0.00';
|
||||
}
|
||||
if (!class_exists('\AKSRT\Settings\Settings') || !method_exists('\AKSRT\Settings\Settings', 'get_payment_affiliate_settings')) {
|
||||
return 0.0;
|
||||
return '0.00';
|
||||
}
|
||||
$aff = \AKSRT\Settings\Settings::get_payment_affiliate_settings();
|
||||
if (empty($aff['enabled'])) {
|
||||
return 0.0;
|
||||
return '0.00';
|
||||
}
|
||||
$uid = $user_id > 0 ? $user_id : (function_exists('get_current_user_id') ? (int) get_current_user_id() : 0);
|
||||
$referrer_id = class_exists('\AKSRT\Payment\ReferralAttribution')
|
||||
? \AKSRT\Payment\ReferralAttribution::get_instance()->resolve($uid)
|
||||
: 0;
|
||||
if ($referrer_id <= 0) {
|
||||
return 0.0;
|
||||
return '0.00';
|
||||
}
|
||||
// Need a positive ratio for referrer (VIP tier of referrer preferred).
|
||||
$ratio = (int) round(\AKSRT\Settings\Settings::affiliate_ratio_for_user($referrer_id));
|
||||
$ratio = (int) \AKSRT\Settings\Settings::affiliate_ratio_for_user($referrer_id);
|
||||
if ($ratio <= 0) {
|
||||
return 0.0;
|
||||
return '0.00';
|
||||
}
|
||||
return round($fixed, 2);
|
||||
return \AKSRT\Ledger\AssetAmount::decimal_from_minor($fixed_minor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,10 +752,10 @@ if (!function_exists('aksrt_is_payshow_purchase_enabled')) {
|
||||
|
||||
$pay_modo = ($meta['pay_modo'] ?? '0') === 'points' ? 'points' : '0';
|
||||
$price = $pay_modo === 'points'
|
||||
? (float) ($meta['points_price'] ?? 0)
|
||||
: (float) ($meta['price'] ?? 0);
|
||||
? (int) ($meta['points_price'] ?? 0)
|
||||
: (string) ($meta['price'] ?? '0.00');
|
||||
|
||||
return $price > 0;
|
||||
return aksrt_asset_price_minor($price, $pay_modo) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +801,9 @@ if (!function_exists('aksrt_has_paid_access')) {
|
||||
// 兜底:仅在 service 不可用时使用,避免离线环境直接拒绝。
|
||||
$meta = aksrt_get_pay_meta($p);
|
||||
if ($meta['pay_type'] === AKSRT_PAY_TYPE_NO) return true;
|
||||
if ((float) $meta['price'] <= 0 && $meta['pay_type'] !== AKSRT_PAY_TYPE_VIP) return true;
|
||||
$pay_modo = ($meta['pay_modo'] ?? '0') === 'points' ? 'points' : '0';
|
||||
$price = $pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00');
|
||||
if (aksrt_asset_price_minor($price, $pay_modo) <= 0 && $meta['pay_type'] !== AKSRT_PAY_TYPE_VIP) return true;
|
||||
|
||||
$uid = $user_id > 0 ? $user_id : get_current_user_id();
|
||||
|
||||
@@ -843,7 +895,10 @@ if (!function_exists('aksrt_get_download_cost')) {
|
||||
}
|
||||
|
||||
$meta = aksrt_get_pay_meta($post);
|
||||
return (int) ceil((float) $meta['price']);
|
||||
if (($meta['pay_modo'] ?? '0') !== 'points') {
|
||||
return 0;
|
||||
}
|
||||
return max(0, (int) ($meta['points_price'] ?? 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,18 +973,19 @@ if (!function_exists('aksrt_get_pay_price_label')) {
|
||||
'text' => __('会员专属', 'aksrt'),
|
||||
'free' => false,
|
||||
'amount' => 0,
|
||||
'base' => is_array($priced) ? (float) ($priced['base'] ?? 0) : 0,
|
||||
'base' => is_array($priced) ? ($priced['base'] ?? ($pay_modo === 'points' ? 0 : '0.00')) : ($pay_modo === 'points' ? 0 : '0.00'),
|
||||
'modo' => $pay_modo,
|
||||
'pay_limit' => $pay_limit,
|
||||
];
|
||||
}
|
||||
|
||||
$price = is_array($priced)
|
||||
? (float) ($priced['amount'] ?? 0)
|
||||
: ($pay_modo === 'points' ? (float) ($meta['points_price'] ?? 0) : (float) ($meta['price'] ?? 0));
|
||||
$base = is_array($priced) ? (float) ($priced['base'] ?? $price) : $price;
|
||||
? ($priced['amount'] ?? ($pay_modo === 'points' ? 0 : '0.00'))
|
||||
: ($pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'));
|
||||
$base = is_array($priced) ? ($priced['base'] ?? $price) : $price;
|
||||
$price_minor = aksrt_asset_price_minor($price, $pay_modo);
|
||||
|
||||
if ($price <= 0) {
|
||||
if ($price_minor <= 0) {
|
||||
return [
|
||||
'text' => __('免费', 'aksrt'),
|
||||
'free' => true,
|
||||
@@ -963,9 +1019,21 @@ if (!function_exists('aksrt_get_pay_price_label')) {
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_format_price')) {
|
||||
function aksrt_format_price(float $price): string {
|
||||
if (fmod($price, 1.0) === 0.0) return (string) (int) $price;
|
||||
return rtrim(rtrim(number_format($price, 2, '.', ''), '0'), '.');
|
||||
function aksrt_format_price($price): string {
|
||||
if (is_int($price)) {
|
||||
return (string) max(0, $price);
|
||||
}
|
||||
if (!is_string($price)) {
|
||||
return '0';
|
||||
}
|
||||
try {
|
||||
$decimal = \AKSRT\Ledger\AssetAmount::balance($price)->decimal();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return '0';
|
||||
}
|
||||
return str_ends_with($decimal, '.00')
|
||||
? substr($decimal, 0, -3)
|
||||
: rtrim($decimal, '0');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1132,7 +1200,10 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
$pay_type = $meta['pay_type'];
|
||||
$priced = function_exists('aksrt_get_user_pay_price') ? aksrt_get_user_pay_price($post) : null;
|
||||
$pay_modo = is_array($priced) ? ((($priced['modo'] ?? '0') === 'points') ? 'points' : '0') : ((($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0');
|
||||
$price = is_array($priced) ? (float) ($priced['amount'] ?? 0) : (float) ($meta['price'] ?? 0);
|
||||
$price = is_array($priced)
|
||||
? ($priced['amount'] ?? ($pay_modo === 'points' ? 0 : '0.00'))
|
||||
: ($pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'));
|
||||
$price_minor = aksrt_asset_price_minor($price, $pay_modo);
|
||||
$vip_level = is_array($priced) ? (int) ($priced['vip_level'] ?? 0) : 0;
|
||||
$currency = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt');
|
||||
$cash_symbol = '¥';
|
||||
@@ -1156,8 +1227,11 @@ if (!function_exists('aksrt_get_paywall_html')) {
|
||||
}
|
||||
$login_url = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url(get_permalink($post));
|
||||
$is_logged_in = is_user_logged_in();
|
||||
$original_price = (float) ($meta['original_price'] ?? 0);
|
||||
$has_original = $original_price > 0 && $original_price > $price;
|
||||
$original_price = $pay_modo === 'points'
|
||||
? max(0, (int) ($meta['original_price'] ?? 0))
|
||||
: (string) ($meta['original_price'] ?? '0.00');
|
||||
$original_minor = aksrt_asset_price_minor($original_price, $pay_modo);
|
||||
$has_original = $original_minor > 0 && $original_minor > $price_minor;
|
||||
$pay_limit = (int) ($meta['pay_limit'] ?? 0);
|
||||
$member_blocked = $pay_limit > 0 && $vip_level < $pay_limit;
|
||||
$vip_url = function_exists('aksrt_get_user_center_tab_url')
|
||||
|
||||
@@ -67,13 +67,13 @@ if (!function_exists('aksrt_get_resource_meta')) {
|
||||
return [
|
||||
'version' => (string) ($pay_meta['version'] ?? ''),
|
||||
'size' => (string) ($pay_meta['size'] ?? ''),
|
||||
'price' => (float) ($pay_meta['price'] ?? 0),
|
||||
'price' => (string) ($pay_meta['price'] ?? '0.00'),
|
||||
'points_price' => (int) ($pay_meta['points_price'] ?? 0),
|
||||
'pay_modo' => (($pay_meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0',
|
||||
'pay_limit' => in_array((int) ($pay_meta['pay_limit'] ?? 0), [0, 1, 2], true) ? (int) $pay_meta['pay_limit'] : 0,
|
||||
'original_price' => (float) ($pay_meta['original_price'] ?? 0),
|
||||
'vip1_price' => (float) ($pay_meta['vip1_price'] ?? 0),
|
||||
'vip2_price' => (float) ($pay_meta['vip2_price'] ?? 0),
|
||||
'original_price' => (string) ($pay_meta['original_price'] ?? '0.00'),
|
||||
'vip1_price' => (string) ($pay_meta['vip1_price'] ?? '0.00'),
|
||||
'vip2_price' => (string) ($pay_meta['vip2_price'] ?? '0.00'),
|
||||
'vip1_points' => (int) ($pay_meta['vip1_points'] ?? 0),
|
||||
'vip2_points' => (int) ($pay_meta['vip2_points'] ?? 0),
|
||||
'pay_type' => (string) ($pay_meta['pay_type'] ?? \AKSRT\Core\DomainModel::PAY_TYPE_DOWNLOAD),
|
||||
@@ -99,13 +99,13 @@ if (!function_exists('aksrt_default_resource_meta')) {
|
||||
return [
|
||||
'version' => (string) ($meta['version'] ?? ''),
|
||||
'size' => (string) ($meta['size'] ?? ''),
|
||||
'price' => (float) ($meta['price'] ?? 0),
|
||||
'price' => (string) ($meta['price'] ?? '0.00'),
|
||||
'points_price' => (int) ($meta['points_price'] ?? 0),
|
||||
'pay_modo' => (($meta['pay_modo'] ?? '0') === 'points') ? 'points' : '0',
|
||||
'pay_limit' => in_array((int) ($meta['pay_limit'] ?? 0), [0, 1, 2], true) ? (int) $meta['pay_limit'] : 0,
|
||||
'original_price' => (float) ($meta['original_price'] ?? 0),
|
||||
'vip1_price' => (float) ($meta['vip1_price'] ?? 0),
|
||||
'vip2_price' => (float) ($meta['vip2_price'] ?? 0),
|
||||
'original_price' => (string) ($meta['original_price'] ?? '0.00'),
|
||||
'vip1_price' => (string) ($meta['vip1_price'] ?? '0.00'),
|
||||
'vip2_price' => (string) ($meta['vip2_price'] ?? '0.00'),
|
||||
'vip1_points' => (int) ($meta['vip1_points'] ?? 0),
|
||||
'vip2_points' => (int) ($meta['vip2_points'] ?? 0),
|
||||
'pay_type' => \AKSRT\Core\DomainModel::PAY_TYPE_DOWNLOAD,
|
||||
@@ -128,19 +128,18 @@ if (!function_exists('aksrt_resource_price_label')) {
|
||||
/**
|
||||
* 把价格数字渲染成展示徽章文案。
|
||||
*
|
||||
* @param float $price
|
||||
* @param int $price
|
||||
* @return array { text:string, free:bool }
|
||||
*/
|
||||
function aksrt_resource_price_label(float $price): array {
|
||||
function aksrt_resource_price_label(int $price): array {
|
||||
if ($price <= 0) {
|
||||
return [
|
||||
'text' => __('免费', 'aksrt'),
|
||||
'free' => true,
|
||||
];
|
||||
}
|
||||
$n = (fmod($price, 1.0) === 0.0) ? (string) (int) $price : rtrim(rtrim(number_format($price, 2, '.', ''), '0'), '.');
|
||||
return [
|
||||
'text' => sprintf(__('%s 积分', 'aksrt'), $n),
|
||||
'text' => sprintf(__('%s 积分', 'aksrt'), (string) $price),
|
||||
'free' => false,
|
||||
];
|
||||
}
|
||||
@@ -150,15 +149,11 @@ if (!function_exists('aksrt_resource_price_amount')) {
|
||||
/**
|
||||
* Format the raw resource price number for compact UI labels.
|
||||
*
|
||||
* @param float $price
|
||||
* @param int $price
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_resource_price_amount(float $price): string {
|
||||
if (fmod($price, 1.0) === 0.0) {
|
||||
return (string) (int) $price;
|
||||
}
|
||||
|
||||
return rtrim(rtrim(number_format($price, 2, '.', ''), '0'), '.');
|
||||
function aksrt_resource_price_amount(int $price): string {
|
||||
return (string) max(0, $price);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,14 +196,15 @@ if (!function_exists('aksrt_resource_card_badge_text')) {
|
||||
$priced = function_exists('aksrt_get_user_pay_price')
|
||||
? aksrt_get_user_pay_price($p)
|
||||
: [
|
||||
'amount' => $pay_modo === 'points' ? (float) ($meta['points_price'] ?? 0) : (float) ($meta['price'] ?? 0),
|
||||
'amount' => $pay_modo === 'points' ? (int) ($meta['points_price'] ?? 0) : (string) ($meta['price'] ?? '0.00'),
|
||||
'modo' => $pay_modo,
|
||||
];
|
||||
$price = (float) ($priced['amount'] ?? 0);
|
||||
$price = $priced['amount'] ?? ($pay_modo === 'points' ? 0 : '0.00');
|
||||
$pay_modo = (($priced['modo'] ?? $pay_modo) === 'points') ? 'points' : '0';
|
||||
$price_minor = function_exists('aksrt_asset_price_minor') ? aksrt_asset_price_minor($price, $pay_modo) : 0;
|
||||
|
||||
// Free paid-type (price 0).
|
||||
if ($price <= 0) {
|
||||
if ($price_minor <= 0) {
|
||||
if ($pay_type === 'download') {
|
||||
return __('免费资源', 'aksrt');
|
||||
}
|
||||
@@ -218,7 +214,7 @@ if (!function_exists('aksrt_resource_card_badge_text')) {
|
||||
if ($pay_modo === 'points') {
|
||||
$currency = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt');
|
||||
$amount = function_exists('aksrt_resource_price_amount')
|
||||
? aksrt_resource_price_amount($price)
|
||||
? aksrt_resource_price_amount($price_minor)
|
||||
: (string) (int) $price;
|
||||
return sprintf('%s %s%s', $type_name, $amount, $currency);
|
||||
}
|
||||
@@ -461,13 +457,11 @@ if (!function_exists('aksrt_resource_download_cost')) {
|
||||
}
|
||||
|
||||
if (is_array($priced)) {
|
||||
$price = (float) ($priced['amount'] ?? 0);
|
||||
return $price > 0 ? (int) ceil($price) : 0;
|
||||
return is_int($priced['amount'] ?? null) ? max(0, (int) $priced['amount']) : 0;
|
||||
}
|
||||
|
||||
$meta = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post) : [];
|
||||
$price = (float) ($meta['points_price'] ?? $meta['price'] ?? 0);
|
||||
return $price > 0 ? (int) ceil($price) : 0;
|
||||
return max(0, (int) ($meta['points_price'] ?? 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,17 @@ if (!function_exists('aksrt_render_rewards_modal_for_user')) {
|
||||
$done[$key] = true;
|
||||
$settings = \AKSRT\Settings\Settings::get_post_page_settings();
|
||||
$amounts = (array) ($settings['rewards_amounts'] ?? [5, 10, 20, 50, 100]);
|
||||
$render_amounts = [];
|
||||
foreach ($amounts as $amount) {
|
||||
try {
|
||||
$parsed = \AKSRT\Ledger\AssetAmount::balance(is_string($amount) ? $amount : '');
|
||||
if ($parsed->minor() > 0) {
|
||||
$render_amounts[] = $parsed->decimal();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$recipient = get_userdata($user_id);
|
||||
?>
|
||||
<div class="reward-modal" id="reward-modal-<?php echo (int) $user_id; ?>" data-user-id="<?php echo (int) $user_id; ?>" data-post-id="<?php echo (int) $post_id; ?>" aria-hidden="true">
|
||||
@@ -54,8 +65,8 @@ if (!function_exists('aksrt_render_rewards_modal_for_user')) {
|
||||
<h3 id="reward-title-<?php echo (int) $user_id; ?>"><?php echo esc_html((string) ($settings['rewards_text'] ?? __('赞赏', 'aksrt'))); ?></h3>
|
||||
<p class="muted-2-color em09"><?php printf(esc_html__('赞赏将直接进入 %s 的站内余额', 'aksrt'), esc_html($recipient ? $recipient->display_name : __('作者', 'aksrt'))); ?></p>
|
||||
<div class="reward-amounts" data-aksrt-reward-amounts>
|
||||
<?php foreach ($amounts as $index => $amount) : ?>
|
||||
<button type="button" class="reward-amount<?php echo $index === 0 ? ' is-active' : ''; ?>" data-reward-amount="<?php echo esc_attr(number_format((float) $amount, 2, '.', '')); ?>">¥<?php echo esc_html(number_format_i18n((float) $amount, 2)); ?></button>
|
||||
<?php foreach ($render_amounts as $index => $amount) : ?>
|
||||
<button type="button" class="reward-amount<?php echo $index === 0 ? ' is-active' : ''; ?>" data-reward-amount="<?php echo esc_attr($amount); ?>">¥<?php echo esc_html($amount); ?></button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if (!empty($settings['rewards_custom'])) : ?>
|
||||
@@ -75,7 +86,8 @@ add_action('wp_ajax_aksrt_submit_tip', function (): void {
|
||||
if (!is_user_logged_in()) {
|
||||
wp_send_json_error(['message' => __('请先登录后赞赏', 'aksrt')], 401);
|
||||
}
|
||||
if (!aksrt_rewards_enabled() || !class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
|
||||
$recharge = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_recharge_settings() : [];
|
||||
if (!aksrt_rewards_enabled() || empty($recharge['enabled'])) {
|
||||
wp_send_json_error(['message' => __('赞赏功能当前不可用', 'aksrt')], 400);
|
||||
}
|
||||
|
||||
@@ -94,40 +106,63 @@ add_action('wp_ajax_aksrt_submit_tip', function (): void {
|
||||
}
|
||||
|
||||
$settings = \AKSRT\Settings\Settings::get_post_page_settings();
|
||||
$amount = isset($_POST['amount']) ? round((float) wp_unslash($_POST['amount']), 2) : 0.0;
|
||||
$minimum = (float) ($settings['rewards_min'] ?? 1);
|
||||
$maximum = (float) ($settings['rewards_max'] ?? 1000);
|
||||
if (!is_finite($amount) || $amount < $minimum || $amount > $maximum) {
|
||||
wp_send_json_error(['message' => sprintf(__('赞赏金额需在 ¥%1$s 至 ¥%2$s 之间', 'aksrt'), number_format_i18n($minimum, 2), number_format_i18n($maximum, 2))], 400);
|
||||
$raw_amount = isset($_POST['amount']) ? (string) wp_unslash($_POST['amount']) : '';
|
||||
try {
|
||||
$amount = \AKSRT\Ledger\AssetAmount::balance($raw_amount);
|
||||
$minimum = \AKSRT\Ledger\AssetAmount::balance(is_string($settings['rewards_min'] ?? null) ? $settings['rewards_min'] : '');
|
||||
$maximum = \AKSRT\Ledger\AssetAmount::balance(is_string($settings['rewards_max'] ?? null) ? $settings['rewards_max'] : '');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
wp_send_json_error(['message' => __('赞赏金额格式无效', 'aksrt')], 400);
|
||||
}
|
||||
if ($amount->minor() < $minimum->minor() || $amount->minor() > $maximum->minor()) {
|
||||
wp_send_json_error(['message' => sprintf(__('赞赏金额需在 ¥%1$s 至 ¥%2$s 之间', 'aksrt'), $minimum->formatted(), $maximum->formatted())], 400);
|
||||
}
|
||||
if (empty($settings['rewards_custom'])) {
|
||||
$allowed_amounts = array_map(static fn($value): float => round((float) $value, 2), (array) ($settings['rewards_amounts'] ?? []));
|
||||
if (!in_array($amount, $allowed_amounts, true)) {
|
||||
$allowed_amounts = [];
|
||||
foreach ((array) ($settings['rewards_amounts'] ?? []) as $allowed) {
|
||||
try {
|
||||
$allowed_amounts[] = \AKSRT\Ledger\AssetAmount::balance(is_string($allowed) ? $allowed : '')->minor();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!in_array($amount->minor(), $allowed_amounts, true)) {
|
||||
wp_send_json_error(['message' => __('请选择预设的赞赏金额', 'aksrt')], 400);
|
||||
}
|
||||
}
|
||||
$request_key = sanitize_text_field(wp_unslash((string) ($_SERVER['HTTP_IDEMPOTENCY_KEY'] ?? '')));
|
||||
if (!wp_is_uuid($request_key)) {
|
||||
wp_send_json_error(['message' => __('缺少或无效的 Idempotency-Key 请求头', 'aksrt')], 400);
|
||||
}
|
||||
$operation_key = \AKSRT\Ledger\OperationKey::deterministic('client-tip', [$sender_id, strtolower($request_key)]);
|
||||
|
||||
$rate_key = 'aksrt_tip_rate_' . $sender_id;
|
||||
if (get_transient($rate_key)) {
|
||||
$recent_operation = (string) get_transient($rate_key);
|
||||
if ($recent_operation !== '' && !hash_equals($recent_operation, $operation_key)) {
|
||||
wp_send_json_error(['message' => __('操作太频繁,请稍后再试', 'aksrt')], 429);
|
||||
}
|
||||
set_transient($rate_key, 1, 3);
|
||||
set_transient($rate_key, $operation_key, 3);
|
||||
|
||||
$result = \AKSRT\Credits\Balance::transfer(
|
||||
$result = \AKSRT\Ledger\LedgerService::get_instance()->transfer(
|
||||
$sender_id,
|
||||
$recipient_id,
|
||||
$amount,
|
||||
'tip_sent',
|
||||
'tip_received',
|
||||
\AKSRT\Ledger\AssetType::BALANCE,
|
||||
$amount->minor(),
|
||||
0,
|
||||
$operation_key,
|
||||
'tip',
|
||||
['type' => 'tip', 'id' => $post_id],
|
||||
$post_id > 0 ? sprintf(__('赞赏文章 #%d', 'aksrt'), $post_id) : __('用户赞赏', 'aksrt')
|
||||
$post_id > 0 ? sprintf(__('赞赏文章 #%d', 'aksrt'), $post_id) : __('用户赞赏', 'aksrt'),
|
||||
__('收到用户赞赏', 'aksrt')
|
||||
);
|
||||
if (is_wp_error($result)) {
|
||||
wp_send_json_error(['message' => $result->get_error_message()], 400);
|
||||
wp_send_json_error(['message' => $result->get_error_message()], (int) ($result->get_error_data()['status'] ?? 400));
|
||||
}
|
||||
|
||||
wp_send_json_success([
|
||||
'message' => __('赞赏成功,金额已进入对方余额', 'aksrt'),
|
||||
'balance' => \AKSRT\Credits\Balance::format((float) $result['sender_balance']),
|
||||
'transaction_id' => $result->transaction_id,
|
||||
'replayed' => $result->replayed,
|
||||
'balance' => \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, $result->balance($sender_id, \AKSRT\Ledger\AssetType::BALANCE))->decimal(),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -48,54 +48,3 @@ function aksrt_get_orders_page_view(int $user_id, int $paged = 1, int $per_page
|
||||
|
||||
return $empty;
|
||||
}
|
||||
|
||||
function aksrt_get_revenue_page_view(int $user_id): array {
|
||||
$balance = 0.0;
|
||||
$total_earned = 0.0;
|
||||
$total_withdrawn = 0.0;
|
||||
$records = [];
|
||||
|
||||
if (class_exists('\AKSRT\Credits\Balance')) {
|
||||
$balance = (float) \AKSRT\Credits\Balance::balance($user_id);
|
||||
}
|
||||
|
||||
if (class_exists('\AKSRT\Payment\Revenue')) {
|
||||
$revenues = \AKSRT\Payment\Revenue::get_instance()->get_user_revenues($user_id, ['limit' => 200]);
|
||||
foreach ($revenues as $rev) {
|
||||
$row = is_array($rev) ? $rev : (array) $rev;
|
||||
$total_earned += (float) ($row['amount'] ?? 0);
|
||||
$records[] = [
|
||||
'type' => 'earning',
|
||||
'title' => (string) ($row['description'] ?? $row['type'] ?? __('创作分成', 'aksrt')),
|
||||
'amount' => (float) ($row['amount'] ?? 0),
|
||||
'created_at' => (string) ($row['created_at'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('\AKSRT\Payment\Withdrawal')) {
|
||||
$withdrawals = \AKSRT\Payment\Withdrawal::get_instance()->get_user_withdrawals($user_id, ['limit' => 200]);
|
||||
foreach ($withdrawals as $w) {
|
||||
$wrow = is_array($w) ? $w : (array) $w;
|
||||
$total_withdrawn += (float) ($wrow['amount'] ?? 0);
|
||||
$records[] = [
|
||||
'type' => 'withdrawal',
|
||||
'title' => __('提现', 'aksrt'),
|
||||
'amount' => (float) ($wrow['amount'] ?? 0),
|
||||
'created_at' => (string) ($wrow['created_at'] ?? ''),
|
||||
'status' => (string) ($wrow['status'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
usort($records, static function ($a, $b) {
|
||||
return strcmp($b['created_at'] ?? '', $a['created_at'] ?? '');
|
||||
});
|
||||
|
||||
return [
|
||||
'balance' => $balance,
|
||||
'total_earned' => $total_earned,
|
||||
'total_withdrawn' => $total_withdrawn,
|
||||
'records' => $records,
|
||||
];
|
||||
}
|
||||
@@ -70,16 +70,16 @@ function aksrt_get_user_dashboard_view(int $user_id, array $args = []): array {
|
||||
$background_url = function_exists('aksrt_get_user_cover_url') ? aksrt_get_user_cover_url($user_id) : '';
|
||||
|
||||
$credits_enabled = class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::credits_enabled();
|
||||
$credit_balance = $credits_enabled && $is_own_profile && function_exists('aksrt_user_credits')
|
||||
? (float) aksrt_user_credits($user_id)
|
||||
$credit_balance = $credits_enabled && $is_own_profile
|
||||
? (float) aksrt_user_points($user_id)
|
||||
: 0.0;
|
||||
$currency_name = $credits_enabled && class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_currency_name()
|
||||
: __('积分', 'aksrt');
|
||||
|
||||
// Cash wallet (legacy pay_balance) — separate from points.
|
||||
$balance_enabled = $is_own_profile && class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled();
|
||||
$wallet_balance = $balance_enabled ? \AKSRT\Credits\Balance::balance($user_id) : 0.0;
|
||||
$recharge = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_recharge_settings() : [];
|
||||
$balance_enabled = $is_own_profile && !empty($recharge['enabled']);
|
||||
$wallet_balance = $balance_enabled ? aksrt_user_balance_decimal($user_id) : '0.00';
|
||||
|
||||
$user_home_manager = $include_governance && class_exists('\AKSRT\User\Home')
|
||||
? \AKSRT\User\Home::get_instance()
|
||||
|
||||
@@ -307,7 +307,7 @@ if (!function_exists('aksrt_check_free_download_quota')) {
|
||||
];
|
||||
// Optional overbuy price for free-quota exhausted (legacy download_limit_over_price).
|
||||
// Callers may pass post context via filter.
|
||||
$over = apply_filters('aksrt_download_limit_over_price', 0.0, $user_id);
|
||||
$over = apply_filters('aksrt_download_limit_over_price', 0, $user_id);
|
||||
if ($over > 0) {
|
||||
$data['download_limit_over_price'] = $over;
|
||||
$data['allow_limit_over'] = true;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$balance = (float) ($credit_balance ?? 0.0);
|
||||
$balance = max(0, (int) ($credit_balance ?? 0));
|
||||
$credits_enabled = !empty($credits_enabled);
|
||||
if (!$credits_enabled) {
|
||||
return;
|
||||
@@ -26,7 +26,8 @@ if ($points_transfer_on && class_exists('\AKSRT\Settings\Capabilities') && !\AKS
|
||||
}
|
||||
$points_transfer_min = max(1, (int) ($all_settings['points_transfer_min'] ?? 1));
|
||||
$points_exchange = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_recharge_settings()['points_exchange'] ?? [] : [];
|
||||
$points_exchange_on = !empty($points_exchange['enabled']) && class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled();
|
||||
$recharge = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_recharge_settings() : [];
|
||||
$points_exchange_on = !empty($points_exchange['enabled']) && !empty($recharge['enabled']);
|
||||
$currency = (string) ($currency_name ?? __('积分', 'aksrt'));
|
||||
?>
|
||||
<div class="uc-asset-card uc-asset-card--points">
|
||||
@@ -45,7 +46,7 @@ $currency = (string) ($currency_name ?? __('积分', 'aksrt'));
|
||||
</div>
|
||||
<div class="uc-asset-card__body flex jsb ac">
|
||||
<div class="uc-asset-card__amount c-green">
|
||||
<span class="uc-asset-card__value font-bold"><?php echo esc_html(function_exists('aksrt_format_credits') ? aksrt_format_credits((int) $balance) : (string) (int) $balance); ?></span>
|
||||
<span class="uc-asset-card__value font-bold"><?php echo esc_html(aksrt_format_points($balance)); ?></span>
|
||||
</div>
|
||||
<div class="uc-asset-card__actions flex0">
|
||||
<?php if ($points_transfer_on) : ?>
|
||||
@@ -74,7 +75,7 @@ $currency = (string) ($currency_name ?? __('积分', 'aksrt'));
|
||||
<?php endif; ?>
|
||||
<form data-aksrt-points-exchange-form>
|
||||
<label class="muted-color em09"><?php esc_html_e('兑换余额', 'aksrt'); ?></label>
|
||||
<input type="number" class="uc-card-pass__input" name="amount" min="1" step="1" inputmode="numeric" data-aksrt-points-exchange-amount data-aksrt-points-exchange-rate="<?php echo esc_attr((string) $pb_rate); ?>">
|
||||
<input type="number" class="uc-card-pass__input" name="amount" min="0.01" step="0.01" inputmode="decimal" data-aksrt-points-exchange-amount data-aksrt-points-exchange-rate="<?php echo esc_attr((string) $pb_rate); ?>">
|
||||
<p class="muted-2-color em09 mt6"><?php printf(esc_html__('1 余额 = %d 积分;单笔至少 %d 积分,每日最多 %d 积分。', 'aksrt'), $pb_rate, $pb_min_points, $pb_daily_max_points); ?></p>
|
||||
<p class="muted-2-color em09 mt6" data-aksrt-points-exchange-preview></p>
|
||||
<button type="submit" class="but jb-blue btn-block mt10"><?php esc_html_e('立即购买', 'aksrt'); ?></button>
|
||||
|
||||
@@ -18,16 +18,12 @@ defined('ABSPATH') || exit;
|
||||
</div>
|
||||
<?php
|
||||
$credits_page = max(1, isset($_GET['credits_page']) ? (int) $_GET['credits_page'] : 1);
|
||||
if (class_exists('\AKSRT\Credits\Credits')) {
|
||||
$log = \AKSRT\Credits\Credits::get_log(['user_id' => $user_id, 'page' => $credits_page, 'per_page' => 10]);
|
||||
} else {
|
||||
$log = ['items' => [], 'total' => 0];
|
||||
}
|
||||
$log = \AKSRT\Ledger\LedgerQuery::get_instance()->history(['user_id' => $user_id, 'asset' => 'points', 'page' => $credits_page, 'per_page' => 10]);
|
||||
if (!empty($log['items'])) :
|
||||
?>
|
||||
<div class="uc-transactions__list">
|
||||
<?php foreach ($log['items'] as $row) :
|
||||
$delta = (int) $row['delta'];
|
||||
$delta = (int) $row['delta_minor'];
|
||||
$delta_class = $delta >= 0 ? 'is-positive' : 'is-negative';
|
||||
?>
|
||||
<div class="uc-transactions__item">
|
||||
@@ -36,7 +32,7 @@ defined('ABSPATH') || exit;
|
||||
</div>
|
||||
<div class="uc-transactions__info">
|
||||
<div class="uc-transactions__reason">
|
||||
<?php echo esc_html(aksrt_credits_label((string) $row['reason'])); ?>
|
||||
<?php echo esc_html(aksrt_asset_reason_label((string) $row['reason'])); ?>
|
||||
<?php if (!empty($row['remark'])) : ?>
|
||||
<span class="uc-transactions__remark">(<?php echo esc_html((string) $row['remark']); ?>)</span>
|
||||
<?php endif; ?>
|
||||
@@ -44,6 +40,7 @@ defined('ABSPATH') || exit;
|
||||
<div class="uc-transactions__time">
|
||||
<?php echo esc_html(get_date_from_gmt((string) $row['created_at'], 'Y-m-d H:i')); ?>
|
||||
</div>
|
||||
<?php if (!empty($row['counterparty_user_id'])) : ?><div class="muted-2-color em09"><?php printf(esc_html__('对方用户 #%d', 'aksrt'), (int) $row['counterparty_user_id']); ?></div><?php endif; ?>
|
||||
</div>
|
||||
<div class="uc-transactions__amount">
|
||||
<span class="uc-transactions__delta <?php echo esc_attr($delta_class); ?>">
|
||||
@@ -52,9 +49,11 @@ defined('ABSPATH') || exit;
|
||||
<span class="uc-transactions__balance">
|
||||
<?php
|
||||
/* translators: %s: balance */
|
||||
printf(esc_html__('余额 %s', 'aksrt'), esc_html((string) (int) $row['balance_after']));
|
||||
printf(esc_html__('余额 %s', 'aksrt'), esc_html((string) (int) $row['balance_after_minor']));
|
||||
?>
|
||||
</span>
|
||||
<?php if ((int) ($row['fee_minor'] ?? 0) > 0) : ?><span class="muted-2-color em09"><?php printf(esc_html__('手续费 %d', 'aksrt'), (int) $row['fee_minor']); ?></span><?php endif; ?>
|
||||
<span class="muted-2-color em09"><?php printf(esc_html__('交易 #%d', 'aksrt'), (int) $row['id']); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
@@ -13,10 +13,15 @@ if (empty($balance_enabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wallet = (float) ($wallet_balance ?? 0.0);
|
||||
$wallet_fmt = class_exists('\AKSRT\Credits\Balance')
|
||||
? \AKSRT\Credits\Balance::format($wallet)
|
||||
: number_format_i18n($wallet, 2);
|
||||
$normalize_balance = static function ($value): \AKSRT\Ledger\AssetAmount {
|
||||
try {
|
||||
return \AKSRT\Ledger\AssetAmount::balance(is_string($value) ? $value : '');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return \AKSRT\Ledger\AssetAmount::balance('0');
|
||||
}
|
||||
};
|
||||
$wallet = $normalize_balance($wallet_balance ?? '0');
|
||||
$wallet_fmt = $wallet->formatted();
|
||||
|
||||
$recharge = class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_payment_recharge_settings')
|
||||
? \AKSRT\Settings\Settings::get_payment_recharge_settings()
|
||||
@@ -32,9 +37,9 @@ if ($withdraw_on && class_exists('\AKSRT\Settings\Capabilities') && !\AKSRT\Sett
|
||||
$withdraw_on = false;
|
||||
}
|
||||
$withdraw_settings = class_exists('\\AKSRT\\Settings\\Settings') ? \AKSRT\Settings\Settings::get_withdrawal_settings() : [];
|
||||
$withdraw_min = max(0, (float) ($withdraw_settings['min_amount'] ?? 50));
|
||||
$withdraw_usage = ['remaining_count' => 0, 'remaining_amount' => 0];
|
||||
$withdraw_pending_hold = 0.0;
|
||||
$withdraw_min = $normalize_balance($withdraw_settings['min_amount'] ?? '50')->decimal();
|
||||
$withdraw_usage = ['remaining_count' => 0, 'remaining_amount' => '0.00'];
|
||||
$withdraw_pending_hold = '0.00';
|
||||
$withdraw_history = [];
|
||||
if ($withdraw_on && class_exists('\AKSRT\Payment\Withdrawal')) {
|
||||
$wd_svc = \AKSRT\Payment\Withdrawal::get_instance();
|
||||
@@ -42,7 +47,7 @@ if ($withdraw_on && class_exists('\AKSRT\Payment\Withdrawal')) {
|
||||
$withdraw_history = $wd_svc->get_user_withdrawals((int) ($user_id ?? 0), ['limit' => 30]);
|
||||
$withdraw_usage = $wd_svc->daily_usage((int) ($user_id ?? 0), $withdraw_settings);
|
||||
}
|
||||
$withdraw_processing = $withdraw_pending_hold > 0;
|
||||
$withdraw_processing = $normalize_balance($withdraw_pending_hold)->minor() > 0;
|
||||
$card_pass_balance = ['enabled' => false, 'desc' => '', 'only_password' => true];
|
||||
if (class_exists('\AKSRT\Payment\ChargeCard')) {
|
||||
$opts = \AKSRT\Payment\ChargeCard::get_instance()->get_public_options();
|
||||
@@ -90,7 +95,7 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元');
|
||||
</div>
|
||||
<?php if ($withdraw_on) : ?>
|
||||
<div class="uc-asset-card__foot muted-2-color em09 mt6">
|
||||
<span><?php printf(esc_html__('冻结中 %s', 'aksrt'), esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format((float) $withdraw_pending_hold) : number_format_i18n((float) $withdraw_pending_hold, 2))); ?></span>
|
||||
<span><?php printf(esc_html__('冻结中 %s', 'aksrt'), esc_html($normalize_balance($withdraw_pending_hold)->formatted())); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -128,13 +133,17 @@ $mark = (string) ($charge_view['currency_mark'] ?? '元');
|
||||
<?php if ($packages) : ?>
|
||||
<div class="muted-color mb6"><?php esc_html_e('请选择充值金额', 'aksrt'); ?></div>
|
||||
<div class="uc-charge-packages">
|
||||
<?php foreach ($packages as $idx => $pkg) : ?>
|
||||
<?php foreach ($packages as $idx => $pkg) :
|
||||
$package_credit = $normalize_balance($pkg['price'] ?? '');
|
||||
$package_pay = $normalize_balance($pkg['pay_price'] ?? '');
|
||||
$package_saving_minor = max(0, $package_credit->minor() - $package_pay->minor());
|
||||
?>
|
||||
<label class="uc-charge-package<?php echo $idx === 0 ? ' is-active' : ''; ?>">
|
||||
<input type="radio" name="balance_package" value="<?php echo esc_attr((string) $pkg['key']); ?>" <?php checked($idx === 0); ?>>
|
||||
<div class="uc-charge-package__credit"><span class="px12">¥</span><?php echo esc_html((string) $pkg['price']); ?></div>
|
||||
<div class="uc-charge-package__pay c-red"><span class="px12">¥</span><?php echo esc_html((string) $pkg['pay_price']); ?>
|
||||
<?php if ((float) $pkg['pay_price'] < (float) $pkg['price']) : ?>
|
||||
<span class="ml6 c-yellow smail"><?php printf(esc_html__('省%s', 'aksrt'), esc_html((string) ((float) $pkg['price'] - (float) $pkg['pay_price']))); ?></span>
|
||||
<?php if ($package_saving_minor > 0) : ?>
|
||||
<span class="ml6 c-yellow smail"><?php printf(esc_html__('省%s', 'aksrt'), esc_html(\AKSRT\Ledger\AssetAmount::decimal_from_minor($package_saving_minor))); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($pkg['tag'])) : ?>
|
||||
@@ -195,19 +204,19 @@ endif; ?>
|
||||
<?php if (!empty($withdraw_history)) : ?>
|
||||
<?php foreach ($withdraw_history as $wd) :
|
||||
$st = sanitize_key((string) ($wd['status'] ?? ''));
|
||||
$gross = (float) ($wd['gross_amount'] ?? $wd['amount'] ?? 0);
|
||||
$net = (float) ($wd['amount'] ?? 0);
|
||||
$gross = $normalize_balance($wd['gross_amount'] ?? $wd['amount'] ?? '0');
|
||||
$net = $normalize_balance($wd['amount'] ?? '0');
|
||||
$st_class = $st === 'rejected' ? 'c-red' : ($st === 'completed' ? 'c-green' : 'c-blue');
|
||||
?>
|
||||
<div class="uc-withdraw-history__item border-bottom padding-h10">
|
||||
<div class="flex jsb ac">
|
||||
<span class="badg badg-sm <?php echo esc_attr($st_class); ?>"><?php echo esc_html($status_labels[$st] ?? $st); ?></span>
|
||||
<b class="em12"><?php echo esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($gross) : number_format_i18n($gross, 2)); ?></b>
|
||||
<b class="em12"><?php echo esc_html($gross->formatted()); ?></b>
|
||||
</div>
|
||||
<div class="muted-2-color em09 mt6">
|
||||
<?php echo esc_html((string) ($wd['created_at'] ?? '')); ?>
|
||||
<?php if (abs($gross - $net) > 0.001) : ?>
|
||||
· <?php printf(esc_html__('到账 %s', 'aksrt'), esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($net) : number_format_i18n($net, 2))); ?>
|
||||
<?php if ($gross->minor() !== $net->minor()) : ?>
|
||||
· <?php printf(esc_html__('到账 %s', 'aksrt'), esc_html($net->formatted())); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($wd['note'])) : ?>
|
||||
@@ -233,16 +242,14 @@ endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
$wallet_page = max(1, isset($_GET['wallet_page']) ? (int) $_GET['wallet_page'] : 1);
|
||||
$wlog = class_exists('\AKSRT\Credits\Balance')
|
||||
? \AKSRT\Credits\Balance::get_log(['user_id' => (int) $user_id, 'page' => $wallet_page, 'per_page' => 10])
|
||||
: ['items' => [], 'total' => 0];
|
||||
$wlog = \AKSRT\Ledger\LedgerQuery::get_instance()->history(['user_id' => (int) $user_id, 'asset' => 'balance', 'page' => $wallet_page, 'per_page' => 10]);
|
||||
if (!empty($wlog['items'])) :
|
||||
?>
|
||||
<div class="uc-transactions__list">
|
||||
<?php foreach ($wlog['items'] as $row) :
|
||||
$delta = (float) $row['delta'];
|
||||
$delta = (int) $row['delta_minor'];
|
||||
$delta_class = $delta >= 0 ? 'is-positive' : 'is-negative';
|
||||
$delta_txt = ($delta > 0 ? '+' : '') . (class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($delta) : number_format_i18n($delta, 2));
|
||||
$delta_txt = ($delta > 0 ? '+' : '-') . \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, abs($delta))->formatted();
|
||||
?>
|
||||
<div class="uc-transactions__item">
|
||||
<div class="uc-transactions__icon <?php echo esc_attr($delta_class); ?>">
|
||||
@@ -250,7 +257,7 @@ endif; ?>
|
||||
</div>
|
||||
<div class="uc-transactions__info">
|
||||
<div class="uc-transactions__reason">
|
||||
<?php echo esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::reason_label((string) $row['reason']) : (string) $row['reason']); ?>
|
||||
<?php echo esc_html(aksrt_asset_reason_label((string) $row['reason'])); ?>
|
||||
<?php if (!empty($row['remark'])) : ?>
|
||||
<span class="uc-transactions__remark">(<?php echo esc_html((string) $row['remark']); ?>)</span>
|
||||
<?php endif; ?>
|
||||
@@ -263,7 +270,7 @@ endif; ?>
|
||||
<?php
|
||||
printf(
|
||||
esc_html__('余额 %s', 'aksrt'),
|
||||
esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format((float) $row['balance_after']) : number_format_i18n((float) $row['balance_after'], 2))
|
||||
esc_html(\AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, (int) $row['balance_after_minor'])->formatted())
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
|
||||
@@ -39,7 +39,14 @@ $page_url = static function (int $target_page) use ($base_url): string {
|
||||
);
|
||||
};
|
||||
$format = static function ($amount, string $unit): string {
|
||||
return number_format_i18n((float) $amount, $unit === 'points' ? 0 : 2);
|
||||
if ($unit === 'points') {
|
||||
return aksrt_format_points(max(0, (int) $amount));
|
||||
}
|
||||
try {
|
||||
return \AKSRT\Ledger\AssetAmount::balance(is_string($amount) ? $amount : '')->formatted();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return '0.00';
|
||||
}
|
||||
};
|
||||
$note = trim((string) ($settings['note'] ?? ''));
|
||||
if ($note === '') {
|
||||
|
||||
@@ -77,17 +77,15 @@ if ($show_wallet || $show_credits) :
|
||||
// Render only the ledger portion by reusing balance log markup.
|
||||
$user_id = (int) ($user_id ?? 0);
|
||||
$wallet_page = max(1, isset($_GET['wallet_page']) ? (int) $_GET['wallet_page'] : 1);
|
||||
$wlog = class_exists('\AKSRT\Credits\Balance')
|
||||
? \AKSRT\Credits\Balance::get_log(['user_id' => $user_id, 'page' => $wallet_page, 'per_page' => 10])
|
||||
: ['items' => [], 'total' => 0];
|
||||
$wlog = \AKSRT\Ledger\LedgerQuery::get_instance()->history(['user_id' => $user_id, 'asset' => 'balance', 'page' => $wallet_page, 'per_page' => 10]);
|
||||
?>
|
||||
<div class="uc-transactions uc-transactions--wallet">
|
||||
<?php if (!empty($wlog['items'])) : ?>
|
||||
<div class="uc-transactions__list">
|
||||
<?php foreach ($wlog['items'] as $row) :
|
||||
$delta = (float) $row['delta'];
|
||||
$delta = (int) $row['delta_minor'];
|
||||
$delta_class = $delta >= 0 ? 'is-positive' : 'is-negative';
|
||||
$delta_txt = ($delta > 0 ? '+' : '') . (class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($delta) : number_format_i18n($delta, 2));
|
||||
$delta_txt = ($delta > 0 ? '+' : '-') . \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, abs($delta))->formatted();
|
||||
?>
|
||||
<div class="uc-transactions__item">
|
||||
<div class="uc-transactions__icon <?php echo esc_attr($delta_class); ?>">
|
||||
@@ -95,7 +93,7 @@ if ($show_wallet || $show_credits) :
|
||||
</div>
|
||||
<div class="uc-transactions__info">
|
||||
<div class="uc-transactions__reason">
|
||||
<?php echo esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::reason_label((string) $row['reason']) : (string) $row['reason']); ?>
|
||||
<?php echo esc_html(aksrt_asset_reason_label((string) $row['reason'])); ?>
|
||||
<?php if (!empty($row['remark'])) : ?>
|
||||
<span class="uc-transactions__remark">(<?php echo esc_html((string) $row['remark']); ?>)</span>
|
||||
<?php endif; ?>
|
||||
@@ -104,7 +102,9 @@ if ($show_wallet || $show_credits) :
|
||||
</div>
|
||||
<div class="uc-transactions__amount">
|
||||
<span class="uc-transactions__delta <?php echo esc_attr($delta_class); ?>"><?php echo esc_html($delta_txt); ?></span>
|
||||
<span class="uc-transactions__balance"><?php printf(esc_html__('余额 %s', 'aksrt'), esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format((float) ($row['balance_after'] ?? 0)) : number_format_i18n((float) ($row['balance_after'] ?? 0), 2))); ?></span>
|
||||
<span class="uc-transactions__balance"><?php printf(esc_html__('余额 %s', 'aksrt'), esc_html(\AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, (int) ($row['balance_after_minor'] ?? 0))->formatted())); ?></span>
|
||||
<?php if ((int) ($row['fee_minor'] ?? 0) > 0) : ?><span class="muted-2-color em09"><?php printf(esc_html__('手续费 %s', 'aksrt'), esc_html(\AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, (int) $row['fee_minor'])->formatted())); ?></span><?php endif; ?>
|
||||
<span class="muted-2-color em09"><?php printf(esc_html__('交易 #%d', 'aksrt'), (int) $row['id']); ?></span>
|
||||
<?php if (!empty($row['ref_id'])) : ?>
|
||||
<span class="uc-transactions__ref muted-2-color em09"><?php printf(esc_html__('单号 %s', 'aksrt'), esc_html((string) $row['ref_id'])); ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -111,9 +111,16 @@ $tabs = [
|
||||
<?php foreach ($orders as $order) :
|
||||
$number = (string) ($order['order_number'] ?? '');
|
||||
$actions = (array) ($order['allowed_actions'] ?? []);
|
||||
$amount = !empty($order['is_points'])
|
||||
? esc_html((string) ($order['currency_symbol'] ?? __('积分', 'aksrt')) . ' ' . (string) (int) round((float) ($order['amount'] ?? 0)))
|
||||
: '¥' . esc_html(number_format((float) ($order['amount'] ?? 0), 2));
|
||||
if (!empty($order['is_points'])) {
|
||||
$amount = esc_html((string) ($order['currency_symbol'] ?? __('积分', 'aksrt')) . ' ' . (string) max(0, (int) ($order['amount'] ?? 0)));
|
||||
} else {
|
||||
try {
|
||||
$order_amount = \AKSRT\Ledger\AssetAmount::balance(is_string($order['amount'] ?? null) ? $order['amount'] : '')->formatted();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$order_amount = '0.00';
|
||||
}
|
||||
$amount = '¥' . esc_html($order_amount);
|
||||
}
|
||||
?>
|
||||
<article class="aksrt-orders-page__card" data-aksrt-order-card="<?php echo esc_attr($number); ?>" data-order-status="<?php echo esc_attr((string) ($order['status_group'] ?? '')); ?>">
|
||||
<div class="aksrt-orders-page__card-rail"><span><?php echo esc_html((string) ($order['product_type_label'] ?? '')); ?></span><time><?php echo esc_html((string) ($order['created_at'] ?? '')); ?></time><span class="aksrt-orders-page__card-status is-<?php echo esc_attr((string) ($order['status_group'] ?? '')); ?>"><?php echo esc_html((string) ($order['status_label'] ?? '')); ?></span></div>
|
||||
|
||||
@@ -21,22 +21,34 @@ $affiliate_on = !empty($affiliate['enabled']);
|
||||
$withdrawal = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_withdrawal_settings()
|
||||
: [];
|
||||
$withdraw_on = $affiliate_on
|
||||
&& class_exists('\AKSRT\Credits\Balance')
|
||||
&& \AKSRT\Credits\Balance::enabled();
|
||||
$recharge = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_payment_recharge_settings() : [];
|
||||
$withdraw_on = $affiliate_on && !empty($recharge['enabled']);
|
||||
if ($withdraw_on && class_exists('\AKSRT\Settings\Capabilities') && !\AKSRT\Settings\Capabilities::user_can('balance_withdraw', $user_id)) {
|
||||
$withdraw_on = false;
|
||||
}
|
||||
$withdraw_min = max(1, (float) ($withdrawal['min_amount'] ?? 50));
|
||||
$normalize_balance = static function ($value): \AKSRT\Ledger\AssetAmount {
|
||||
try {
|
||||
return \AKSRT\Ledger\AssetAmount::balance(is_string($value) ? $value : '');
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return \AKSRT\Ledger\AssetAmount::balance('0');
|
||||
}
|
||||
};
|
||||
$signed_balance_minor = static function ($value) use ($normalize_balance): int {
|
||||
$value = is_string($value) ? trim($value) : '';
|
||||
$negative = str_starts_with($value, '-');
|
||||
$amount = $normalize_balance($negative ? substr($value, 1) : $value)->minor();
|
||||
return $negative ? -$amount : $amount;
|
||||
};
|
||||
$withdraw_min = $normalize_balance($withdrawal['min_amount'] ?? '50')->decimal();
|
||||
|
||||
$commission_stats = class_exists('\AKSRT\Payment\CommissionLedger')
|
||||
? \AKSRT\Payment\CommissionLedger::get_instance()->overview($user_id)
|
||||
: ['total' => 0, 'pending' => 0, 'settled' => 0, 'wallet' => 0];
|
||||
$pending_commission = (float) ($commission_stats['pending'] ?? 0);
|
||||
$pending_commission = $normalize_balance($commission_stats['pending'] ?? '0')->decimal();
|
||||
$vip_ratios = [];
|
||||
$commission_ratio = class_exists('\AKSRT\Settings\Settings')
|
||||
? (float) \AKSRT\Settings\Settings::affiliate_ratio_for_user($user_id)
|
||||
: 0.0;
|
||||
? (int) \AKSRT\Settings\Settings::affiliate_ratio_for_user($user_id)
|
||||
: 0;
|
||||
$details_text = trim((string) ($affiliate['promotion_text'] ?? ''));
|
||||
if ($details_text === '') {
|
||||
$details_text = __('好友通过推广链接完成符合条件的订单后,系统会按当前佣金比例记录返佣,结算后进入可提现余额。', 'aksrt');
|
||||
@@ -56,8 +68,8 @@ $base_url = function_exists('aksrt_get_user_center_tab_url')
|
||||
$reward_url = static function (string $tab, array $extra = []) use ($base_url): string {
|
||||
return add_query_arg(array_merge(['reward_tab' => $tab], $extra), $base_url);
|
||||
};
|
||||
$format_amount = static function ($amount): string {
|
||||
return number_format_i18n((float) $amount, 2);
|
||||
$format_amount = static function ($amount) use ($normalize_balance): string {
|
||||
return $normalize_balance($amount)->formatted();
|
||||
};
|
||||
|
||||
$commission_page = max(1, (int) ($revenue_request['commission_page'] ?? ($_GET['commission_page'] ?? 1)));
|
||||
@@ -151,7 +163,11 @@ $status_labels = [
|
||||
$source_user = !empty($item['source_user_id']) ? get_userdata((int) $item['source_user_id']) : null;
|
||||
$source_name = $source_user instanceof WP_User ? $source_user->display_name : __('推广用户', 'aksrt');
|
||||
?>
|
||||
<article class="uc-commission-row"><span class="uc-commission-row__icon"><i class="fa fas fa-file-alt" aria-hidden="true"></i></span><div class="uc-commission-row__main"><strong><?php echo esc_html($source_name); ?></strong><span><?php printf(esc_html__('订单 %s', 'aksrt'), esc_html((string) ($item['order_number'] ?? '-'))); ?></span><time><?php echo esc_html((string) ($item['created_at'] ?? '')); ?></time></div><div class="uc-commission-row__value"><strong><?php echo esc_html($format_amount((float) ($item['original_amount'] ?? 0) + (float) ($item['adjustment_total'] ?? 0))); ?></strong><span class="is-<?php echo esc_attr($status); ?>"><?php echo esc_html($status_labels[$status] ?? $status); ?></span></div></article>
|
||||
<?php
|
||||
$commission_minor = $signed_balance_minor($item['original_amount'] ?? '0') + $signed_balance_minor($item['adjustment_total'] ?? '0');
|
||||
$commission_amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor(max(0, $commission_minor));
|
||||
?>
|
||||
<article class="uc-commission-row"><span class="uc-commission-row__icon"><i class="fa fas fa-file-alt" aria-hidden="true"></i></span><div class="uc-commission-row__main"><strong><?php echo esc_html($source_name); ?></strong><span><?php printf(esc_html__('订单 %s', 'aksrt'), esc_html((string) ($item['order_number'] ?? '-'))); ?></span><time><?php echo esc_html((string) ($item['created_at'] ?? '')); ?></time></div><div class="uc-commission-row__value"><strong><?php echo esc_html($format_amount($commission_amount)); ?></strong><span class="is-<?php echo esc_attr($status); ?>"><?php echo esc_html($status_labels[$status] ?? $status); ?></span></div></article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($commission_total_pages > 1) : ?><nav class="uc-reward-pagination" aria-label="<?php esc_attr_e('佣金明细分页', 'aksrt'); ?>"><?php for ($i = 1; $i <= $commission_total_pages; $i++) : ?><a class="<?php echo $i === $commission_page ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('orders', ['commission_page' => $i])); ?>"><?php echo esc_html((string) $i); ?></a><?php endfor; ?></nav><?php endif; ?>
|
||||
|
||||
@@ -14,15 +14,19 @@ if (!$show_wallet && !$show_credits) {
|
||||
}
|
||||
|
||||
$assets_url = aksrt_get_user_center_tab_url('credits');
|
||||
$wallet = (float) ($wallet_balance ?? 0);
|
||||
$points = (float) ($credit_balance ?? 0);
|
||||
try {
|
||||
$wallet = \AKSRT\Ledger\AssetAmount::balance(is_string($wallet_balance ?? null) ? $wallet_balance : '')->formatted();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$wallet = '0.00';
|
||||
}
|
||||
$points = max(0, (int) ($credit_balance ?? 0));
|
||||
?>
|
||||
<div class="uc-sidebar__pair uc-sidebar__pair--assets">
|
||||
<?php if ($show_wallet) : ?>
|
||||
<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__body">
|
||||
<strong><?php echo esc_html(class_exists('\AKSRT\Credits\Balance') ? \AKSRT\Credits\Balance::format($wallet) : number_format_i18n($wallet, 2)); ?></strong>
|
||||
<strong><?php echo esc_html($wallet); ?></strong>
|
||||
<i class="fa fas fa-money-bill" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
@@ -31,7 +35,7 @@ $points = (float) ($credit_balance ?? 0);
|
||||
<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__body">
|
||||
<strong><?php echo esc_html(function_exists('aksrt_format_credits') ? aksrt_format_credits((int) $points) : number_format_i18n((int) $points)); ?></strong>
|
||||
<strong><?php echo esc_html(aksrt_format_points($points)); ?></strong>
|
||||
<i class="fa fas fa-money-bill" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -6,8 +6,12 @@ if (!empty($GLOBALS['aksrt_withdraw_modal_rendered'])) {
|
||||
return;
|
||||
}
|
||||
$GLOBALS['aksrt_withdraw_modal_rendered'] = true;
|
||||
$withdraw_min = max(0, (float) ($withdraw_min ?? 50));
|
||||
$withdraw_usage = is_array($withdraw_usage ?? null) ? $withdraw_usage : ['remaining_count' => 0, 'remaining_amount' => 0];
|
||||
try {
|
||||
$withdraw_min = \AKSRT\Ledger\AssetAmount::balance(is_string($withdraw_min ?? null) ? $withdraw_min : '')->decimal();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$withdraw_min = '0.00';
|
||||
}
|
||||
$withdraw_usage = is_array($withdraw_usage ?? null) ? $withdraw_usage : ['remaining_count' => 0, 'remaining_amount' => '0.00'];
|
||||
$withdraw_fee_rate = (int) ($withdraw_settings['service_charge_rate'] ?? 5);
|
||||
$withdraw_channels = array_values(array_intersect(['alipay', 'wechat'], (array) ($withdraw_settings['payout_channels'] ?? ['alipay', 'wechat'])));
|
||||
if (!$withdraw_channels) {
|
||||
@@ -21,8 +25,8 @@ if (!$withdraw_channels) {
|
||||
<h3 class="uc-modal__title"><?php esc_html_e('余额提现', 'aksrt'); ?></h3>
|
||||
<form data-aksrt-withdraw-form>
|
||||
<label class="muted-color em09"><?php esc_html_e('提现金额', 'aksrt'); ?></label>
|
||||
<input type="number" class="uc-card-pass__input" name="amount" min="<?php echo esc_attr((string) $withdraw_min); ?>" max="<?php echo esc_attr((string) ($withdraw_usage['remaining_amount'] ?? 0)); ?>" step="1" inputmode="numeric" data-aksrt-withdraw-amount data-withdraw-min="<?php echo esc_attr((string) $withdraw_min); ?>" data-withdraw-remaining-amount="<?php echo esc_attr((string) ($withdraw_usage['remaining_amount'] ?? 0)); ?>" data-withdraw-remaining-count="<?php echo esc_attr((string) ($withdraw_usage['remaining_count'] ?? 0)); ?>">
|
||||
<p class="muted-2-color em09 mt6"><?php printf(esc_html__('最低提现%s 元,今日可提现%d次,提现手续费率%d%%', 'aksrt'), esc_html((string) $withdraw_min), (int) ($withdraw_usage['remaining_count'] ?? 0), $withdraw_fee_rate); ?></p>
|
||||
<input type="number" class="uc-card-pass__input" name="amount" min="<?php echo esc_attr($withdraw_min); ?>" max="<?php echo esc_attr((string) ($withdraw_usage['remaining_amount'] ?? '0.00')); ?>" step="0.01" inputmode="decimal" data-aksrt-withdraw-amount data-withdraw-min="<?php echo esc_attr($withdraw_min); ?>" data-withdraw-remaining-amount="<?php echo esc_attr((string) ($withdraw_usage['remaining_amount'] ?? '0.00')); ?>" data-withdraw-remaining-count="<?php echo esc_attr((string) ($withdraw_usage['remaining_count'] ?? 0)); ?>">
|
||||
<p class="muted-2-color em09 mt6"><?php printf(esc_html__('最低提现%s 元,今日可提现%d次,提现手续费率%d%%', 'aksrt'), esc_html($withdraw_min), (int) ($withdraw_usage['remaining_count'] ?? 0), $withdraw_fee_rate); ?></p>
|
||||
<label class="muted-color em09 mt10"><?php esc_html_e('收款方式', 'aksrt'); ?></label>
|
||||
<select class="uc-card-pass__input" name="method" data-aksrt-withdraw-method>
|
||||
<?php foreach ($withdraw_channels as $channel) : ?>
|
||||
|
||||
@@ -53,8 +53,10 @@ function aksrt_notification_type_label(string $type): string {
|
||||
'comment_reply' => __('评论回复', 'aksrt'),
|
||||
'comment_approved' => __('评论审核', 'aksrt'),
|
||||
'download_ready' => __('下载就绪', 'aksrt'),
|
||||
'credits_added' => __('积分增加', 'aksrt'),
|
||||
'credits_deducted' => __('积分扣减', 'aksrt'),
|
||||
'asset_points_increase' => __('积分增加', 'aksrt'),
|
||||
'asset_points_decrease' => __('积分扣减', 'aksrt'),
|
||||
'asset_balance_increase' => __('余额增加', 'aksrt'),
|
||||
'asset_balance_decrease' => __('余额扣减', 'aksrt'),
|
||||
'pending_comments' => __('待审核评论', 'aksrt'),
|
||||
'notice' => __('通知', 'aksrt'),
|
||||
];
|
||||
@@ -549,25 +551,38 @@ add_action('transition_comment_status', function ($new_status, $old_status, $com
|
||||
update_comment_meta($comment->comment_ID, 'aksrt_reply_notified', 1);
|
||||
}, 20, 3);
|
||||
|
||||
add_action('aksrt_credits_added', function ($user_id, $delta, $reason, $new_balance) {
|
||||
if ($user_id <= 0 || $delta <= 0) return;
|
||||
aksrt_add_user_notification((int) $user_id, [
|
||||
'type' => 'credits_added',
|
||||
'title' => __('积分增加', 'aksrt'),
|
||||
'desc' => sprintf(__('积分变动:+%1$d,当前余额 %2$d。', 'aksrt'), (int) $delta, (int) $new_balance),
|
||||
'url' => aksrt_get_user_center_url('credits'),
|
||||
]);
|
||||
}, 10, 4);
|
||||
|
||||
add_action('aksrt_credits_deducted', function ($user_id, $cost, $reason, $new_balance) {
|
||||
if ($user_id <= 0 || $cost <= 0) return;
|
||||
aksrt_add_user_notification((int) $user_id, [
|
||||
'type' => 'credits_deducted',
|
||||
'title' => __('积分扣减', 'aksrt'),
|
||||
'desc' => sprintf(__('积分变动:-%1$d,当前余额 %2$d。', 'aksrt'), (int) $cost, (int) $new_balance),
|
||||
'url' => aksrt_get_user_center_url('credits'),
|
||||
]);
|
||||
}, 10, 4);
|
||||
add_action('aksrt_asset_transaction_committed', function ($result, $command): void {
|
||||
if (!$result instanceof \AKSRT\Ledger\LedgerResult || !$command instanceof \AKSRT\Ledger\LedgerCommand) {
|
||||
return;
|
||||
}
|
||||
$changes = [];
|
||||
foreach ($result->entries as $entry) {
|
||||
$user_id = (int) ($entry['user_id'] ?? 0);
|
||||
$asset = (string) ($entry['asset'] ?? '');
|
||||
if ($user_id <= 0 || !in_array($asset, ['points', 'balance'], true)) continue;
|
||||
$key = $user_id . ':' . $asset;
|
||||
$changes[$key] ??= ['user_id' => $user_id, 'asset' => $asset, 'delta' => 0, 'balance' => 0];
|
||||
$changes[$key]['delta'] += (int) ($entry['delta_minor'] ?? 0);
|
||||
$changes[$key]['balance'] = (int) ($entry['balance_after_minor'] ?? 0);
|
||||
}
|
||||
foreach ($changes as $change) {
|
||||
if ((int) $change['delta'] === 0) continue;
|
||||
$is_points = $change['asset'] === 'points';
|
||||
$positive = $change['delta'] > 0;
|
||||
$amount = $is_points
|
||||
? (string) abs((int) $change['delta'])
|
||||
: \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, abs((int) $change['delta']))->decimal();
|
||||
$balance = $is_points
|
||||
? (string) $change['balance']
|
||||
: \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, (int) $change['balance'])->decimal();
|
||||
aksrt_add_user_notification((int) $change['user_id'], [
|
||||
'type' => 'asset_' . $change['asset'] . '_' . ($positive ? 'increase' : 'decrease'),
|
||||
'title' => $is_points ? __('积分变动', 'aksrt') : __('余额变动', 'aksrt'),
|
||||
'desc' => sprintf(__('%1$s:%2$s%3$s,当前余额 %4$s。', 'aksrt'), \AKSRT\Ledger\LedgerPresentation::reason_label($command->reason), $positive ? '+' : '-', $amount, $balance),
|
||||
'url' => aksrt_get_user_center_url('credits'),
|
||||
]);
|
||||
}
|
||||
}, 10, 2);
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user