CaiWuXiTong/tests/Feature/Business/FinanceLedgerAccountStatusTest.php

412 lines
16 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\Support\Facades\DB;
use Tests\Feature\FeatureTestCase;
class FinanceLedgerAccountStatusTest extends FeatureTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->user->attachPermission(
Permission::where('name', 'read-admin-panel')->firstOrFail()
);
DB::connection('business_mirror')->table('fin_accounts')->insert([
'company_name' => '测试财务公司',
'account_short' => '测试账户',
'account_no' => '6222000000000001',
'bank_name' => '测试银行',
'company_plan' => '保留',
]);
}
private function pageUrl(): string
{
return route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
]);
}
private function statusUrl(): string
{
return route('business.financial-ledger.accounts.status', [
'company_id' => $this->company->id,
]);
}
private function typeUrl(): string
{
return route('business.financial-ledger.accounts.type', [
'company_id' => $this->company->id,
]);
}
private function planUrl(): string
{
return route('business.financial-ledger.accounts.plan', [
'company_id' => $this->company->id,
]);
}
private function keepUrl(): string
{
return route('business.financial-ledger.accounts.keep', [
'company_id' => $this->company->id,
]);
}
public function test_account_table_renders_status_selector_with_four_options(): void
{
$this->loginAs()->get($this->pageUrl())
->assertOk()
->assertSee('账户状态')
->assertSee('data-account-status', false)
->assertSee('正常')
->assertSee('网银异常')
->assertSee('限额')
->assertSee('工商注销')
->assertSee('name="accounts_short"', false)
->assertSee('name="accounts_status"', false)
->assertSee('name="accounts_region"', false)
->assertSee('name="accounts_type"', false)
->assertSee('data-account-type', false)
->assertSee('data-account-plan', false)
->assertSee('data-account-keep', false)
->assertSee('data-account-plan-display', false)
->assertSee('data-account-keep-display', false)
->assertSee('ledger-type-select', false)
->assertSee('data-mapping-bulk', false)
->assertSee('导出录入模板')
->assertSee('data-account-template-download', false)
->assertSee('data-account-template-download-status', false)
->assertSee('<th>账户简称</th><th>账户类型</th><th class="ledger-status-column">账户状态</th>', false)
->assertSee('<th>公司规划</th><th class="ledger-keep-column">账户是否保留</th><th>后4位</th>', false)
->assertSee('data-account-short="测试账户" data-account-should-keep="是"', false)
->assertSee('网商银行')
->assertSee('ledger-accounts-table-wrap', false)
->assertSee('ledger-pagination__controls', false)
->assertSee('ledger-page-box', false)
->assertSee('1 / 1', false)
->assertSee('data-ledger-column-picker', false)
->assertSee('data-ledger-column-panel', false)
->assertSee('data-ledger-edit-mode-toggle', false)
->assertSee('aria-checked="false"', false)
->assertSee('ledger-account-editor', false)
->assertSee('data-account-edit-display', false)
->assertSee('列设置')
->assertSee('拖动字段可调整列顺序')
->assertSee('恢复默认')
->assertSee('可用金额合计')
->assertSee('不可用金额合计')
->assertSee('可用金额 − 不可用金额')
->assertSee('未填写')
->assertDontSee('data-account-filter-state', false)
->assertSee('value="normal" selected', false);
}
public function test_financial_ledger_tab_forms_submit_to_query_tab_routes(): void
{
$pageUrl = $this->pageUrl();
$response = $this->loginAs()->get($pageUrl)->assertOk();
foreach (['accounts', 'shops', 'flows', 'transactions', 'mapping'] as $tab) {
$response->assertSee('action="' . $pageUrl . '?tab=' . $tab . '"', false);
$response->assertDontSee('action="' . $pageUrl . '/' . $tab . '"', false);
}
}
public function test_explicit_account_keep_value_takes_precedence_over_company_plan(): void
{
DB::connection('business_mirror')->table('fin_accounts')->insert([
'company_name' => '保留判断测试公司',
'account_short' => '显式不保留账户',
'company_plan' => '保留',
'account_should_keep' => '否',
]);
$this->loginAs()->get($this->pageUrl())
->assertOk()
->assertSee('data-account-short="显式不保留账户" data-account-should-keep="否"', false);
}
public function test_account_pagination_lists_page_urls_with_current_filter(): void
{
$rows = [];
for ($index = 1; $index <= 101; $index++) {
$rows[] = [
'company_name' => '分页测试公司',
'account_short' => 'page-test-' . $index,
];
}
DB::connection('business_mirror')->table('fin_accounts')->insert($rows);
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
'accounts_short' => 'page-test',
]))
->assertOk()
->assertSee('ledger-page-box', false)
->assertSee('aria-label="下一页"', false)
->assertSee('accounts_page=2', false)
->assertSee('accounts_short=page-test', false);
}
public function test_account_filters_narrow_by_short_status_region_and_type(): void
{
$connection = DB::connection('business_mirror');
$connection->table('fin_accounts')->insert([
[
'company_name' => '筛选测试公司甲',
'account_short' => '筛选账户甲',
'region' => '上海',
'account_type' => '公户',
],
[
'company_name' => '筛选测试公司乙',
'account_short' => '筛选账户乙',
'region' => '杭州',
'account_type' => '个人卡',
],
]);
$connection->table('fin_account_statuses')->insert([
'account_short' => '筛选账户乙',
'status' => 'limited',
'updated_by' => 'Test User',
]);
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
'accounts_short' => '筛选账户',
'accounts_status' => 'limited',
'accounts_region' => '杭州',
'accounts_type' => '个人卡',
]))
->assertOk()
->assertSee('data-account-short="筛选账户乙"', false)
->assertDontSee('data-account-short="筛选账户甲"', false)
->assertSee('data-account-filter-state', false)
->assertSee('筛选中')
->assertSee('value="limited" selected', false);
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
'accounts_short' => '筛选账户',
'accounts_status' => 'normal',
]))
->assertOk()
->assertSee('data-account-short="筛选账户甲"', false)
->assertDontSee('data-account-short="筛选账户乙"', false);
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
'accounts_short' => '测试账户',
'accounts_status' => 'normal',
'accounts_region' => '__empty__',
'accounts_type' => '__empty__',
]))
->assertOk()
->assertSee('data-account-short="测试账户"', false);
}
public function test_account_type_can_be_saved_and_filtered_by_effective_value(): void
{
$connection = DB::connection('business_mirror');
$connection->table('fin_accounts')->insert([
[
'company_name' => '类型测试公司甲',
'account_short' => '类型账户甲',
'account_type' => '公户',
],
[
'company_name' => '类型测试公司乙',
'account_short' => '类型账户乙',
'account_type' => '个人卡',
],
[
'company_name' => '类型测试公司丙',
'account_short' => '类型账户丙',
'account_type' => '支付宝',
],
]);
$this->loginAs()->postJson($this->typeUrl(), [
'account_short' => '类型账户甲',
'account_type' => '网商银行',
])
->assertOk()
->assertJsonPath('account_type', '网商银行')
->assertJsonPath('label', '网商银行');
$this->loginAs()->postJson($this->typeUrl(), [
'account_short' => '类型账户甲',
'account_type' => '个人卡',
])->assertOk();
$this->assertDatabaseCount('fin_account_type_overrides', 1, 'business_mirror');
$this->assertDatabaseHas('fin_account_type_overrides', [
'account_short' => '类型账户甲',
'account_type' => '个人卡',
'updated_by' => 'Test User',
], 'business_mirror');
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
'accounts_type' => '个人卡',
]))
->assertOk()
->assertSee('data-account-short="类型账户甲"', false)
->assertSee('data-account-short="类型账户乙"', false)
->assertDontSee('data-account-short="类型账户丙"', false)
->assertSee('value="个人卡" selected', false);
$this->loginAs()->get(route('business.pages.show', [
'company_id' => $this->company->id,
'section' => 'financial-operations',
'page' => 'ledger',
'accounts_type' => '公户',
]))
->assertOk()
->assertDontSee('data-account-short="类型账户甲"', false);
$this->withExceptionHandling()->loginAs()->postJson($this->typeUrl(), [
'account_short' => '类型账户甲',
'account_type' => '不存在的类型',
])->assertUnprocessable()->assertJsonPath('message', '请选择现有账户类型。');
}
public function test_account_status_can_be_saved_and_updated_without_duplicate_rows(): void
{
$payload = [
'account_short' => '测试账户',
'status' => 'limited',
];
$this->loginAs()->postJson($this->statusUrl(), $payload)
->assertOk()
->assertJsonPath('status', 'limited')
->assertJsonPath('label', '限额');
$this->loginAs()->postJson($this->statusUrl(), [
'account_short' => '测试账户',
'status' => 'normal',
])->assertOk()->assertJsonPath('label', '正常');
$this->assertDatabaseCount('fin_account_statuses', 1, 'business_mirror');
$this->assertDatabaseHas('fin_account_statuses', [
'account_short' => '测试账户',
'status' => 'normal',
'updated_by' => 'Test User',
], 'business_mirror');
$this->loginAs()->get($this->pageUrl())
->assertOk()
->assertSee('value="normal" selected', false);
}
public function test_company_plan_and_account_keep_can_be_updated(): void
{
DB::connection('business_mirror')->table('fin_accounts')->insert([
'company_name' => '规划选项公司',
'account_short' => '规划选项账户',
'company_plan' => '待注销',
]);
$this->loginAs()->postJson($this->planUrl(), [
'account_short' => '测试账户',
'company_plan' => '待注销',
])->assertOk()->assertJsonPath('label', '待注销');
$this->loginAs()->postJson($this->keepUrl(), [
'account_short' => '测试账户',
'account_should_keep' => '否',
])->assertOk()->assertJsonPath('label', '否');
$this->assertDatabaseHas('fin_accounts', [
'account_short' => '测试账户',
'company_plan' => '待注销',
'account_should_keep' => '否',
], 'business_mirror');
$this->withExceptionHandling()->loginAs()->postJson($this->planUrl(), [
'account_short' => '测试账户',
'company_plan' => '不存在的规划',
])->assertUnprocessable()->assertJsonPath('message', '请选择现有公司规划。');
$this->withExceptionHandling()->loginAs()->postJson($this->keepUrl(), [
'account_short' => '测试账户',
'account_should_keep' => '可能',
])->assertUnprocessable()->assertJsonValidationErrors('account_should_keep');
}
public function test_invalid_status_or_account_is_rejected(): void
{
$this->withExceptionHandling()->loginAs()->postJson($this->statusUrl(), [
'account_short' => '测试账户',
'status' => 'unknown',
])->assertUnprocessable()->assertJsonValidationErrors('status');
$this->withExceptionHandling()->loginAs()->postJson($this->statusUrl(), [
'account_short' => '不存在的账户',
'status' => 'limited',
])->assertUnprocessable()->assertJsonPath('message', '账户简称不存在,请刷新账户总表后重试。');
$this->assertDatabaseCount('fin_account_statuses', 0, 'business_mirror');
}
public function test_user_without_finance_editor_role_cannot_change_account_status(): void
{
$viewer = user_model_class()::create([
'name' => '只读测试用户',
'email' => 'ledger-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->pageUrl())
->assertOk()
->assertSee('data-ledger-edit-mode-toggle', false)
->assertSee('当前账号没有财务台账编辑权限')
->assertDontSee('data-account-status data-account-short', false)
->assertDontSee('data-account-type data-account-short', false);
$this->withExceptionHandling()->loginAs($viewer)->postJson($this->statusUrl(), [
'account_short' => '测试账户',
'status' => 'limited',
])->assertForbidden();
$this->withExceptionHandling()->loginAs($viewer)->postJson($this->planUrl(), [
'account_short' => '测试账户',
'company_plan' => '保留',
])->assertForbidden();
$this->withExceptionHandling()->loginAs($viewer)->postJson($this->keepUrl(), [
'account_short' => '测试账户',
'account_should_keep' => '否',
])->assertForbidden();
$this->assertDatabaseCount('fin_account_statuses', 0, 'business_mirror');
}
}