CaiWuXiTong/tests/Feature/Business/FinanceLedgerAccountKeepTodoTest.php
shanshi 5d8bbc36a2 feat(财务台账): 法人筛选显示账户数量 (#515)
法人名称筛选显示账户数量,并支持未填写数量与带数量筛选。
2026-10-24 19:21:05 +08:00

630 lines
26 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Feature\Business;
use App\Models\Auth\Permission;
use App\Models\Auth\Role;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\Feature\FeatureTestCase;
class FinanceLedgerAccountKeepTodoTest extends FeatureTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->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>账户数<\/span><b>4<\/b><\/div>\s*<a[^>]+aria-label="查看不保留账户处理待办"[^>]*><span>不保留账户数<\/span><b>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 id="ledger-header-options-keep-legal_representative">(.*?)<\/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 id="ledger-header-options-keep-legal_representative">(.*?)<\/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('<option value="表头筛选乙"', false);
$this->loginAs()->get($this->keepTasksUrl([
'keep_filter_column' => 'legal_representative',
'keep_filter_value' => '表头法人乙',
]))->assertOk()
->assertSee('data-keep-account="表头筛选乙"', false)
->assertDontSee('data-keep-account="表头筛选甲"', false);
$this->loginAs()->get($this->keepTasksUrl([
'keep_filter_column' => 'started_at',
'keep_filter_value' => '2026-10-21',
]))->assertOk()
->assertSee('data-keep-account="表头筛选甲"', false)
->assertDontSee('data-keep-account="表头筛选乙"', false);
}
public function test_keep_tasks_filters_sort_and_ajax_pagination_work(): 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 09:00:00',
'current_progress' => 'in_progress',
],
[
'account_short' => '筛选账户乙',
'handling_method' => 'offline',
'owner_name' => '山时',
'started_at' => '2026-10-22 09:00:00',
'current_progress' => 'not_started',
],
]);
$this->loginAs()->get($this->keepTasksUrl([
'keep_short' => '筛选账户甲',
'keep_type' => '公户',
'keep_status' => 'limited',
'keep_method' => 'online',
'keep_owner' => '玉兔',
'keep_progress' => 'in_progress',
]))
->assertOk()
->assertSee('data-keep-account="筛选账户甲"', false)
->assertDontSee('data-keep-account="筛选账户乙"', false)
->assertSee('value="limited" selected', false)
->assertSee('value="online" selected', false)
->assertSee('value="in_progress" selected', false);
$sortResponse = $this->loginAs()->get($this->keepTasksUrl([
'keep_sort' => 'started_at',
'keep_direction' => 'desc',
]))->assertOk()->assertSee('aria-sort="descending"', false);
preg_match_all('/data-keep-account="([^"]+)"/u', $sortResponse->getContent(), $sortedAccounts);
$this->assertSame(['筛选账户乙', '筛选账户甲'], $sortedAccounts[1]);
$pageRows = [];
for ($index = 1; $index <= 51; $index++) {
$pageRows[] = [
'company_name' => '分页公司',
'account_short' => 'keep-page-' . str_pad((string) $index, 2, '0', STR_PAD_LEFT),
'account_should_keep' => '否',
];
}
$connection->table('fin_accounts')->insert($pageRows);
$this->loginAs()->get($this->keepTasksUrl(['keep_short' => 'keep-page-']))
->assertOk()
->assertSee('1 / 2')
->assertSee('aria-label="下一页"', false)
->assertSee('data-keep-pagination', false);
$this->loginAs()->get($this->keepTasksUrl(['keep_short' => 'keep-page-', 'page' => 2]))
->assertOk()
->assertSee('2 / 2')
->assertSee('data-keep-account="keep-page-51"', false);
}
public function test_keep_todo_save_is_isolated_from_abnormal_tasks_and_permission_protected(): void
{
$connection = DB::connection('business_mirror');
$connection->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' => '是',
],
]);
$payload = [
'account_short' => '待办不保留账户',
'handling_method' => 'online',
'owner_name' => '玉兔',
'started_at' => '2026-10-21T09:00',
'completed_at' => '2026-10-21T11:30',
'current_progress' => 'in_progress',
];
$this->loginAs()->post($this->keepTodoUrl(), $payload)->assertRedirect();
$this->assertDatabaseHas('fin_account_keep_todos', [
'account_short' => '待办不保留账户',
'handling_method' => 'online',
'owner_name' => '玉兔',
'current_progress' => 'in_progress',
'updated_by' => 'Test User',
], 'business_mirror');
$this->assertDatabaseCount('fin_account_todos', 0, 'business_mirror');
$this->loginAs()->post($this->keepTodoUrl(), array_merge($payload, [
'current_progress' => 'completed',
]))->assertRedirect();
$this->assertDatabaseCount('fin_account_keep_todos', 1, 'business_mirror');
$this->assertDatabaseHas('fin_account_keep_todos', [
'account_short' => '待办不保留账户',
'current_progress' => 'completed',
], 'business_mirror');
$this->loginAs()->post($this->keepTodoUrl(), [
'account_short' => '规划不保留待办账户',
'current_progress' => 'not_started',
])->assertRedirect();
$this->assertDatabaseHas('fin_account_keep_todos', [
'account_short' => '规划不保留待办账户',
'current_progress' => 'not_started',
], 'business_mirror');
$this->withExceptionHandling()->loginAs()->post($this->keepTodoUrl(), [
'account_short' => '待办保留账户',
'current_progress' => 'not_started',
])->assertStatus(422);
$viewer = user_model_class()::create([
'name' => '不保留账户只读用户',
'email' => 'keep-viewer-' . uniqid() . '@example.com',
'password' => 'local-test-password',
'locale' => 'zh-CN',
'enabled' => 1,
'landing_page' => 'dashboard',
'created_from' => 'core::test',
]);
$viewer->companies()->attach($this->company->id);
$viewer->roles()->attach(Role::where('name', 'user')->firstOrFail()->id);
$viewer->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
$this->loginAs($viewer)->get($this->keepTasksUrl())
->assertOk()
->assertSee('disabled', false)
->assertDontSee('title="保存待办"', false);
$this->withExceptionHandling()->loginAs($viewer)->post($this->keepTodoUrl(), $payload)
->assertForbidden();
}
}