积分与余额账务系统硬切重构
This commit is contained in:
@@ -174,7 +174,7 @@ trait OrderRepositoryAdmin {
|
||||
* orderby?: string,
|
||||
* order?: string
|
||||
* } $args
|
||||
* @return array{items: list<array{product_id:int,product_type:string,sales_count:int,avg_amount:float,revenue:float}>, total: int}
|
||||
* @return array{items: list<array{product_id:int,product_type:string,sales_count:int,avg_amount:int|string,revenue:int|string}>, total: int}
|
||||
*/
|
||||
public function get_content_sales_summary(array $args = []): array {
|
||||
global $wpdb;
|
||||
@@ -237,12 +237,13 @@ trait OrderRepositoryAdmin {
|
||||
|
||||
$list_sql = "SELECT product_id,
|
||||
product_type,
|
||||
currency,
|
||||
COUNT(*) AS sales_count,
|
||||
AVG(amount) AS avg_amount,
|
||||
SUM(amount) AS revenue
|
||||
FROM {$table}
|
||||
{$where_sql}
|
||||
GROUP BY product_id, product_type
|
||||
GROUP BY product_id, product_type, currency
|
||||
ORDER BY {$orderby_col} {$order_dir}
|
||||
LIMIT %d OFFSET %d";
|
||||
$list_params = $params;
|
||||
@@ -252,12 +253,28 @@ trait OrderRepositoryAdmin {
|
||||
$rows = $wpdb->get_results($wpdb->prepare($list_sql, $list_params), ARRAY_A);
|
||||
$items = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$sales_count = max(1, (int) ($row['sales_count'] ?? 0));
|
||||
$is_points = (string) ($row['currency'] ?? '') === 'points';
|
||||
if ($is_points) {
|
||||
$revenue = max(0, (int) ($row['revenue'] ?? 0));
|
||||
$avg_amount = intdiv($revenue + intdiv($sales_count, 2), $sales_count);
|
||||
} else {
|
||||
try {
|
||||
$revenue_minor = \AKSRT\Ledger\AssetAmount::balance_minor((string) ($row['revenue'] ?? '0'));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$revenue_minor = 0;
|
||||
}
|
||||
$revenue = \AKSRT\Ledger\AssetAmount::decimal_from_minor($revenue_minor);
|
||||
$avg_amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor(
|
||||
intdiv($revenue_minor + intdiv($sales_count, 2), $sales_count)
|
||||
);
|
||||
}
|
||||
$items[] = [
|
||||
'product_id' => (int) ($row['product_id'] ?? 0),
|
||||
'product_type' => (string) ($row['product_type'] ?? $product_type),
|
||||
'sales_count' => (int) ($row['sales_count'] ?? 0),
|
||||
'avg_amount' => round((float) ($row['avg_amount'] ?? 0), 2),
|
||||
'revenue' => round((float) ($row['revenue'] ?? 0), 2),
|
||||
'avg_amount' => $avg_amount,
|
||||
'revenue' => $revenue,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -273,7 +290,7 @@ trait OrderRepositoryAdmin {
|
||||
* Paid order totals for a set of product IDs (resource content).
|
||||
*
|
||||
* @param int[] $product_ids
|
||||
* @return array<int, array{sales_count:int,avg_amount:float,revenue:float}>
|
||||
* @return array<int, array{sales_count:int,avg_amount:int|string,revenue:int|string}>
|
||||
*/
|
||||
public function get_content_sales_map(array $product_ids, string $product_type = ''): array {
|
||||
$ids = array_values(array_unique(array_filter(array_map('intval', $product_ids), static function ($id) {
|
||||
@@ -304,8 +321,8 @@ trait OrderRepositoryAdmin {
|
||||
}
|
||||
$map[$pid] = [
|
||||
'sales_count' => (int) ($item['sales_count'] ?? 0),
|
||||
'avg_amount' => (float) ($item['avg_amount'] ?? 0),
|
||||
'revenue' => (float) ($item['revenue'] ?? 0),
|
||||
'avg_amount' => $item['avg_amount'] ?? '0.00',
|
||||
'revenue' => $item['revenue'] ?? '0.00',
|
||||
];
|
||||
}
|
||||
return $map;
|
||||
@@ -384,7 +401,7 @@ trait OrderRepositoryAdmin {
|
||||
'order_number' => $order_number,
|
||||
'status' => '',
|
||||
'status_label' => '',
|
||||
'amount' => 0.0,
|
||||
'amount' => '0.00',
|
||||
'currency_symbol' => '¥',
|
||||
'created_at' => '',
|
||||
'paid_at' => '',
|
||||
@@ -403,10 +420,10 @@ trait OrderRepositoryAdmin {
|
||||
],
|
||||
'coupon' => [],
|
||||
'pricing' => [
|
||||
'subtotal' => 0.0,
|
||||
'shipping_fee' => 0.0,
|
||||
'discount' => 0.0,
|
||||
'amount' => 0.0,
|
||||
'subtotal' => '0.00',
|
||||
'shipping_fee' => '0.00',
|
||||
'discount' => '0.00',
|
||||
'amount' => '0.00',
|
||||
],
|
||||
'items' => [],
|
||||
'customer_note' => '',
|
||||
@@ -430,10 +447,17 @@ trait OrderRepositoryAdmin {
|
||||
$shipping_method = is_array($meta['shipping_method'] ?? null) ? $meta['shipping_method'] : [];
|
||||
$coupon = is_array($meta['coupon'] ?? null) ? $meta['coupon'] : [];
|
||||
$items = is_array($meta['items'] ?? null) ? $meta['items'] : [];
|
||||
$shipping_fee = (float) ($meta['shipping_fee'] ?? 0);
|
||||
$discount = (float) ($meta['discount'] ?? 0);
|
||||
$amount = (float) ($order['amount'] ?? 0);
|
||||
$subtotal = $this->calculate_order_subtotal($items, max(0, $amount + $discount - $shipping_fee));
|
||||
$currency = (string) ($order['currency'] ?? 'CNY');
|
||||
$is_points = $currency === 'points';
|
||||
$shipping_minor = $is_points ? max(0, (int) ($meta['shipping_fee'] ?? 0)) : $this->cash_minor((string) ($meta['shipping_fee'] ?? '0'));
|
||||
$discount_minor = $is_points ? max(0, (int) ($meta['discount'] ?? 0)) : $this->cash_minor((string) ($meta['discount'] ?? '0'));
|
||||
$amount_minor = $is_points ? max(0, (int) ($order['amount'] ?? 0)) : $this->cash_minor((string) ($order['amount'] ?? '0'));
|
||||
$fallback_minor = max(0, $amount_minor + $discount_minor - $shipping_minor);
|
||||
$subtotal_minor = $this->calculate_order_subtotal_minor($items, $fallback_minor, $is_points);
|
||||
$amount = $is_points ? $amount_minor : \AKSRT\Ledger\AssetAmount::decimal_from_minor($amount_minor);
|
||||
$shipping_fee = $is_points ? $shipping_minor : \AKSRT\Ledger\AssetAmount::decimal_from_minor($shipping_minor);
|
||||
$discount = $is_points ? $discount_minor : \AKSRT\Ledger\AssetAmount::decimal_from_minor($discount_minor);
|
||||
$subtotal = $is_points ? $subtotal_minor : \AKSRT\Ledger\AssetAmount::decimal_from_minor($subtotal_minor);
|
||||
|
||||
$address['full_text'] = $this->build_address_text($address);
|
||||
|
||||
@@ -444,7 +468,7 @@ trait OrderRepositoryAdmin {
|
||||
'status' => $status,
|
||||
'status_label' => class_exists('AKSRT\\Payment\\Order') ? (Order::get_valid_statuses()[$status] ?? $status) : $status,
|
||||
'amount' => $amount,
|
||||
'currency_symbol' => '¥',
|
||||
'currency_symbol' => $is_points ? __('积分', 'aksrt') : '¥',
|
||||
'created_at' => (string) ($order['created_at'] ?? ''),
|
||||
'paid_at' => (string) ($order['paid_at'] ?? ''),
|
||||
'product_type' => (string) ($order['product_type'] ?? ''),
|
||||
@@ -492,26 +516,49 @@ trait OrderRepositoryAdmin {
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $items
|
||||
*/
|
||||
private function calculate_order_subtotal(array $items, float $fallback): float {
|
||||
private function calculate_order_subtotal_minor(array $items, int $fallback, bool $is_points): int {
|
||||
if (empty($items)) {
|
||||
return round($fallback, 2);
|
||||
return max(0, $fallback);
|
||||
}
|
||||
|
||||
$subtotal = 0.0;
|
||||
$subtotal = 0;
|
||||
foreach ($items as $item) {
|
||||
if (isset($item['line_total'])) {
|
||||
$subtotal += (float) $item['line_total'];
|
||||
$line_minor = $is_points
|
||||
? max(0, (int) $item['line_total'])
|
||||
: $this->cash_minor((string) $item['line_total']);
|
||||
if ($subtotal > PHP_INT_MAX - $line_minor) {
|
||||
return max(0, $fallback);
|
||||
}
|
||||
$subtotal += $line_minor;
|
||||
continue;
|
||||
}
|
||||
|
||||
$subtotal += (float) ($item['price'] ?? 0) * max(1, (int) ($item['quantity'] ?? 1));
|
||||
$price_minor = $is_points
|
||||
? max(0, (int) ($item['price'] ?? 0))
|
||||
: $this->cash_minor((string) ($item['price'] ?? '0'));
|
||||
$quantity = max(1, (int) ($item['quantity'] ?? 1));
|
||||
if ($price_minor > intdiv(PHP_INT_MAX, $quantity)
|
||||
|| $subtotal > PHP_INT_MAX - ($price_minor * $quantity)
|
||||
) {
|
||||
return max(0, $fallback);
|
||||
}
|
||||
$subtotal += $price_minor * $quantity;
|
||||
}
|
||||
|
||||
if ($subtotal <= 0) {
|
||||
return round($fallback, 2);
|
||||
return max(0, $fallback);
|
||||
}
|
||||
|
||||
return round($subtotal, 2);
|
||||
return $subtotal;
|
||||
}
|
||||
|
||||
private function cash_minor(string $value): int {
|
||||
try {
|
||||
return \AKSRT\Ledger\AssetAmount::balance_minor($value);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user