user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $connection = DB::connection('business_mirror'); $connection->table('fin_accounts')->insert([ [ 'company_name' => '甲公司', 'account_short' => '账户甲', 'account_type' => '公户', 'region' => '上海', 'company_plan' => '保留', 'account_should_keep' => '是', 'current_balance' => 100, 'daily_available' => 80, 'blocked_amount' => 20, ], [ 'company_name' => '乙公司', 'account_short' => '账户乙', 'account_type' => '支付宝', 'region' => '杭州', 'company_plan' => '待注销', 'account_should_keep' => '否', 'current_balance' => 300, 'daily_available' => 300, 'blocked_amount' => 0, ], ]); $connection->table('fin_shops')->insert([ [ 'shop_name' => '天猫店铺', 'platform' => '天猫', 'company_name' => '甲公司', 'account_short' => '账户甲', 'status' => '在营', 'shop_balance' => 100, ], [ 'shop_name' => '拼多多店铺', 'platform' => '拼多多', 'company_name' => '乙公司', 'account_short' => '账户乙', 'status' => '停业', 'shop_balance' => 300, ], ]); $connection->table('fin_daily_flows')->insert([ [ 'flow_date' => '2026-10-17', 'company_name' => '甲公司', 'account_short' => '账户甲', 'opening_balance' => 100, 'inflow' => 10, 'outflow' => 0, 'closing_balance' => 110, ], [ 'flow_date' => '2026-10-18', 'company_name' => '乙公司', 'account_short' => '账户乙', 'opening_balance' => 300, 'inflow' => 0, 'outflow' => 20, 'closing_balance' => 280, ], ]); $connection->table('fin_transactions')->insert([ [ 'txn_date' => '2026-10-17', 'account_short' => '账户甲', 'detail' => '甲笔流水', 'income' => 10, 'expense' => 0, 'approval_no' => 'APR-甲', 'source' => 'dingtalk', 'source_value' => 'VAL-甲', 'process_type' => '报销', 'row_key' => 'header-filter-row-a', ], [ 'txn_date' => '2026-10-18', 'account_short' => '账户乙', 'detail' => '乙笔流水', 'income' => 0, 'expense' => 20, 'approval_no' => 'APR-乙', 'source' => 'shop', 'source_value' => 'VAL-乙', 'process_type' => '提现', 'row_key' => 'header-filter-row-b', ], ]); $connection->table('fin_account_map')->insert([ [ 'source' => 'dingtalk', 'source_value' => 'VAL-甲', 'account_short' => '账户甲', 'txn_count' => 1, 'income_sum' => 10, 'expense_sum' => 0, ], [ 'source' => 'shop', 'source_value' => 'VAL-乙', 'account_short' => null, 'txn_count' => 1, 'income_sum' => 0, 'expense_sum' => 20, ], ]); } public function test_every_financial_ledger_table_has_a_header_menu(): void { $response = $this->loginAs()->get($this->pageUrl()); $html = $response->assertOk()->getContent(); $this->assertSame(63, preg_match_all('/]*data-ledger-header-details/', $html)); $this->assertSame(63, preg_match_all('/]*data-ledger-header-label/', $html)); foreach (['accounts', 'shops', 'flows', 'transactions', 'mapping', 'sources'] as $tab) { $this->assertStringContainsString('name="' . $tab . '_filter_value"', $html); $this->assertStringContainsString($tab . '_sort=', $html); } } public function test_account_and_flow_headers_filter_and_sort_the_full_dataset(): void { $filtered = $this->loginAs()->get($this->pageUrl([ 'accounts_filter_column' => 'company_name', 'accounts_filter_value' => '乙公司', ]))->assertOk(); $filtered->assertSee('data-account-short="账户乙"', false) ->assertDontSee('data-account-short="账户甲"', false); $sortedAccounts = $this->loginAs()->get($this->pageUrl([ 'accounts_sort' => 'current_balance', 'accounts_direction' => 'desc', ]))->assertOk()->getContent(); $this->assertLessThan( strpos($sortedAccounts, 'data-account-short="账户甲"'), strpos($sortedAccounts, 'data-account-short="账户乙"'), ); $flows = $this->loginAs()->get($this->pageUrl([ 'accounts_filter_column' => 'company_name', 'accounts_filter_value' => '乙公司', 'shops_filter_column' => 'company_name', 'shops_filter_value' => '乙公司', 'flows_filter_column' => 'account_short', 'flows_filter_value' => '账户乙', ]))->assertOk(); $flows->assertSee('>乙公司', false) ->assertDontSee('>甲公司', false); } public function test_shop_transaction_mapping_and_source_headers_filter_their_tables(): void { $this->loginAs()->get($this->pageUrl([ 'shops_filter_column' => 'platform', 'shops_filter_value' => '天猫', ])) ->assertOk() ->assertSee('>天猫店铺', false) ->assertDontSee('>拼多多店铺', false); $this->loginAs()->get($this->pageUrl([ 'transactions_filter_column' => 'approval_no', 'transactions_filter_value' => 'APR-乙', 'transactions_sort' => 'expense', 'transactions_direction' => 'desc', ])) ->assertOk() ->assertSee('APR-乙') ->assertDontSee('APR-甲'); $this->loginAs()->get($this->pageUrl([ 'mapping_filter_column' => 'mapping_status', 'mapping_filter_value' => 'unmapped', ])) ->assertOk() ->assertSee('VAL-乙') ->assertDontSee('VAL-甲'); $this->loginAs()->get($this->pageUrl([ 'sources_filter_column' => 'source', 'sources_filter_value' => 'shop', ])) ->assertOk() ->assertSee('>提现', false) ->assertDontSee('>报销', false); } private function pageUrl(array $parameters = []): string { return route('business.pages.show', array_merge([ 'company_id' => $this->company->id, 'section' => 'financial-operations', 'page' => 'ledger', ], $parameters)); } }