From 75d1e6e53b22e72534e7c2762ee8659f49962081 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Aug 2026 05:59:50 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=BA=86=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=B0=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user-center-renderers/credits-wallet.php | 7 +++++-- .../user-center-renderers/profile-credits.php | 9 ++++++--- src/Ledger/LedgerQuery.php | 8 ++++++-- src/Payment/Withdrawal.php | 5 ++++- tests/asset-ledger/WithdrawalTest.php | 18 ++++++++++++++++++ tests/asset-ledger/bootstrap.php | 1 + .../financial-flow-contract.test.cjs | 12 ++++++++++++ 7 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 tests/asset-ledger/WithdrawalTest.php diff --git a/inc/helpers/user-center-renderers/credits-wallet.php b/inc/helpers/user-center-renderers/credits-wallet.php index 426111a8..293be271 100644 --- a/inc/helpers/user-center-renderers/credits-wallet.php +++ b/inc/helpers/user-center-renderers/credits-wallet.php @@ -251,6 +251,9 @@ endif; ?> $delta = (int) $row['delta_minor']; $delta_class = $delta >= 0 ? 'is-positive' : 'is-negative'; $delta_txt = ($delta > 0 ? '+' : '-') . \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, abs($delta))->formatted(); + $record_note = in_array((string) $row['reason'], ['withdraw_hold', 'withdraw_refund'], true) + ? (string) ($row['withdrawal_number'] ?? '') + : (string) ($row['remark'] ?? ''); ?>
@@ -259,8 +262,8 @@ endif; ?>
- - () + + ()
diff --git a/inc/helpers/user-center-renderers/profile-credits.php b/inc/helpers/user-center-renderers/profile-credits.php index 0612fc7c..0363dbfc 100644 --- a/inc/helpers/user-center-renderers/profile-credits.php +++ b/inc/helpers/user-center-renderers/profile-credits.php @@ -82,9 +82,12 @@ if ($show_wallet || $show_credits) : $delta = (int) $row['delta_minor']; $delta_class = $delta >= 0 ? 'is-positive' : 'is-negative'; $delta_txt = ($delta > 0 ? '+' : '-') . \AKSRT\Ledger\AssetAmount::from_minor(\AKSRT\Ledger\AssetType::BALANCE, abs($delta))->formatted(); - $record_note = (string) $row['reason'] === 'points_exchange' - ? (string) $row['ref_key'] - : (string) $row['remark']; + $record_note = (string) $row['reason'] === 'points_exchange' + ? (string) $row['ref_key'] + : (string) $row['remark']; + if (in_array((string) $row['reason'], ['withdraw_hold', 'withdraw_refund'], true)) { + $record_note = (string) ($row['withdrawal_number'] ?? ''); + } ?>
diff --git a/src/Ledger/LedgerQuery.php b/src/Ledger/LedgerQuery.php index ad836803..399768a9 100644 --- a/src/Ledger/LedgerQuery.php +++ b/src/Ledger/LedgerQuery.php @@ -42,6 +42,7 @@ final class LedgerQuery { $entry_table = \AKSRT\Core\DBMigrator::table('asset_entry'); $transaction_table = \AKSRT\Core\DBMigrator::table('asset_transaction'); + $flow_table = \AKSRT\Core\DBMigrator::table('financial_flow'); $where = ['1=1']; $params = []; if ($user_id > 0) { @@ -107,8 +108,10 @@ final class LedgerQuery { $entry_params[] = $asset; } $rows = $wpdb->get_results($wpdb->prepare( - "SELECT e.*, t.operation_key, t.reason, t.ref_type, t.ref_key, t.actor_user_id, t.metadata, t.created_at transaction_created_at - FROM {$entry_table} e INNER JOIN {$transaction_table} t ON t.id = e.transaction_id + "SELECT e.*, t.operation_key, t.reason, t.ref_type, t.ref_key, t.actor_user_id, t.metadata, t.created_at transaction_created_at, f.withdrawal_number + FROM {$entry_table} e + INNER JOIN {$transaction_table} t ON t.id = e.transaction_id + LEFT JOIN {$flow_table} f ON f.ledger_transaction_id = t.id WHERE " . implode(' AND ', $entry_where) . ' ORDER BY e.transaction_id DESC, e.line_no ASC', $entry_params ), ARRAY_A); @@ -123,6 +126,7 @@ final class LedgerQuery { 'reason' => (string) $row['reason'], 'ref_type' => (string) ($row['ref_type'] ?? ''), 'ref_key' => (string) ($row['ref_key'] ?? ''), + 'withdrawal_number' => (string) ($row['withdrawal_number'] ?? ''), 'actor_user_id' => (int) ($row['actor_user_id'] ?? 0), 'metadata' => json_decode((string) ($row['metadata'] ?? ''), true) ?: [], 'created_at' => (string) $row['transaction_created_at'], diff --git a/src/Payment/Withdrawal.php b/src/Payment/Withdrawal.php index 5181b1be..17c3360a 100644 --- a/src/Payment/Withdrawal.php +++ b/src/Payment/Withdrawal.php @@ -669,7 +669,10 @@ class Withdrawal { $row['amount'] = $this->database_balance_decimal((string) ($row['amount'] ?? '0')); $row['fee_rate'] = (int) ($meta['fee_rate'] ?? 0); $display = (string) ($meta['account'] ?? $row['account_info'] ?? ''); - $row['display_account'] = strlen($display) > 4 ? substr($display, 0, 2) . str_repeat('*', max(2, strlen($display) - 4)) . substr($display, -2) : '****'; + $display_length = mb_strlen($display, 'UTF-8'); + $row['display_account'] = $display_length > 4 + ? mb_substr($display, 0, 2, 'UTF-8') . str_repeat('*', max(2, $display_length - 4)) . mb_substr($display, -2, null, 'UTF-8') + : '****'; $row['source'] = (string) ($meta['source'] ?? 'balance'); return $row; } diff --git a/tests/asset-ledger/WithdrawalTest.php b/tests/asset-ledger/WithdrawalTest.php new file mode 100644 index 00000000..8ba95d7b --- /dev/null +++ b/tests/asset-ledger/WithdrawalTest.php @@ -0,0 +1,18 @@ +invoke(Withdrawal::get_instance(), [ + 'account_info' => wp_json_encode(['account' => '账户名称 账户号码']), + 'gross_amount' => '100.00', + 'amount' => '95.00', + ]); + + self::assertSame('账户*****号码', $row['display_account']); + self::assertSame(1, preg_match('//u', $row['display_account'])); + } +} diff --git a/tests/asset-ledger/bootstrap.php b/tests/asset-ledger/bootstrap.php index 3d8a6668..d6c1981a 100644 --- a/tests/asset-ledger/bootstrap.php +++ b/tests/asset-ledger/bootstrap.php @@ -70,3 +70,4 @@ require_once dirname(__DIR__, 2) . '/src/Ledger/LedgerCommand.php'; require_once dirname(__DIR__, 2) . '/src/Ledger/LedgerResult.php'; require_once dirname(__DIR__, 2) . '/src/Ledger/OperationKey.php'; require_once dirname(__DIR__, 2) . '/src/Finance/BusinessNumber.php'; +require_once dirname(__DIR__, 2) . '/src/Payment/Withdrawal.php'; diff --git a/tests/widget-system/financial-flow-contract.test.cjs b/tests/widget-system/financial-flow-contract.test.cjs index d2166683..ebd59e31 100644 --- a/tests/widget-system/financial-flow-contract.test.cjs +++ b/tests/widget-system/financial-flow-contract.test.cjs @@ -41,3 +41,15 @@ test('native and front-end surfaces expose immutable business numbers', () => { assert.match(read('assets/js/order-center.js'), /\["流水号", order\.flow_number \|\| "—"\]/) assert.match(read('inc/helpers/user-center-renderers/credits-wallet.php'), /withdrawal_number/) }) + +test('balance history renders withdrawal numbers from the committed flow', () => { + const query = read('src/Ledger/LedgerQuery.php') + const profile = read('inc/helpers/user-center-renderers/profile-credits.php') + const wallet = read('inc/helpers/user-center-renderers/credits-wallet.php') + assert.match(query, /LEFT JOIN \{\$flow_table\} f ON f\.ledger_transaction_id = t\.id/) + assert.match(query, /'withdrawal_number'\s*=>\s*\(string\)/) + for (const source of [profile, wallet]) { + assert.match(source, /\['withdraw_hold', 'withdraw_refund'\]/) + assert.match(source, /\$row\['withdrawal_number'\]/) + } +})