积分与余额账务系统硬切重构

This commit is contained in:
kate522 committed 2026-08-24 15:59:11 +08:00
1 parent ca12226b39
commit 5cae5b5c93
159 files changed
+7275 -4718

No files matched your search

+131 -57
View File
@@ -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')