diff --git a/.gitignore b/.gitignore
index 78c0ee49..e5aa37d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,6 +27,7 @@
!/tests/widget-system/user-features-contract.test.cjs
!/tests/widget-system/asset-ledger-contract.test.cjs
!/tests/widget-system/financial-flow-contract.test.cjs
+!/tests/widget-system/pay-orders-filter-contract.test.cjs
!/tests/asset-ledger/
!/tests/asset-ledger/*.php
!/tests/visual/docker-compose.zibll.yml
diff --git a/src/Admin/Native/PayOrders.php b/src/Admin/Native/PayOrders.php
index 45b7d82f..c6ef204f 100644
--- a/src/Admin/Native/PayOrders.php
+++ b/src/Admin/Native/PayOrders.php
@@ -48,6 +48,20 @@ class PayOrders {
return;
}
+ $type_tabs = [
+ '' => __('全部类型', 'aksrt'),
+ \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE => __('内容付费', 'aksrt'),
+ \AKSRT\Core\DomainModel::ORDER_PRODUCT_VIP => __('VIP', 'aksrt'),
+ \AKSRT\Core\DomainModel::ORDER_PRODUCT_RECHARGE => __('充值', 'aksrt'),
+ \AKSRT\Core\DomainModel::ORDER_PRODUCT_POINTS => __('购买积分', 'aksrt'),
+ ];
+ $method_tabs = [
+ '' => __('支付方式', 'aksrt'),
+ 'balance' => __('余额', 'aksrt'),
+ 'points' => __('积分', 'aksrt'),
+ 'gateway' => __('第三方网关支付', 'aksrt'),
+ ];
+
$status = isset($_GET['status']) ? sanitize_key((string) wp_unslash($_GET['status'])) : '';
$search = isset($_GET['s']) ? sanitize_text_field((string) wp_unslash($_GET['s'])) : '';
$product_type = isset($_GET['product_type']) ? sanitize_key((string) wp_unslash($_GET['product_type'])) : '';
@@ -57,6 +71,13 @@ class PayOrders {
$page_num = max(1, (int) ($_GET['paged'] ?? 1));
$per_page = 20;
+ if (!array_key_exists($product_type, $type_tabs)) {
+ $product_type = '';
+ }
+ if (!array_key_exists($pay_method, $method_tabs)) {
+ $pay_method = '';
+ }
+
$repo = \AKSRT\Payment\OrderRepository::get_instance();
$args = [
'limit' => $per_page,
@@ -74,8 +95,10 @@ class PayOrders {
if ($user_id > 0) {
$args['user_id'] = $user_id;
}
- if ($pay_method !== '') {
- $args['payment_method'] = $pay_method;
+ if ($pay_method === 'gateway') {
+ $args['payment_methods'] = $this->third_party_gateway_ids();
+ } elseif ($pay_method !== '') {
+ $args['payment_methods'] = [$pay_method];
}
$items = $repo->get_orders_admin($args, $search);
@@ -86,13 +109,6 @@ class PayOrders {
: [];
// Type tabs.
- $type_tabs = [
- '' => __('全部类型', 'aksrt'),
- 'resource' => __('内容付费', 'aksrt'),
- 'vip' => __('VIP', 'aksrt'),
- 'recharge' => __('充值', 'aksrt'),
- 'shop_product' => __('商城商品', 'aksrt'),
- ];
echo '
';
$tab_bits = [];
foreach ($type_tabs as $tkey => $tlabel) {
@@ -111,13 +127,6 @@ class PayOrders {
echo '
';
// Payment method quick tabs.
- $method_tabs = [
- '' => __('全部支付', 'aksrt'),
- 'balance' => __('余额', 'aksrt'),
- 'points' => __('积分', 'aksrt'),
- 'alipay' => __('支付宝', 'aksrt'),
- 'wechat' => __('微信', 'aksrt'),
- ];
echo '';
$m_bits = [];
foreach ($method_tabs as $mkey => $mlabel) {
@@ -172,7 +181,7 @@ class PayOrders {
$filter_bits[] = sprintf(__('用户=%d', 'aksrt'), $user_id);
}
if ($pay_method !== '') {
- $filter_bits[] = sprintf(__('支付=%s', 'aksrt'), $pay_method);
+ $filter_bits[] = sprintf(__('支付方式=%s', 'aksrt'), $method_tabs[$pay_method]);
}
echo ' ' . esc_html(implode(' · ', $filter_bits)) . '';
echo ' ' . esc_html__('清除过滤', 'aksrt') . '';
@@ -214,7 +223,7 @@ class PayOrders {
$product_type = sanitize_key((string) ($row['product_type'] ?? ''));
$meta = is_array($row['meta_payload'] ?? null) ? $row['meta_payload'] : [];
$product_title = (string) ($meta['product_title'] ?? $meta['title'] ?? $meta['package_title'] ?? '');
- if ($product_title === '' && $product_id > 0 && in_array($product_type, ['resource', 'shop_product'], true)) {
+ if ($product_title === '' && $product_id > 0 && $product_type === \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE) {
$product_title = (string) get_the_title($product_id);
}
@@ -451,6 +460,14 @@ class PayOrders {
}
}
+ /** @return string[] */
+ private function third_party_gateway_ids(): array {
+ return array_values(array_diff(
+ array_keys(\AKSRT\Payment\Gateway::get_instance()->get_all()),
+ ['balance', 'points']
+ ));
+ }
+
/** @param array $order */
private function order_amount(array $order): string {
$currency = sanitize_key((string) ($order['currency'] ?? ''));
diff --git a/src/Payment/OrderRepositoryAdmin.php b/src/Payment/OrderRepositoryAdmin.php
index c4800ce0..e1da818c 100644
--- a/src/Payment/OrderRepositoryAdmin.php
+++ b/src/Payment/OrderRepositoryAdmin.php
@@ -369,10 +369,17 @@ trait OrderRepositoryAdmin {
$params[] = $user_id;
}
- $payment_method = sanitize_key((string) ($args['payment_method'] ?? ''));
- if ($payment_method !== '') {
- $where[] = 'payment_method = %s';
- $params[] = $payment_method;
+ if (array_key_exists('payment_methods', $args)) {
+ $payment_methods = array_values(array_unique(array_filter(array_map(
+ static fn($method): string => sanitize_key((string) $method),
+ (array) $args['payment_methods']
+ ))));
+ if ($payment_methods === []) {
+ $where[] = '1 = 0';
+ } else {
+ $where[] = 'payment_method IN (' . implode(', ', array_fill(0, count($payment_methods), '%s')) . ')';
+ array_push($params, ...$payment_methods);
+ }
}
if ($search !== '') {
diff --git a/tests/widget-system/pay-orders-filter-contract.test.cjs b/tests/widget-system/pay-orders-filter-contract.test.cjs
new file mode 100644
index 00000000..21b21c2b
--- /dev/null
+++ b/tests/widget-system/pay-orders-filter-contract.test.cjs
@@ -0,0 +1,35 @@
+const fs = require('node:fs')
+const path = require('node:path')
+const test = require('node:test')
+const assert = require('node:assert/strict')
+
+const root = path.resolve(__dirname, '..', '..')
+const read = (relativePath) => fs.readFileSync(path.join(root, relativePath), 'utf8')
+
+test('admin order filters expose only the current order and payment categories', () => {
+ const page = read('src/Admin/Native/PayOrders.php')
+
+ assert.match(page, /ORDER_PRODUCT_RESOURCE\s*=>\s*__\('内容付费'/)
+ assert.match(page, /ORDER_PRODUCT_VIP\s*=>\s*__\('VIP'/)
+ assert.match(page, /ORDER_PRODUCT_RECHARGE\s*=>\s*__\('充值'/)
+ assert.match(page, /ORDER_PRODUCT_POINTS\s*=>\s*__\('购买积分'/)
+ assert.doesNotMatch(page, /shop_product|商城商品/)
+
+ assert.match(page, /''\s*=>\s*__\('支付方式'/)
+ assert.match(page, /'balance'\s*=>\s*__\('余额'/)
+ assert.match(page, /'points'\s*=>\s*__\('积分'/)
+ assert.match(page, /'gateway'\s*=>\s*__\('第三方网关支付'/)
+ assert.doesNotMatch(page, /全部支付|支付宝'|微信'/)
+})
+
+test('third-party payment filter resolves registered external gateways as one query', () => {
+ const page = read('src/Admin/Native/PayOrders.php')
+ const repository = read('src/Payment/OrderRepositoryAdmin.php')
+
+ assert.match(page, /\$args\['payment_methods'\]\s*=\s*\$this->third_party_gateway_ids\(\)/)
+ assert.match(page, /array_diff\(\s*array_keys\(.*?get_all\(\)\),\s*\['balance', 'points'\]\s*\)/s)
+ assert.match(repository, /array_key_exists\('payment_methods',\s*\$args\)/)
+ assert.match(repository, /payment_method IN \('/)
+ assert.match(repository, /\$payment_methods === \[\][\s\S]*?'1 = 0'/)
+ assert.doesNotMatch(repository, /\$args\['payment_method'\]/)
+})