956 lines
40 KiB
PHP
956 lines
40 KiB
PHP
<?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' => '保留',
|
|
'current_balance' => 321.45,
|
|
'blocked_amount' => 0,
|
|
'daily_available' => 321.45,
|
|
]);
|
|
}
|
|
|
|
private function pageUrl(): string
|
|
{
|
|
return route('business.pages.show', [
|
|
'company_id' => $this->company->id,
|
|
'section' => 'financial-operations',
|
|
'page' => 'ledger',
|
|
]);
|
|
}
|
|
|
|
private function unavailableBalancesUrl(): string
|
|
{
|
|
return route('business.financial-ledger.unavailable-balances', [
|
|
'company_id' => $this->company->id,
|
|
]);
|
|
}
|
|
|
|
private function accountTodoUrl(): string
|
|
{
|
|
return route('business.financial-ledger.accounts.todo', [
|
|
'company_id' => $this->company->id,
|
|
]);
|
|
}
|
|
|
|
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,
|
|
]);
|
|
}
|
|
|
|
private function createAccountUrl(): string
|
|
{
|
|
return route('business.financial-ledger.accounts.store', [
|
|
'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('name="accounts_balance"', false)
|
|
->assertSee('0-5万')
|
|
->assertSee('5-20万')
|
|
->assertSee('20万以上')
|
|
->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('data-ledger-header-field="account_short"', false)
|
|
->assertSee('data-ledger-header-field="account_type"', false)
|
|
->assertSee('data-ledger-header-field="account_status"', false)
|
|
->assertSee('data-ledger-header-field="company_plan"', false)
|
|
->assertSee('data-ledger-header-field="account_should_keep"', false)
|
|
->assertSee('data-ledger-header-details', false)
|
|
->assertSee('aria-label="账户状态排序和筛选"', 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('data-ledger-page-select', false)
|
|
->assertSee('data-ledger-pagination="accounts"', false)
|
|
->assertSee('data-ledger-pagination="shops"', false)
|
|
->assertSee('data-ledger-pagination="flows"', false)
|
|
->assertSee('data-ledger-pagination="transactions"', false)
|
|
->assertSee('data-ledger-pagination="mapping"', 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('data-ledger-add-company', false)
|
|
->assertSee('data-ledger-company-dialog', false)
|
|
->assertSee('新增公司/账户')
|
|
->assertSee('name="company_name"', false)
|
|
->assertSee('name="company_register_place"', false)
|
|
->assertSee('name="company_business_type"', false)
|
|
->assertSee('name="company_tax_type"', false)
|
|
->assertSee('name="company_status"', false)
|
|
->assertSee('name="company_basic_bank"', false)
|
|
->assertSee('name="company_basic_account_last4"', false)
|
|
->assertSee('name="company_remark"', false)
|
|
->assertSee('name="opening_balance"', false)
|
|
->assertSee('id="ledger-company-options"', false)
|
|
->assertSee('aria-checked="false"', false)
|
|
->assertSee('ledger-account-editor', false)
|
|
->assertSee('data-account-edit-display', false)
|
|
->assertSee('列设置')
|
|
->assertSee('拖动字段可调整列顺序')
|
|
->assertSee('拖动表头右侧边界可调整列宽')
|
|
->assertSee('恢复默认')
|
|
->assertSee('可用金额合计')
|
|
->assertSee('不可用金额合计')
|
|
->assertSee('可用金额合计(万元)')
|
|
->assertSee('href="' . $this->unavailableBalancesUrl() . '"', false)
|
|
->assertSee('查看账户异常待办')
|
|
->assertSee('正常计可用,异常计不可用')
|
|
->assertSee('data-ledger-header-field="current_balance"', false)
|
|
->assertSee('data-ledger-header-field="daily_available"', false)
|
|
->assertSee('data-ledger-header-field="blocked_amount"', false)
|
|
->assertSee('data-ledger-summary-available', false)
|
|
->assertSee('data-account-current-balance="321.45"', false)
|
|
->assertSee('data-account-available-amount', false)
|
|
->assertSee('data-account-blocked-amount', false)
|
|
->assertSee('未填写')
|
|
->assertDontSee('data-account-filter-state', false)
|
|
->assertSee('value="normal" selected', false);
|
|
}
|
|
|
|
public function test_account_balance_filter_uses_non_overlapping_ranges(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fin_accounts')->insert([
|
|
['company_name' => '余额筛选公司', 'account_short' => '余额-负数', 'current_balance' => -1],
|
|
['company_name' => '余额筛选公司', 'account_short' => '余额-0', 'current_balance' => 0],
|
|
['company_name' => '余额筛选公司', 'account_short' => '余额-49999', 'current_balance' => 49999.99],
|
|
['company_name' => '余额筛选公司', 'account_short' => '余额-50000', 'current_balance' => 50000],
|
|
['company_name' => '余额筛选公司', 'account_short' => '余额-199999', 'current_balance' => 199999.99],
|
|
['company_name' => '余额筛选公司', 'account_short' => '余额-200000', 'current_balance' => 200000],
|
|
]);
|
|
|
|
$this->loginAs()->get(route('business.pages.show', [
|
|
'company_id' => $this->company->id,
|
|
'section' => 'financial-operations',
|
|
'page' => 'ledger',
|
|
'accounts_balance' => '0-5',
|
|
]))
|
|
->assertOk()
|
|
->assertSee('data-account-short="余额-0"', false)
|
|
->assertSee('data-account-short="余额-49999"', false)
|
|
->assertDontSee('data-account-short="余额-负数"', false)
|
|
->assertDontSee('data-account-short="余额-50000"', false)
|
|
->assertSee('value="0-5" selected', false);
|
|
|
|
$this->loginAs()->get(route('business.pages.show', [
|
|
'company_id' => $this->company->id,
|
|
'section' => 'financial-operations',
|
|
'page' => 'ledger',
|
|
'accounts_balance' => '5-20',
|
|
]))
|
|
->assertOk()
|
|
->assertSee('data-account-short="余额-50000"', false)
|
|
->assertSee('data-account-short="余额-199999"', false)
|
|
->assertDontSee('data-account-short="余额-49999"', false)
|
|
->assertDontSee('data-account-short="余额-200000"', false);
|
|
|
|
$this->loginAs()->get(route('business.pages.show', [
|
|
'company_id' => $this->company->id,
|
|
'section' => 'financial-operations',
|
|
'page' => 'ledger',
|
|
'accounts_balance' => '20-plus',
|
|
]))
|
|
->assertOk()
|
|
->assertSee('data-account-short="余额-200000"', false)
|
|
->assertDontSee('data-account-short="余额-199999"', false);
|
|
}
|
|
|
|
public function test_account_table_monetary_columns_are_displayed_in_ten_thousands(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fin_accounts')
|
|
->where('account_short', '测试账户')
|
|
->update([
|
|
'current_balance' => 123456.78,
|
|
'daily_available' => 120000,
|
|
'blocked_amount' => 3456.78,
|
|
'single_limit' => '200000/10000',
|
|
'daily_limit' => 300000,
|
|
'monthly_limit' => 400000,
|
|
'yearly_limit' => 500000,
|
|
'raise_target' => 50000,
|
|
]);
|
|
|
|
$this->loginAs()->get($this->pageUrl())
|
|
->assertOk()
|
|
->assertSee('当前余额(万元)')
|
|
->assertSee('单笔限额(万元)')
|
|
->assertSee('title="123,456.78 元"', false)
|
|
->assertSee('>12.35</td>', false)
|
|
->assertSee('>12.00</td>', false)
|
|
->assertSee('>0.35</td>', false)
|
|
->assertSee('>20.00 / 1.00</td>', false)
|
|
->assertSee('>5.00</td>', false)
|
|
->assertSee('<td class="center" title="200000/10000">20.00 / 1.00</td>', false)
|
|
->assertSee('<td class="center" title="300,000.00 元">30.00</td>', false)
|
|
->assertSee('<td class="center" title="400,000.00 元">40.00</td>', false)
|
|
->assertSee('<td class="center" title="500,000.00 元">50.00</td>', false);
|
|
}
|
|
|
|
public function test_unavailable_balance_tasks_page_is_separate_and_only_lists_blocked_accounts(): void
|
|
{
|
|
$connection = DB::connection('business_mirror');
|
|
$accounts = [
|
|
[
|
|
'company_name' => '待办测试公司',
|
|
'account_short' => '待办测试账户',
|
|
'account_no' => '6222000000000099',
|
|
'account_type' => '公户',
|
|
'bank_name' => '待办测试银行',
|
|
'bank_city_branch' => '上海 / 待办测试支行',
|
|
'current_balance' => 100,
|
|
'blocked_amount' => 100,
|
|
'daily_available' => 0,
|
|
'owner' => '待办负责人',
|
|
'next_action' => '核实冻结原因',
|
|
'remark' => '独立待办备注',
|
|
],
|
|
[
|
|
'company_name' => '零金额测试公司',
|
|
'account_short' => '零金额测试账户',
|
|
'current_balance' => 100,
|
|
'blocked_amount' => 0,
|
|
'daily_available' => 100,
|
|
],
|
|
[
|
|
'company_name' => '正常状态测试公司',
|
|
'account_short' => '正常状态测试账户',
|
|
'current_balance' => 100,
|
|
'blocked_amount' => 0,
|
|
'daily_available' => 100,
|
|
],
|
|
[
|
|
'company_name' => '待办测试公司二',
|
|
'account_short' => '待办测试账户二',
|
|
'account_no' => '6222000000000100',
|
|
'account_type' => '个人卡',
|
|
'bank_name' => '待办测试银行二',
|
|
'bank_city_branch' => '杭州 / 待办测试支行',
|
|
'current_balance' => 250,
|
|
'blocked_amount' => 250,
|
|
'daily_available' => 0,
|
|
],
|
|
];
|
|
foreach ($accounts as $account) {
|
|
$connection->table('fin_accounts')->insert($account);
|
|
}
|
|
$connection->table('fin_account_statuses')->insert([
|
|
[
|
|
'account_short' => '待办测试账户',
|
|
'status' => 'limited',
|
|
'updated_by' => 'Test User',
|
|
],
|
|
[
|
|
'account_short' => '正常状态测试账户',
|
|
'status' => 'normal',
|
|
'updated_by' => 'Test User',
|
|
],
|
|
[
|
|
'account_short' => '待办测试账户二',
|
|
'status' => 'online_banking_abnormal',
|
|
'updated_by' => 'Test User',
|
|
],
|
|
]);
|
|
$connection->table('fin_account_type_overrides')->insert([
|
|
'account_short' => '待办测试账户',
|
|
'account_type' => '网商银行',
|
|
'updated_by' => 'Test User',
|
|
]);
|
|
|
|
$this->loginAs()->get($this->unavailableBalancesUrl())
|
|
->assertOk()
|
|
->assertSee('账户异常待办')
|
|
->assertSee('不与其他页面的待办事项合并')
|
|
->assertSee('待办测试公司')
|
|
->assertSee('data-pending-account="待办测试账户"', false)
|
|
->assertSee('不可用金额合计')
|
|
->assertSee('350.00')
|
|
->assertSee('限额')
|
|
->assertSee('网商银行')
|
|
->assertSee('6222000000000099')
|
|
->assertSee('待办测试银行')
|
|
->assertSee('上海 / 待办测试支行')
|
|
->assertSee('异常原因')
|
|
->assertSee('办理方式')
|
|
->assertSee('当前进度')
|
|
->assertSee('是否完成')
|
|
->assertSee('<th data-pending-column-key="current_balance">当前余额</th>', false)
|
|
->assertSee('data-pending-current-balance="100.00"', false)
|
|
->assertSee('data-pending-current-balance-total="350.00"', false)
|
|
->assertSee('当前筛选合计')
|
|
->assertSee('name="pending_short"', false)
|
|
->assertSee('name="pending_type"', false)
|
|
->assertSee('name="pending_status"', false)
|
|
->assertSee('name="pending_reason"', false)
|
|
->assertSee('name="pending_method"', false)
|
|
->assertSee('name="pending_owner"', false)
|
|
->assertSee('按开始时间排序')
|
|
->assertSee('按完成时间排序')
|
|
->assertDontSee('name="pending_q"', false)
|
|
->assertSee('data-pending-tbody', false)
|
|
->assertSee('data-pending-pagination', false)
|
|
->assertSee('data-pending-table', false)
|
|
->assertSee('拖动表头右侧边界可调整列宽')
|
|
->assertSee('const pendingColumnDefaultWidths = Object.freeze({', false)
|
|
->assertSee('company_name: 170', false)
|
|
->assertSee('completion_status: 105', false)
|
|
->assertSee('ledger-page-box', false)
|
|
->assertSee('1 / 1', false)
|
|
->assertSee('data-pending-account="待办测试账户二"', false)
|
|
->assertDontSee('data-pending-account="正常状态测试账户"', false)
|
|
->assertDontSee('data-pending-account="零金额测试账户"', false);
|
|
|
|
$this->loginAs()->post($this->accountTodoUrl(), [
|
|
'account_short' => '待办测试账户',
|
|
'abnormal_reason' => '账户冻结',
|
|
'handling_method' => 'online',
|
|
'owner_name' => '待办负责人',
|
|
'started_at' => '2026-10-21T09:00',
|
|
'completed_at' => '2026-10-21T11:30',
|
|
'current_progress' => '处理中',
|
|
'completion_status' => 'in_progress',
|
|
])->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('fin_account_todos', [
|
|
'account_short' => '待办测试账户',
|
|
'abnormal_reason' => '账户冻结',
|
|
'handling_method' => 'online',
|
|
'owner_name' => '待办负责人',
|
|
'current_progress' => '处理中',
|
|
'completion_status' => 'in_progress',
|
|
'updated_by' => 'Test User',
|
|
], 'business_mirror');
|
|
|
|
$connection->table('fin_account_todos')->insert([
|
|
'account_short' => '待办测试账户二',
|
|
'abnormal_reason' => '网银证书过期',
|
|
'handling_method' => 'offline',
|
|
'owner_name' => '其他负责人',
|
|
'started_at' => '2026-10-21 10:00:00',
|
|
'current_progress' => '待联系银行',
|
|
'completion_status' => 'not_started',
|
|
'updated_by' => 'Test User',
|
|
]);
|
|
|
|
$this->loginAs()->get($this->unavailableBalancesUrl())
|
|
->assertOk()
|
|
->assertSee('账户冻结')
|
|
->assertSee('待办负责人')
|
|
->assertSee('处理中')
|
|
->assertSee('进行中');
|
|
|
|
$filteredUrl = $this->unavailableBalancesUrl() . '?' . http_build_query([
|
|
'pending_short' => '待办测试账户',
|
|
'pending_type' => '网商银行',
|
|
'pending_status' => 'limited',
|
|
'pending_reason' => '账户冻结',
|
|
'pending_method' => 'online',
|
|
'pending_owner' => '待办负责人',
|
|
]);
|
|
$this->loginAs()->get($filteredUrl)
|
|
->assertOk()
|
|
->assertSee('data-pending-account="待办测试账户"', false)
|
|
->assertSee('data-pending-current-balance-total="100.00"', false)
|
|
->assertDontSee('data-pending-account="待办测试账户二"', false);
|
|
|
|
$connection->table('fin_accounts')
|
|
->where('account_short', '待办测试账户')
|
|
->update(['current_balance' => 180]);
|
|
$this->loginAs()->get($filteredUrl)
|
|
->assertOk()
|
|
->assertSee('data-pending-current-balance="180.00"', false)
|
|
->assertSee('data-pending-current-balance-total="180.00"', false);
|
|
|
|
$sortResponse = $this->loginAs()->get(
|
|
$this->unavailableBalancesUrl() . '?pending_sort=started_at&pending_direction=desc'
|
|
)->assertOk()->assertSee('aria-sort="descending"', false);
|
|
preg_match_all('/data-pending-account="([^"]+)"/u', $sortResponse->getContent(), $sortedAccounts);
|
|
$this->assertSame(['待办测试账户二', '待办测试账户'], array_values(array_intersect(
|
|
$sortedAccounts[1],
|
|
['待办测试账户', '待办测试账户二'],
|
|
)));
|
|
|
|
$this->loginAs()->post($this->accountTodoUrl(), [
|
|
'account_short' => '待办测试账户',
|
|
'abnormal_reason' => '账户冻结',
|
|
'handling_method' => 'online',
|
|
'owner_name' => '待办负责人',
|
|
'started_at' => '2026-10-21T09:00',
|
|
'completed_at' => '2026-10-21T12:00',
|
|
'current_progress' => '已处理',
|
|
'completion_status' => 'completed',
|
|
])->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('fin_account_statuses', [
|
|
'account_short' => '待办测试账户',
|
|
'status' => 'normal',
|
|
], 'business_mirror');
|
|
$this->assertDatabaseHas('fin_accounts', [
|
|
'account_short' => '待办测试账户',
|
|
'current_balance' => 180,
|
|
'daily_available' => 180,
|
|
'blocked_amount' => 0,
|
|
], 'business_mirror');
|
|
|
|
$this->loginAs()->get($this->unavailableBalancesUrl())
|
|
->assertOk()
|
|
->assertDontSee('data-pending-account="待办测试账户"', 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('data-ledger-page-select', 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_type_change_derives_last4_and_alipay_uses_slash(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fin_accounts')
|
|
->where('account_short', '测试账户')
|
|
->update([
|
|
'account_no' => '6222-1234 5678',
|
|
'account_last4' => '0000',
|
|
]);
|
|
|
|
$this->loginAs()->postJson($this->typeUrl(), [
|
|
'account_short' => '测试账户',
|
|
'account_type' => '网商银行',
|
|
])
|
|
->assertOk()
|
|
->assertJsonPath('account_last4', '5678');
|
|
$this->assertDatabaseHas('fin_accounts', [
|
|
'account_short' => '测试账户',
|
|
'account_last4' => '5678',
|
|
], 'business_mirror');
|
|
|
|
$this->loginAs()->postJson($this->typeUrl(), [
|
|
'account_short' => '测试账户',
|
|
'account_type' => '支付宝',
|
|
])
|
|
->assertOk()
|
|
->assertJsonPath('account_last4', '/');
|
|
$this->assertDatabaseHas('fin_accounts', [
|
|
'account_short' => '测试账户',
|
|
'account_last4' => '/',
|
|
], 'business_mirror');
|
|
|
|
$this->loginAs()->get($this->pageUrl())
|
|
->assertOk()
|
|
->assertSee('<td class="center" data-account-last4>/</td>', false);
|
|
}
|
|
|
|
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->assertDatabaseHas('fin_accounts', [
|
|
'account_short' => '测试账户',
|
|
'current_balance' => 321.45,
|
|
'daily_available' => 0,
|
|
'blocked_amount' => 321.45,
|
|
], 'business_mirror');
|
|
|
|
$this->loginAs()->postJson($this->statusUrl(), [
|
|
'account_short' => '测试账户',
|
|
'status' => 'normal',
|
|
])->assertOk()->assertJsonPath('label', '正常');
|
|
$this->assertDatabaseHas('fin_accounts', [
|
|
'account_short' => '测试账户',
|
|
'current_balance' => 321.45,
|
|
'daily_available' => 321.45,
|
|
'blocked_amount' => 0,
|
|
], 'business_mirror');
|
|
|
|
$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_editor_can_create_new_company_and_account_with_opening_balance(): void
|
|
{
|
|
$this->loginAs()->postJson($this->createAccountUrl(), [
|
|
'company_name' => '新设财务公司',
|
|
'company_register_place' => '上海市浦东新区',
|
|
'company_business_type' => '有限责任公司',
|
|
'company_tax_type' => '一般纳税人',
|
|
'company_status' => '正常',
|
|
'company_basic_bank' => '中国农业银行上海浦东支行',
|
|
'company_basic_account_last4' => '1234',
|
|
'company_remark' => '新设公司财务备注',
|
|
'account_short' => '新设财务公司农行',
|
|
'account_type' => '公户',
|
|
'status' => 'limited',
|
|
'region' => '上海',
|
|
'account_no' => '6222000000001234',
|
|
'bank_name' => '中国农业银行',
|
|
'bank_city_branch' => '上海浦东支行',
|
|
'company_plan' => '待注销',
|
|
'account_should_keep' => '否',
|
|
'opening_date' => '2026-10-20',
|
|
'opening_balance' => '12345.67',
|
|
])
|
|
->assertCreated()
|
|
->assertJsonPath('account.company_name', '新设财务公司')
|
|
->assertJsonPath('account.account_short', '新设财务公司农行')
|
|
->assertJsonPath('account.company_created', true)
|
|
->assertJsonPath('account.status', 'limited')
|
|
->assertJsonPath('message', '已新增公司并建立首个账户。');
|
|
|
|
$this->assertDatabaseHas('fin_companies', [
|
|
'name' => '新设财务公司',
|
|
'register_place' => '上海市浦东新区',
|
|
'business_type' => '有限责任公司',
|
|
'tax_type' => '一般纳税人',
|
|
'status' => '正常',
|
|
'basic_bank' => '中国农业银行上海浦东支行',
|
|
'basic_account_last4' => '1234',
|
|
'remark' => '新设公司财务备注',
|
|
], 'business_mirror');
|
|
$this->assertDatabaseHas('fin_accounts', [
|
|
'company_name' => '新设财务公司',
|
|
'account_short' => '新设财务公司农行',
|
|
'account_type' => '公户',
|
|
'region' => '上海',
|
|
'account_no' => '6222000000001234',
|
|
'account_last4' => '1234',
|
|
'company_plan' => '待注销',
|
|
'account_should_keep' => '否',
|
|
'current_balance' => 12345.67,
|
|
'daily_available' => 0,
|
|
'blocked_amount' => 12345.67,
|
|
], 'business_mirror');
|
|
$this->assertDatabaseHas('fin_account_statuses', [
|
|
'account_short' => '新设财务公司农行',
|
|
'status' => 'limited',
|
|
'updated_by' => 'Test User',
|
|
], 'business_mirror');
|
|
$this->assertDatabaseHas('fin_account_opening', [
|
|
'account_short' => '新设财务公司农行',
|
|
'opening_date' => '2026-10-20',
|
|
'opening_balance' => 12345.67,
|
|
], 'business_mirror');
|
|
$this->assertDatabaseHas('fin_daily_flows', [
|
|
'company_name' => '新设财务公司',
|
|
'account_short' => '新设财务公司农行',
|
|
'flow_date' => '2026-10-20',
|
|
'opening_balance' => 12345.67,
|
|
'closing_balance' => 12345.67,
|
|
], 'business_mirror');
|
|
|
|
$this->loginAs()->get($this->pageUrl() . '?accounts_short=' . urlencode('新设财务公司农行'))
|
|
->assertOk()
|
|
->assertSee('新设财务公司')
|
|
->assertSee('新设财务公司农行')
|
|
->assertSee('>1.23</td>', false);
|
|
|
|
$this->withExceptionHandling()->loginAs()->postJson($this->createAccountUrl(), [
|
|
'company_name' => '另一个公司',
|
|
'account_short' => '新设财务公司农行',
|
|
'status' => 'normal',
|
|
'opening_date' => '2026-10-20',
|
|
'opening_balance' => 0,
|
|
])->assertUnprocessable()->assertJsonValidationErrors('account_short');
|
|
|
|
$this->assertDatabaseCount('fin_companies', 1, 'business_mirror');
|
|
}
|
|
|
|
public function test_existing_company_profile_can_be_updated_with_a_new_account(): void
|
|
{
|
|
DB::connection('business_mirror')->table('fin_companies')->insert([
|
|
'name' => '已有资料公司',
|
|
'register_place' => '江苏省苏州市',
|
|
'business_type' => '个体工商户',
|
|
'tax_type' => '小规模纳税人',
|
|
'status' => '存续',
|
|
'remark' => '原公司备注',
|
|
]);
|
|
|
|
$this->loginAs()->postJson($this->createAccountUrl(), [
|
|
'company_name' => '已有资料公司',
|
|
'company_business_type' => '有限责任公司',
|
|
'company_tax_type' => '一般纳税人',
|
|
'company_status' => '正常',
|
|
'company_basic_bank' => '中国工商银行苏州分行',
|
|
'company_basic_account_last4' => '8899',
|
|
'company_remark' => '更新后的公司备注',
|
|
'account_short' => '已有资料公司工行',
|
|
'account_type' => '公户',
|
|
'status' => 'normal',
|
|
'account_no' => '1102000000008899',
|
|
'opening_date' => '2026-10-20',
|
|
'opening_balance' => 0,
|
|
])
|
|
->assertCreated()
|
|
->assertJsonPath('account.company_created', false)
|
|
->assertJsonPath('account.company_updated', true)
|
|
->assertJsonPath('message', '已新增账户并更新公司资料。');
|
|
|
|
$this->assertDatabaseHas('fin_companies', [
|
|
'name' => '已有资料公司',
|
|
'register_place' => '江苏省苏州市',
|
|
'business_type' => '有限责任公司',
|
|
'tax_type' => '一般纳税人',
|
|
'status' => '正常',
|
|
'basic_bank' => '中国工商银行苏州分行',
|
|
'basic_account_last4' => '8899',
|
|
'remark' => '更新后的公司备注',
|
|
], 'business_mirror');
|
|
}
|
|
|
|
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)
|
|
->assertDontSee('class="ledger-btn ledger-add-company"', 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->withExceptionHandling()->loginAs($viewer)->postJson($this->createAccountUrl(), [
|
|
'company_name' => '无权限公司',
|
|
'account_short' => '无权限账户',
|
|
'status' => 'normal',
|
|
'opening_date' => '2026-10-20',
|
|
'opening_balance' => 0,
|
|
])->assertForbidden();
|
|
$this->withExceptionHandling()->loginAs($viewer)->post($this->accountTodoUrl(), [
|
|
'account_short' => '测试账户',
|
|
'current_progress' => '处理中',
|
|
])->assertForbidden();
|
|
|
|
$this->assertDatabaseCount('fin_account_statuses', 0, 'business_mirror');
|
|
$this->assertDatabaseCount('fin_account_todos', 0, 'business_mirror');
|
|
}
|
|
}
|