['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '']]); 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(); }); $registry = new BusinessMirrorDatasetRegistry(); foreach ([SupplierManagementMirrorRepository::DATASET, ...array_values(SupplierManagementMirrorRepository::RELATED)] as $key) { Schema::connection('business_mirror')->create($registry->get($key)->targetTable(), function (Blueprint $table) use ($registry, $key): void { foreach ($registry->columnSelection($key) as $column) { if (strtolower($column) === 'id') $table->integer($column)->primary(); else $table->string($column)->nullable(); } }); } $this->repository = new SupplierManagementMirrorRepository($registry, new GenericBusinessMirrorRepository(app('db'))); } public function test_filters_treat_wildcards_literally_and_pages_are_stable(): void { $this->ready(SupplierManagementMirrorRepository::DATASET); $this->table('js_supplier_management')->insert([ ['Id' => 1, 'scmname' => 'A%_供应商', 'buyer' => '采购甲', 'coopersgn' => 1], ['Id' => 2, 'scmname' => 'A%_供应商', 'buyer' => '采购甲', 'coopersgn' => 1], ['Id' => 3, 'scmname' => 'A普通供应商', 'buyer' => '采购乙', 'coopersgn' => 2], ]); $filters = ['supplier_name' => '%_', 'buyer' => '采购甲', 'cooperation_status' => '1']; $this->assertSame(2, $this->repository->paginate($filters, 1, 1)['total']); $this->assertSame(2, $this->repository->paginate($filters, 2, 1)['rows'][0]->Id); $this->assertSame([1, 2], array_map(fn ($row) => $row->Id, iterator_to_array($this->repository->exportRows($filters)))); } public function test_right_hand_supplier_fields_survive_pagination_and_export(): void { $this->ready(SupplierManagementMirrorRepository::DATASET); $fields = ['handlePerson' => '测试经办人', 'paycyclesgn' => '月结', 'endTimeB' => '2026-12-31', 'finishTimeA' => '2026-10-01', 'undefined2' => '第三方', 'linkerprovience' => '江苏省', 'linkeradd' => '测试地址', 'craftType' => '板式', 'capacity' => '120', 'region' => '苏北', 'sindou' => '双日']; $this->table('js_supplier_management')->insert(['Id' => 9, 'scmname' => '完整资料测试'] + $fields); $page = $this->repository->paginate([], 1, 20); $export = iterator_to_array($this->repository->exportRows([])); foreach ($fields as $column => $value) { $this->assertSame($value, $page['rows'][0]->{$column}); $this->assertSame($value, $export[0]->{$column}); $this->assertArrayHasKey($column, SupplierManagementMirrorRepository::COLUMNS); } $columns = (new BusinessMirrorDatasetRegistry())->columnSelection(SupplierManagementMirrorRepository::DATASET); $this->assertCount(52, $columns); $this->assertSame([], array_values(array_diff(array_keys(SupplierManagementMirrorRepository::COLUMNS), $columns))); } public function test_related_mirror_indexes_can_be_built_from_the_50_character_source_fields(): void { $registry = new BusinessMirrorDatasetRegistry(); foreach (SupplierManagementMirrorRepository::RELATED as $key) { $dataset = $registry->get($key); foreach ($registry->columnSelection($key) as $position => $name) { DB::table('upstream_schema_columns')->insert([ 'source_key' => 'jiansun', 'schema_name' => 'dbo', 'object_name' => $dataset->sourceObject(), 'object_type' => 'VIEW', 'column_name' => $name, 'ordinal_position' => $position + 1, 'data_type' => strtolower($name) === 'id' ? 'int' : 'varchar', 'max_length' => 50, 'is_nullable' => true, 'synchronized_at' => now(), 'created_at' => now(), 'updated_at' => now(), ]); } (new BusinessMirrorSchemaManager())->ensure($dataset); $indexes = collect(Schema::connection('business_mirror')->getIndexes($dataset->targetTable())) ->pluck('columns')->all(); foreach ($dataset->indexDefinitions() as $columns) $this->assertContains($columns, $indexes); } } public function test_details_do_not_mix_suppliers_or_contract_signing_companies(): void { foreach (SupplierManagementMirrorRepository::RELATED as $key) $this->ready($key); $supplier = (object) ['scmname' => '甲供应商', 'tradebody' => '甲主体', 'company' => '签订公司甲']; $this->table('js_supplier_contracts')->insert([ ['id' => 1, 'tradebody' => '甲主体', 'company' => '签订公司甲', 'title' => '正确合同'], ['id' => 2, 'tradebody' => '甲主体', 'company' => '签订公司乙', 'title' => '其他公司合同'], ]); foreach (['js_supplier_contacts', 'js_supplier_payment_accounts'] as $table) { $this->table($table)->insert([['Id' => 1, 'scmname' => '甲供应商'], ['Id' => 2, 'scmname' => '乙供应商']]); } foreach (['contracts', 'contacts', 'payments'] as $tab) { $this->assertSame(1, $this->repository->details($supplier, $tab, 1, 20)['total']); } $supplier->company = ''; $this->assertSame(0, $this->repository->details($supplier, 'contracts', 1, 20)['total']); $supplier->scmname = ''; $this->assertSame(0, $this->repository->details($supplier, 'payments', 1, 20)['total']); $this->assertFalse($this->repository->details($supplier, 'logs', 1, 20)['ready']); } public function test_partial_initial_sync_is_not_presented_as_complete(): void { $this->table('js_supplier_management')->insert(['Id' => 1]); $this->assertFalse($this->repository->ready()); $this->assertSame([], $this->repository->signingOptions()); $this->assertNull($this->repository->signingSupplier(1)); $this->expectException(\RuntimeException::class); $this->repository->paginate([], 1, 20); } public function test_signing_accounts_use_the_account_field_and_keep_real_names_separate(): void { $this->ready(SupplierManagementMirrorRepository::DATASET); $this->table('js_supplier_management')->insert([ ['Id' => 7, 'scmname' => '测试供应商', 'scmcode' => 'T007', 'tradebody' => '测试供应商有限公司', 'accountbankno' => '13800138000', 'handlePerson' => '张经理'], ['Id' => 8, 'scmname' => '缺账号供应商', 'scmcode' => 'T008', 'tradebody' => '', 'accountbankno' => null, 'handlePerson' => '李经理'], ]); $options = collect($this->repository->signingOptions())->keyBy('id'); $this->assertSame('13800138000', $options[7]['account']); $this->assertSame('张经理', $options[7]['operator']); $this->assertSame('', $options[8]['account']); $this->assertSame('13800138000', $this->repository->signingSupplier(7)->accountbankno); $this->assertNull($this->repository->signingSupplier(999)); } public function test_supplier_lookup_uses_supplier_codes_for_local_supplements(): void { $this->ready(SupplierManagementMirrorRepository::DATASET); $this->table('js_supplier_management')->insert([ ['Id' => 9, 'scmcode' => 'N901', 'scmname' => '一泰'], ['Id' => 11, 'scmcode' => 'Y411', 'scmname' => '七彩'], ]); $rows = $this->repository->suppliersByCodes(['N901', 'Y411', 'UNKNOWN']); $this->assertSame([9, 11], array_map(static fn (object $row): int => (int) $row->Id, $rows)); $this->assertSame('一泰', $this->repository->supplierById(9)->scmname); $this->assertNull($this->repository->supplierById(999)); } public function test_supplier_lookup_by_exact_names_supports_portal_roster_mapping(): void { $this->ready(SupplierManagementMirrorRepository::DATASET); $this->table('js_supplier_management')->insert([ ['Id' => 9, 'scmcode' => 'N901', 'scmname' => '一泰'], ['Id' => 11, 'scmcode' => 'Y411', 'scmname' => '七彩'], ]); $rows = $this->repository->suppliersByNames(['一泰', '不存在']); $this->assertCount(1, $rows); $this->assertSame('N901', $rows[0]->scmcode); } private function ready(string $key): void { $this->table('business_mirror_table_states')->insert(['dataset_key' => $key, 'initial_completed_at' => '2026-10-11 00:00:00']); } private function table(string $name): \Illuminate\Database\Query\Builder { return DB::connection('business_mirror')->table($name); } }