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

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

+75 -53
View File
@@ -17,7 +17,7 @@ trait VipServicePackages {
* Preferred: price|show_price|time|unit|tag|title
* Legacy: price|days|title
*
* @return array<int, array{price:float,show_price:float,time:int,unit:string,tag:string,tag_class:string,title:string,days:int}>
* @return array<int, array{price:string,show_price:string,time:int,unit:string,tag:string,tag_class:string,title:string,days:int}>
*/
public function parse_level_products(string $raw): array {
$lines = preg_split('/\r\n|\r|\n/', $raw) ?: [];
@@ -28,8 +28,8 @@ trait VipServicePackages {
continue;
}
$parts = array_map('trim', explode('|', $line));
$price = isset($parts[0]) ? (float) $parts[0] : 0.0;
if ($price <= 0) {
$price_minor = $this->parse_vip_money_minor($parts[0] ?? '');
if ($price_minor <= 0) {
continue;
}
@@ -38,7 +38,7 @@ trait VipServicePackages {
// Or: price|show_price|time|unit|title (5)
if ($n >= 4 && (in_array(strtolower((string) ($parts[3] ?? '')), ['day', 'month', 'd', 'm'], true)
|| (isset($parts[3]) && $parts[3] !== '' && !is_numeric($parts[3])))) {
$show_price = isset($parts[1]) ? (float) $parts[1] : 0.0;
$show_minor = $this->parse_vip_money_minor($parts[1] ?? '0');
$time = isset($parts[2]) ? (int) $parts[2] : 0;
$unit_raw = strtolower((string) ($parts[3] ?? 'month'));
$unit = ($unit_raw === 'day' || $unit_raw === 'd') ? 'day' : 'month';
@@ -53,7 +53,7 @@ trait VipServicePackages {
}
} else {
// Legacy: price|days|title
$show_price = 0.0;
$show_minor = 0;
$days_legacy = isset($parts[1]) ? (int) $parts[1] : 0;
$time = $days_legacy;
$unit = 'day';
@@ -74,8 +74,8 @@ trait VipServicePackages {
}
$out[] = [
'price' => round($price, 2),
'show_price' => max(0.0, round($show_price, 2)),
'price' => \AKSRT\Ledger\AssetAmount::decimal_from_minor($price_minor),
'show_price' => \AKSRT\Ledger\AssetAmount::decimal_from_minor($show_minor),
'time' => $time,
'unit' => $unit,
'tag' => $tag,
@@ -103,14 +103,14 @@ trait VipServicePackages {
/**
* @deprecated Use parse_level_products — kept as thin adapter for upgrade fixed lines.
*
* @return array<int, array{price:float,days:int,title:string}>
* @return array<int, array{price:string,days:int,title:string}>
*/
public function parse_packages(string $raw): array {
$parsed = $this->parse_level_products($raw);
$out = [];
foreach ($parsed as $p) {
$out[] = [
'price' => (float) $p['price'],
'price' => (string) $p['price'],
'days' => (int) $p['days'],
'title' => (string) $p['title'],
];
@@ -161,12 +161,16 @@ trait VipServicePackages {
if ($is_permanent || $expires <= time() || $has_unit) {
continue;
}
$daily = isset($parts[1]) ? (float) $parts[1] : 0.0;
if ($daily <= 0) {
$daily_minor = $this->parse_vip_money_minor($parts[1] ?? '');
if ($daily_minor <= 0) {
continue;
}
$remaining = (int) ceil(max(1, ($expires - time()) / DAY_IN_SECONDS));
$price = round(max(0.01, $remaining * $daily), 2);
if ($daily_minor > intdiv(PHP_INT_MAX, $remaining)) {
continue;
}
$price_minor = $remaining * $daily_minor;
$price = \AKSRT\Ledger\AssetAmount::decimal_from_minor($price_minor);
$title = sanitize_text_field((string) ($parts[2] ?? ''));
if ($title === '') {
$title = sprintf(__('按剩余 %d 天升级', 'aksrt'), $remaining);
@@ -178,7 +182,7 @@ trait VipServicePackages {
'action' => 'upgrade',
'price' => $price,
'base_price' => $price,
'show_price' => 0.0,
'show_price' => '0.00',
'discount_tag' => __('剩余天数', 'aksrt'),
'days' => $remaining,
'title' => $title,
@@ -198,28 +202,30 @@ trait VipServicePackages {
if ($is_permanent || $has_jump) {
continue;
}
$price = isset($parts[1]) ? (float) $parts[1] : 0.0;
if ($price <= 0) {
$price_minor = $this->parse_vip_money_minor($parts[1] ?? '');
if ($price_minor <= 0) {
continue;
}
$price = \AKSRT\Ledger\AssetAmount::decimal_from_minor($price_minor);
$title = sanitize_text_field((string) ($parts[2] ?? ''));
if ($title === '') {
$title = __('升级为永久会员', 'aksrt');
}
$show = isset($parts[3]) ? (float) $parts[3] : 0.0;
$show_minor = $this->parse_vip_money_minor($parts[3] ?? '0');
$show = \AKSRT\Ledger\AssetAmount::decimal_from_minor($show_minor);
$items[] = [
'package_id' => $this->encode_package_id(2, 903),
'level' => 2,
'index' => 903,
'action' => 'upgrade',
'price' => round($price, 2),
'base_price' => round($price, 2),
'show_price' => max(0.0, $show),
'price' => $price,
'base_price' => $price,
'show_price' => $show,
'discount_tag' => __('永久升级', 'aksrt'),
'days' => 0,
'title' => $title,
'price_label' => $this->format_cash_label($price),
'show_price_label' => $show > 0 ? $this->format_cash_label($show) : '',
'show_price_label' => $show_minor > 0 ? $this->format_cash_label($show) : '',
'days_label' => __('永久', 'aksrt'),
'cta_label' => __('立即升级', 'aksrt'),
'is_upgrade_product' => true,
@@ -234,28 +240,30 @@ trait VipServicePackages {
if ($has_permanent) {
continue;
}
$price = isset($parts[1]) ? (float) $parts[1] : 0.0;
if ($price <= 0) {
$price_minor = $this->parse_vip_money_minor($parts[1] ?? '');
if ($price_minor <= 0) {
continue;
}
$price = \AKSRT\Ledger\AssetAmount::decimal_from_minor($price_minor);
$title = sanitize_text_field((string) ($parts[2] ?? ''));
if ($title === '') {
$title = __('永久会员升级', 'aksrt');
}
$show = isset($parts[3]) ? (float) $parts[3] : 0.0;
$show_minor = $this->parse_vip_money_minor($parts[3] ?? '0');
$show = \AKSRT\Ledger\AssetAmount::decimal_from_minor($show_minor);
$items[] = [
'package_id' => $this->encode_package_id(2, 901),
'level' => 2,
'index' => 901,
'action' => 'upgrade',
'price' => round($price, 2),
'base_price' => round($price, 2),
'show_price' => max(0.0, $show),
'price' => $price,
'base_price' => $price,
'show_price' => $show,
'discount_tag' => __('升级专享', 'aksrt'),
'days' => 0,
'title' => $title,
'price_label' => $this->format_cash_label($price),
'show_price_label' => $show > 0 ? $this->format_cash_label($show) : '',
'show_price_label' => $show_minor > 0 ? $this->format_cash_label($show) : '',
'days_label' => __('永久', 'aksrt'),
'cta_label' => __('立即升级', 'aksrt'),
'is_upgrade_product' => true,
@@ -280,13 +288,13 @@ trait VipServicePackages {
'level' => 2,
'index' => 901,
'action' => 'upgrade',
'price' => (float) $pkg['price'],
'base_price' => (float) $pkg['price'],
'show_price' => 0.0,
'price' => (string) $pkg['price'],
'base_price' => (string) $pkg['price'],
'show_price' => '0.00',
'discount_tag' => __('升级专享', 'aksrt'),
'days' => (int) $pkg['days'],
'title' => (string) $pkg['title'],
'price_label' => $this->format_cash_label((float) $pkg['price']),
'price_label' => $this->format_cash_label((string) $pkg['price']),
'show_price_label' => '',
'days_label' => ((int) $pkg['days'] <= 0)
? __('永久', 'aksrt')
@@ -399,10 +407,10 @@ trait VipServicePackages {
*
* @param array<string,mixed> $renew
* @param array<string,mixed> $upgrade
* @return array{price:float,show_price:float,tag:string}|null
* @return array{price:string,show_price:string,tag:string}|null
*/
private function apply_action_price(
float $base_price,
string $base_price,
string $action,
array $renew,
array $upgrade,
@@ -412,7 +420,8 @@ trait VipServicePackages {
bool $is_permanent,
int $days
): ?array {
if ($base_price <= 0) {
$base_minor = $this->parse_vip_money_minor($base_price);
if ($base_minor <= 0) {
return null;
}
@@ -422,57 +431,59 @@ trait VipServicePackages {
if ($action !== 'renew') {
return [
'price' => round($base_price, 2),
'show_price' => 0.0,
'price' => \AKSRT\Ledger\AssetAmount::decimal_from_minor($base_minor),
'show_price' => '0.00',
'tag' => '',
];
}
$type = sanitize_key((string) ($renew['price_type'] ?? 'discount'));
$price = $base_price;
$show = $base_price;
$price_minor = $base_minor;
$show_minor = $base_minor;
$tag = '';
if ($type === 'discount') {
$discount = (float) ($renew['discount'] ?? 8);
$discount = (int) ($renew['discount'] ?? 8);
if ($discount <= 0) {
$discount = 8;
}
if ($discount <= 10) {
$price = round($base_price * ($discount / 10), 2);
$percent = $discount * 10;
$price_minor = \AKSRT\Ledger\AssetAmount::percentage($base_minor, $percent);
$tag = sprintf(
/* translators: %s: discount like 8 */
__('%s折续费', 'aksrt'),
rtrim(rtrim(number_format($discount, 1, '.', ''), '0'), '.')
(string) $discount
);
} else {
$price = round($base_price * (min(100, $discount) / 100), 2);
$percent = min(100, $discount);
$price_minor = \AKSRT\Ledger\AssetAmount::percentage($base_minor, $percent);
$tag = sprintf(__('%s%% 续费价', 'aksrt'), (string) (int) $discount);
}
} elseif ($type === 'reduce') {
$reduce = max(0, (float) ($renew['reduce'] ?? 20));
$price = round(max(0.01, $base_price - $reduce), 2);
$reduce_minor = $this->parse_vip_money_minor($renew['reduce'] ?? '20');
$price_minor = max(1, $base_minor - $reduce_minor);
$tag = sprintf(
/* translators: %s: amount */
__('续费立减%s', 'aksrt'),
$this->format_cash_label($reduce)
$this->format_cash_label(\AKSRT\Ledger\AssetAmount::decimal_from_minor($reduce_minor))
);
} else {
$show = 0.0;
$show_minor = 0;
$tag = __('续费同价', 'aksrt');
}
if ($price < 0.01) {
$price = 0.01;
if ($price_minor < 1) {
$price_minor = 1;
}
if ($show > 0 && $price >= $show) {
$show = 0.0;
if ($show_minor > 0 && $price_minor >= $show_minor) {
$show_minor = 0;
$tag = __('续费', 'aksrt');
}
return [
'price' => $price,
'show_price' => $show > $price ? $show : 0.0,
'price' => \AKSRT\Ledger\AssetAmount::decimal_from_minor($price_minor),
'show_price' => \AKSRT\Ledger\AssetAmount::decimal_from_minor($show_minor > $price_minor ? $show_minor : 0),
'tag' => $tag,
];
}
@@ -532,7 +543,7 @@ trait VipServicePackages {
private function format_cash_label(float $amount): string {
private function format_cash_label(string $amount): string {
$symbol = '¥';
if (method_exists($this, 'get_paid_display_context')) {
$paid = $this->get_paid_display_context();
@@ -545,6 +556,17 @@ trait VipServicePackages {
return $symbol . $n;
}
private function parse_vip_money_minor($value): int {
if (!is_string($value)) {
return 0;
}
try {
return \AKSRT\Ledger\AssetAmount::balance_minor($value);
} catch (\InvalidArgumentException $e) {
return 0;
}
}
private function format_expires_label(int $expires, int $level): string {