[ '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'], ], ], ]); 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(); }); // 授权状态 / 店铺状态来自这两张镜像表(按店铺名关联)。 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_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')); // 关联出来的列也能排序:正常 -> 已关闭 -> 无档案。 $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)); } }