CaiWuXiTong/tests/Unit/EcommerceFinance/StoreAccountMirrorRepositoryTest.php
renshen 69f3d9228f 店铺账号密码:授权状态 / 店铺状态筛选改成可搜索多选
复用已有的 CaiWuMultiSelect 组件(按钮 + 复选面板 + 全选/清空),勾选结果提交为
authorization_status[] / store_status[],多个取值取并集;一个都不勾=全部。

- 目录表的筛选控件在 query 表单外(靠 form 属性关联),给多选组件补了 formId 选项,
  生成的隐藏 input 带上 form,保证能随查询表单提交。
- pageFilters 支持数组筛选值(去重、最多 50 个);仓库侧筛选统一按列表处理,
  单选(旧链接)和多选都兼容。
2026-10-08 13:48:51 +08:00

177 lines
9.0 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\Unit\EcommerceFinance;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\EcommerceFinance\Repositories\GenericBusinessMirrorRepository;
use Modules\EcommerceFinance\Repositories\StoreAccountMirrorRepository;
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
use Tests\TestCase;
class StoreAccountMirrorRepositoryTest extends TestCase
{
private StoreAccountMirrorRepository $repository;
protected function setUp(): void
{
parent::setUp();
config([
'database.connections.business_mirror' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'upstream_mirrors.connection' => 'business_mirror',
'upstream_mirrors.datasets' => [
StoreAccountMirrorRepository::DATASET => [
'source_key' => 'database_4',
'schema' => 'external_store_accounts',
'object' => 'accounts_v1',
'target' => 'store_accounts',
'keys' => ['id'],
// 模拟 business-mirror:follow-upstream-columns 记录下来的跟随字段。
'followed_columns' => ['platform'],
],
],
]);
DB::purge('business_mirror');
Schema::connection('business_mirror')->create('business_mirror_table_states', function (Blueprint $table): void {
$table->string('dataset_key')->primary();
$table->dateTime('initial_completed_at')->nullable();
});
Schema::connection('business_mirror')->create('store_accounts', function (Blueprint $table): void {
$table->string('id')->primary();
foreach (['storeName', 'operationOwner', 'operationDepartmentHead', 'operationDirector', 'profitCenter', 'accountType', 'account', 'boundPhone', 'verificationContact', 'accountGroupName', 'createdAt', 'updatedAt'] as $column) {
$table->string($column)->nullable();
}
$table->boolean('passwordConfigured')->nullable();
// 自动跟随上游补进来的字段。
$table->string('platform')->nullable();
});
// 授权状态 / 店铺状态来自这两张镜像表(按店铺名关联)。
Schema::connection('business_mirror')->create('ops_fys_shop_info', function (Blueprint $table): void {
$table->integer('Id');
$table->string('erpShopName')->nullable();
$table->integer('shopState')->nullable();
});
Schema::connection('business_mirror')->create('ops_jst_shop_info', function (Blueprint $table): void {
$table->integer('Id');
$table->string('shop_name')->nullable();
$table->dateTime('session_expired')->nullable();
});
DB::connection('business_mirror')->table('business_mirror_table_states')->insert([
'dataset_key' => StoreAccountMirrorRepository::DATASET,
'initial_completed_at' => '2026-09-04 10:00:00',
]);
$this->repository = new StoreAccountMirrorRepository(
new BusinessMirrorDatasetRegistry(),
new GenericBusinessMirrorRepository(app('db')),
);
}
public function test_it_maps_account_type_codes_to_business_labels(): void
{
foreach (['MAIN' => '主账号', 'SUB' => '子账号', '/' => null] as $type => $expected) {
DB::connection('business_mirror')->table('store_accounts')->insert([
'id' => 'account-' . md5($type),
'storeName' => ['MAIN' => 'B店铺', 'SUB' => 'A店铺', '/' => 'C店铺'][$type],
'accountType' => $type,
'account' => 'test-account',
'passwordConfigured' => $type === 'MAIN' ? true : ($type === 'SUB' ? false : null),
]);
}
$rows = collect($this->repository->paginate(1, 50)['data'])->keyBy('id');
$this->assertSame('主账号', $rows['account-' . md5('MAIN')]['account_type']);
$this->assertSame('子账号', $rows['account-' . md5('SUB')]['account_type']);
$this->assertNull($rows['account-' . md5('/')]['account_type']);
$this->assertTrue($rows['account-' . md5('MAIN')]['password_configured']);
$this->assertFalse($rows['account-' . md5('SUB')]['password_configured']);
$this->assertNull($rows['account-' . md5('/')]['password_configured']);
$sorted = $this->repository->paginate(1, 50, ['_sort' => 'store_name', '_direction' => 'asc']);
$this->assertSame(['A店铺', 'B店铺', 'C店铺'], array_column($sorted['data'], 'store_name'));
}
public function test_it_exposes_followed_upstream_columns_to_the_page(): void
{
DB::connection('business_mirror')->table('store_accounts')->insert([
'id' => 'account-followed',
'storeName' => 'A店铺',
'account' => 'acct-A',
'platform' => '拼多多',
]);
$this->assertSame(['platform'], $this->repository->followedColumns());
$this->assertSame([
['name' => 'store_name', 'label' => '店铺名称'],
['name' => 'platform', 'label' => 'platform', 'followed' => true],
], $this->repository->withFollowedFields([['name' => 'store_name', 'label' => '店铺名称']]));
$rows = collect($this->repository->paginate(1, 10)['data'])->keyBy('id');
$this->assertSame('拼多多', $rows['account-followed']['platform']);
}
public function test_it_attaches_authorization_and_store_status_and_filters_them(): void
{
$db = DB::connection('business_mirror');
foreach (['A店铺' => '主账号', 'B店铺' => '主账号', 'C店铺' => '子账号', 'D店铺' => '子账号'] as $store => $type) {
$db->table('store_accounts')->insert([
'id' => 'account-' . md5($store),
'storeName' => $store,
'accountType' => $type === '主账号' ? 'MAIN' : 'SUB',
'account' => 'acct-' . $store,
]);
}
// 店铺档案:A 正常、B 已关闭;聚水潭授权:A 未过期、B 已过期、C 无授权时间,
// D 两条记录都没有。
$db->table('ops_fys_shop_info')->insert([
['Id' => 1, 'erpShopName' => 'A店铺', 'shopState' => 0],
['Id' => 2, 'erpShopName' => 'B店铺', 'shopState' => 6],
]);
$db->table('ops_jst_shop_info')->insert([
['Id' => 1, 'shop_name' => 'A店铺', 'session_expired' => now()->addYear()->toDateTimeString()],
['Id' => 2, 'shop_name' => 'B店铺', 'session_expired' => now()->subDay()->toDateTimeString()],
['Id' => 3, 'shop_name' => 'C店铺', 'session_expired' => null],
]);
$rows = collect($this->repository->paginate(1, 50)['data'])->keyBy('store_name');
$this->assertSame('已授权', $rows['A店铺']['authorization_status']);
$this->assertSame('正常', $rows['A店铺']['store_status']);
$this->assertSame('已过期', $rows['B店铺']['authorization_status']);
$this->assertSame('已关闭', $rows['B店铺']['store_status']);
$this->assertSame('未授权', $rows['C店铺']['authorization_status']);
$this->assertSame('', $rows['C店铺']['store_status']);
$this->assertSame('', $rows['D店铺']['authorization_status']);
$this->assertSame('', $rows['D店铺']['store_status']);
$authorized = $this->repository->paginate(1, 50, ['authorization_status' => '已授权', 'store_status' => '正常']);
$this->assertSame(1, $authorized['total']);
$this->assertSame(['A店铺'], array_column($authorized['data'], 'store_name'));
$missing = $this->repository->paginate(1, 50, ['authorization_status' => '未授权']);
$this->assertSame(['C店铺'], array_column($missing['data'], 'store_name'));
// 多选:勾选多个状态时取并集(正常 + 已关闭)。
$multi = $this->repository->paginate(1, 50, ['store_status' => ['正常', '已关闭']]);
$this->assertSame(['A店铺', 'B店铺'], array_column($multi['data'], 'store_name'));
$multiAuth = $this->repository->paginate(1, 50, ['authorization_status' => ['已授权', '未授权']]);
$multiAuthNames = array_column($multiAuth['data'], 'store_name');
sort($multiAuthNames);
$this->assertSame(['A店铺', 'C店铺'], $multiAuthNames);
// 关联出来的列也能排序:正常 -> 已关闭 -> 无档案。
$sorted = $this->repository->paginate(1, 50, ['_sort' => 'store_status', '_direction' => 'asc']);
$this->assertSame(['A店铺', 'B店铺'], array_slice(array_column($sorted['data'], 'store_name'), 0, 2));
$sortedDesc = $this->repository->paginate(1, 50, ['_sort' => 'store_status', '_direction' => 'desc']);
$this->assertSame(['B店铺', 'A店铺'], array_slice(array_column($sortedDesc['data'], 'store_name'), 2));
}
}