user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $schema = Schema::connection('business_mirror'); if (! $schema->hasTable('ops_fys_company_info')) { $schema->create('ops_fys_company_info', function (Blueprint $table): void { $table->integer('Id')->primary(); $table->string('businessLicenseName')->nullable(); $table->string('legalRepresentative')->nullable(); }); } } private function ledgerUrl(): string { return route('business.pages.show', [ 'company_id' => $this->company->id, 'section' => 'financial-operations', 'page' => 'ledger', ]); } private function keepTasksUrl(array $parameters = []): string { return route('business.financial-ledger.unretained-accounts', array_merge([ 'company_id' => $this->company->id, ], $parameters)); } private function keepTodoUrl(): string { return route('business.financial-ledger.accounts.keep-todo', [ 'company_id' => $this->company->id, ]); } public function test_ledger_card_follows_account_count_and_links_to_independent_keep_tasks(): void { DB::connection('business_mirror')->table('fin_accounts')->insert([ [ 'company_name' => '不保留测试公司甲', 'account_short' => '显式不保留账户', 'company_plan' => '保留', 'account_should_keep' => '否', ], [ 'company_name' => '不保留测试公司乙', 'account_short' => '规划不保留账户', 'company_plan' => '待注销', 'account_should_keep' => null, ], [ 'company_name' => '不保留测试公司丙', 'account_short' => '明确保留账户', 'company_plan' => '待注销', 'account_should_keep' => '是', ], [ 'company_name' => '不保留测试公司丁', 'account_short' => '规划保留账户', 'company_plan' => '保留', 'account_should_keep' => null, ], ]); $response = $this->loginAs()->get($this->ledgerUrl())->assertOk(); $content = $response->getContent(); $this->assertMatchesRegularExpression( '/账户数<\/span>4<\/b><\/div>\s*]+aria-label="查看不保留账户处理待办"[^>]*>不保留账户数<\/span>2<\/b><\/a>/u', $content, ); $response->assertSee('href="' . $this->keepTasksUrl() . '"', false); } public function test_keep_tasks_page_uses_required_columns_filters_and_retention_rule(): void { $connection = DB::connection('business_mirror'); $connection->table('fin_accounts')->insert([ [ 'company_name' => '展示测试公司甲', 'account_short' => '显式不保留账户', 'account_type' => '公户', 'account_no' => '6222000000000001', 'bank_name' => '展示测试银行甲', 'bank_city_branch' => '上海 / 测试支行', 'company_plan' => '保留', 'account_should_keep' => '否', ], [ 'company_name' => '展示测试公司乙', 'account_short' => '规划不保留账户', 'account_type' => '个人卡', 'account_no' => null, 'bank_name' => null, 'bank_city_branch' => null, 'company_plan' => '待注销', 'account_should_keep' => null, ], [ 'company_name' => '展示测试公司丙', 'account_short' => '明确保留账户', 'account_type' => '支付宝', 'account_no' => null, 'bank_name' => null, 'bank_city_branch' => null, 'company_plan' => '待注销', 'account_should_keep' => '是', ], [ 'company_name' => '展示测试公司丁', 'account_short' => '规划保留账户', 'account_type' => '网商银行', 'account_no' => null, 'bank_name' => null, 'bank_city_branch' => null, 'company_plan' => '保留', 'account_should_keep' => null, ], ]); $connection->table('fin_account_statuses')->insert([ 'account_short' => '显式不保留账户', 'status' => 'limited', 'updated_by' => 'Test User', ]); $connection->table('ops_fys_company_info')->insert([ [ 'Id' => 1, 'businessLicenseName' => '展示测试公司甲', 'legalRepresentative' => '旧法人甲', ], [ 'Id' => 2, 'businessLicenseName' => '展示测试公司甲', 'legalRepresentative' => '展示法人甲', ], [ 'Id' => 3, 'businessLicenseName' => '展示测试公司乙', 'legalRepresentative' => '展示法人乙', ], ]); $response = $this->loginAs()->get($this->keepTasksUrl())->assertOk(); $content = $response->getContent(); $response ->assertSee('不保留账户处理待办') ->assertSee('不与其他页面的待办事项合并') ->assertSee('data-keep-account="显式不保留账户"', false) ->assertSee('data-keep-account="规划不保留账户"', false) ->assertSee('法人名称') ->assertSee('展示法人甲') ->assertSee('展示法人乙') ->assertDontSee('旧法人甲') ->assertDontSee('data-keep-account="明确保留账户"', false) ->assertDontSee('data-keep-account="规划保留账户"', false) ->assertSee('name="keep_short"', false) ->assertSee('name="keep_type"', false) ->assertSee('name="keep_status"', false) ->assertSee('name="keep_method"', false) ->assertSee('name="keep_owner"', false) ->assertSee('name="keep_progress"', false) ->assertSee('开始时间排序和筛选') ->assertSee('完成时间排序和筛选') ->assertSee('线上') ->assertSee('线下') ->assertSee('玉兔') ->assertSee('山时') ->assertSee('aria-label="责任人员"', false) ->assertSee('aria-label="开始时间"', false) ->assertSee('aria-label="完成时间"', false) ->assertSee('type="date" name="started_at"', false) ->assertSee('type="date" name="completed_at"', false) ->assertSee('data-ledger-header-searchable-filter', false) ->assertSee('list="ledger-header-options-keep-account_short"', false) ->assertSee('name="keep_filter_column"', false) ->assertSee('name="keep_filter_value"', false) ->assertSee('公司名称排序和筛选') ->assertSee('keep_sort=account_short', false) ->assertSee('keep_sort=account_status', false) ->assertSee('keep_sort=owner_name', false) ->assertSee('keep_sort=current_progress', false) ->assertSee('已完成') ->assertSee('进行中') ->assertSee('待开始') ->assertSee('data-keep-tbody', false) ->assertSee('data-keep-pagination', false) ->assertSee('拖动表头右侧边界可调整列宽') ->assertSee('cursor:col-resize', false) ->assertSee('position:sticky', false) ->assertSee('currentBody.replaceWith', false) ->assertSee('history.replaceState', false) ->assertSee('nextWrap.scrollTop = scrollTop', false); preg_match_all('/data-ledger-header-field="([^"]+)"/u', $content, $matches); $this->assertSame([ 'company_name', 'account_short', 'legal_representative', 'account_type', 'account_status', 'account_no', 'bank_name', 'bank_city_branch', 'account_should_keep', 'handling_method', 'owner_name', 'started_at', 'completed_at', 'current_progress', ], $matches[1]); } public function test_keep_tasks_sort_all_headers_by_effective_display_values(): void { $connection = DB::connection('business_mirror'); $connection->table('fin_accounts')->insert([ [ 'company_name' => '排序公司甲', 'account_short' => '排序账户甲', 'account_type' => '公户', 'company_plan' => '保留', 'account_should_keep' => '否', ], [ 'company_name' => '排序公司乙', 'account_short' => '排序账户乙', 'account_type' => '网商银行', 'company_plan' => '待注销', 'account_should_keep' => null, ], ]); $connection->table('fin_account_type_overrides')->insert([ 'account_short' => '排序账户甲', 'account_type' => '个人卡', 'updated_by' => 'Test User', ]); $connection->table('fin_account_statuses')->insert([ 'account_short' => '排序账户甲', 'status' => 'limited', 'updated_by' => 'Test User', ]); $connection->table('fin_account_keep_todos')->insert([ [ 'account_short' => '排序账户甲', 'handling_method' => 'online', 'owner_name' => '玉兔', 'current_progress' => 'completed', ], [ 'account_short' => '排序账户乙', 'handling_method' => 'offline', 'owner_name' => '山时', 'current_progress' => 'not_started', ], ]); $connection->table('ops_fys_company_info')->insert([ [ 'Id' => 21, 'businessLicenseName' => '排序公司甲', 'legalRepresentative' => '鲍法人', ], [ 'Id' => 22, 'businessLicenseName' => '排序公司乙', 'legalRepresentative' => '安法人', ], ]); $sort = function (string $field, string $direction = 'asc'): array { $response = $this->loginAs()->get($this->keepTasksUrl([ 'keep_sort' => $field, 'keep_direction' => $direction, ]))->assertOk(); preg_match_all('/data-keep-account="([^"]+)"/u', $response->getContent(), $matches); return $matches[1]; }; $this->assertSame(['排序账户乙', '排序账户甲'], $sort('legal_representative')); $this->assertSame(['排序账户甲', '排序账户乙'], $sort('account_type')); $this->assertSame(['排序账户乙', '排序账户甲'], $sort('account_status')); $this->assertSame(['排序账户乙', '排序账户甲'], $sort('current_progress')); $this->assertSame(['排序账户甲', '排序账户乙'], $sort('current_progress', 'desc')); } public function test_legal_representative_filter_options_show_account_counts(): void { $connection = DB::connection('business_mirror'); $connection->table('fin_accounts')->insert([ [ 'company_name' => '法人计数公司甲', 'account_short' => '法人计数甲一', 'account_type' => '网商银行', 'company_plan' => '保留', 'account_should_keep' => '否', ], [ 'company_name' => '法人计数公司甲', 'account_short' => '法人计数甲二', 'account_type' => '公户', 'company_plan' => '保留', 'account_should_keep' => '否', ], [ 'company_name' => '法人计数公司乙', 'account_short' => '法人计数乙', 'account_type' => '网商银行', 'company_plan' => '保留', 'account_should_keep' => '否', ], ]); $connection->table('ops_fys_company_info')->insert([ 'Id' => 31, 'businessLicenseName' => '法人计数公司甲', 'legalRepresentative' => '王法人', ]); $optionsResponse = $this->loginAs()->get($this->keepTasksUrl())->assertOk(); preg_match( '/(.*?)<\/datalist>/su', $optionsResponse->getContent(), $legalRepresentativeOptions, ); $legalRepresentativeOptions = $legalRepresentativeOptions[1] ?? ''; $this->assertStringContainsString('value="王法人(2)"', $legalRepresentativeOptions); $this->assertStringContainsString('value="未填写(1)"', $legalRepresentativeOptions); $this->assertStringNotContainsString('__empty__', $legalRepresentativeOptions); $typeFilteredResponse = $this->loginAs()->get($this->keepTasksUrl([ 'keep_filter_column' => 'account_type', 'keep_filter_value' => '网商银行', ]))->assertOk(); preg_match( '/(.*?)<\/datalist>/su', $typeFilteredResponse->getContent(), $typeFilteredLegalOptions, ); $typeFilteredLegalOptions = $typeFilteredLegalOptions[1] ?? ''; $this->assertStringContainsString('value="王法人(1)"', $typeFilteredLegalOptions); $this->assertStringContainsString('value="未填写(1)"', $typeFilteredLegalOptions); $this->assertStringNotContainsString('王法人(2)', $typeFilteredLegalOptions); $this->loginAs()->get($this->keepTasksUrl([ 'keep_filter_column' => 'legal_representative', 'keep_filter_value' => '王法人(2)', ]))->assertOk() ->assertSee('data-keep-account="法人计数甲一"', false) ->assertSee('data-keep-account="法人计数甲二"', false) ->assertDontSee('data-keep-account="法人计数乙"', false); $this->loginAs()->get($this->keepTasksUrl([ 'keep_filter_column' => 'legal_representative', 'keep_filter_value' => '未填写(1)', ]))->assertOk() ->assertSee('data-keep-account="法人计数乙"', false) ->assertDontSee('data-keep-account="法人计数甲一"', false) ->assertDontSee('data-keep-account="法人计数甲二"', false); } public function test_keep_tasks_header_filters_apply_with_typeahead_options(): void { $connection = DB::connection('business_mirror'); $connection->table('fin_accounts')->insert([ [ 'company_name' => '表头筛选公司甲', 'account_short' => '表头筛选甲', 'account_type' => '公户', 'company_plan' => '保留', 'account_should_keep' => '否', ], [ 'company_name' => '表头筛选公司乙', 'account_short' => '表头筛选乙', 'account_type' => '个人卡', 'company_plan' => '待注销', 'account_should_keep' => null, ], ]); $connection->table('fin_account_statuses')->insert([ 'account_short' => '表头筛选甲', 'status' => 'limited', 'updated_by' => 'Test User', ]); $connection->table('fin_account_keep_todos')->insert([ [ 'account_short' => '表头筛选甲', 'handling_method' => 'online', 'owner_name' => '玉兔', 'started_at' => '2026-10-21 00:00:00', 'current_progress' => 'in_progress', ], [ 'account_short' => '表头筛选乙', 'handling_method' => 'offline', 'owner_name' => '山时', 'started_at' => '2026-10-22 00:00:00', 'current_progress' => 'not_started', ], ]); $connection->table('ops_fys_company_info')->insert([ [ 'Id' => 11, 'businessLicenseName' => '表头筛选公司甲', 'legalRepresentative' => '表头法人甲', ], [ 'Id' => 12, 'businessLicenseName' => '表头筛选公司乙', 'legalRepresentative' => '表头法人乙', ], ]); $accountFiltered = $this->loginAs()->get($this->keepTasksUrl([ 'keep_filter_column' => 'account_short', 'keep_filter_value' => '表头筛选甲', ]))->assertOk() ->assertSee('data-keep-account="表头筛选甲"', false) ->assertDontSee('data-keep-account="表头筛选乙"', false) ->assertSee('ledger-header-cell', false) ->assertSee('is-filtered', false); $accountFiltered->assertSee('