CaiWuXiTong/tests/Feature/Business/FinanceLedgerHeaderControlsTest.php
92451 a8c2169134 调整财务台账店铺表头 (#629)
Co-authored-by: 92451 <924518135@qq.com>
Co-committed-by: 92451 <924518135@qq.com>
2026-10-26 18:43:44 +08:00

282 lines
11 KiB
PHP

<?php
namespace Tests\Feature\Business;
use App\Models\Auth\Permission;
use Illuminate\Support\Facades\DB;
use Tests\Feature\FeatureTestCase;
class FinanceLedgerHeaderControlsTest extends FeatureTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->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('/<details\b[^>]*data-ledger-header-details/', $html));
$this->assertSame(63, preg_match_all('/<span\b[^>]*data-ledger-header-label/', $html));
$this->assertSame(2, preg_match_all('/<select name="transactions_filter_value"/', $html));
$this->assertSame(1, preg_match_all('/<input\b[^>]*name="transactions_filter_value"[^>]*list="ledger-header-options-transactions-effective_account_short"/', $html));
$this->assertStringContainsString(
'<datalist id="ledger-header-options-transactions-effective_account_short">',
$html
);
$this->assertStringContainsString('<option value="账户甲"', $html);
$this->assertStringContainsString('<option value="2026-10-18"', $html);
$this->assertStringContainsString('data-transaction-column-storage-key', $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_shop_ledger_header_labels_and_column_order(): void
{
$html = $this->loginAs()->get($this->pageUrl())->assertOk()->getContent();
$panelStart = strpos($html, 'id="ledger-panel-shops"');
$theadStart = strpos($html, '<thead>', $panelStart);
$theadEnd = strpos($html, '</thead>', $theadStart);
$this->assertNotFalse($panelStart);
$this->assertNotFalse($theadStart);
$this->assertNotFalse($theadEnd);
$headerHtml = substr($html, $theadStart, $theadEnd - $theadStart);
$platformPosition = strpos($headerHtml, 'data-ledger-header-field="platform"');
$shopNamePosition = strpos($headerHtml, 'data-ledger-header-field="shop_name"');
$this->assertNotFalse($platformPosition);
$this->assertNotFalse($shopNamePosition);
$this->assertLessThan($shopNamePosition, $platformPosition);
$this->assertStringContainsString('data-ledger-header-label>平台</span>', $headerHtml);
$this->assertStringContainsString('data-ledger-header-label>ERP系统店铺名称</span>', $headerHtml);
$this->assertStringContainsString('data-ledger-header-label>店铺主体</span>', $headerHtml);
$this->assertStringNotContainsString('data-ledger-header-label>店铺名称</span>', $headerHtml);
$this->assertStringNotContainsString('data-ledger-header-label>所属公司</span>', $headerHtml);
}
public function test_transaction_account_filter_provides_typeahead_suggestions(): void
{
$html = $this->loginAs()->get($this->pageUrl())
->assertOk()
->assertSee('data-ledger-account-filter', false)
->assertSee('data-limit="60"', false)
->assertSee('id="txns-account"', false)
->assertSee('role="combobox"', false)
->assertSee('aria-autocomplete="list"', false)
->assertSee('aria-controls="txns-account-menu"', false)
->assertSee('aria-haspopup="listbox"', false)
->assertSee('data-ledger-account-filter-toggle', false)
->assertSee('data-ledger-account-filter-menu', false)
->assertSee('max-height:min(18rem, 50vh)', false)
->assertSee("input.addEventListener('input'", false)
->assertDontSee('id="txns-account" name="txns_account" list=', false)
->getContent();
$this->assertStringContainsString('<option value="账户甲"', $html);
$this->assertStringContainsString('<option value="账户乙"', $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('>乙公司</td>', false)
->assertDontSee('>甲公司</td>', 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('>天猫店铺</td>', false)
->assertDontSee('>拼多多店铺</td>', 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([
'transactions_filter_column' => 'effective_account_short',
'transactions_filter_value' => '乙',
]))
->assertOk()
->assertSee('乙笔流水')
->assertDontSee('甲笔流水');
$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('>提现</td>', false)
->assertDontSee('>报销</td>', 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));
}
}