['driver'=>'sqlite','database'=>':memory:','prefix'=>''], 'upstream_mirrors.connection'=>'business_mirror']); DB::purge('business_mirror'); $definitions=[]; foreach ([InstallationDetailMirrorRepository::DATASET=>'fixture_install',InstallationDetailMirrorRepository::ITEM_DATASET=>'fixture_items'] as $key=>$table) { $definitions[$key]=['source_key'=>'jiansun','schema'=>'dbo','object'=>explode('.',$key)[2],'target'=>$table,'keys'=>['Id']]; } config(['upstream_mirrors.datasets'=>$definitions]); $schema=Schema::connection('business_mirror'); $schema->create('business_mirror_table_states',function(Blueprint $t){$t->string('dataset_key')->primary();$t->dateTime('initial_completed_at')->nullable();}); $schema->create('fixture_install',function(Blueprint $t){ $t->integer('Id'); foreach(['SourceGuid','OrderNum','ordernum_id','shop_name','SubmitTime','kfshTime','cwshTime','apistatus','kfsh','cwsh','BidStatus','costtaker','installComplete','Delete','installCompanyName','TypeDto'] as $c) $t->string($c)->nullable(); $t->integer('StatusId')->default(0); foreach(['installcost','settleAmount','acceptAmount'] as $c) $t->decimal($c,14,2)->default(0); }); $schema->create('fixture_items',function(Blueprint $t){$t->integer('Id');$t->string('guid');$t->string('shopproid');$t->string('Sourceno')->nullable();}); foreach(array_keys($definitions) as $key) DB::connection('business_mirror')->table('business_mirror_table_states')->insert(['dataset_key'=>$key,'initial_completed_at'=>'2026-08-01']); DB::connection('business_mirror')->table('fixture_install')->insert([ ['Id'=>1,'SourceGuid'=>'A','OrderNum'=>'OLD','shop_name'=>'旧店','SubmitTime'=>'2026-08-01','installcost'=>500], ['Id'=>2,'SourceGuid'=>'A','OrderNum'=>'NEW','shop_name'=>'测试店','SubmitTime'=>'2026-08-20 23:59:59','installcost'=>20], ['Id'=>3,'SourceGuid'=>'B','OrderNum'=>'OTHER','shop_name'=>'其他店','SubmitTime'=>'2026-08-20','installcost'=>30], ['Id'=>4,'SourceGuid'=>'C','OrderNum'=>'NEXT','shop_name'=>'测试店','SubmitTime'=>'2026-08-21','installcost'=>40], ]); DB::connection('business_mirror')->table('fixture_items')->insert([ ['Id'=>1,'guid'=>'A','shopproid'=>'PRODUCT-A'],['Id'=>2,'guid'=>'A','shopproid'=>'PRODUCT-A'], ]); $this->repository=new InstallationDetailMirrorRepository(new GenericBusinessMirrorRepository(app('db')),new BusinessMirrorDatasetRegistry()); } public function test_filters_apply_to_deduplicated_list_count_and_summary(): void { $filters=['shop_name'=>'测试店']; $page=$this->repository->paginate(2,1,$filters); $this->assertSame(2,$page['total']); $this->assertSame(2,$page['data'][0]['id']); $this->assertSame(60.0,$this->repository->summary($filters)['requested']); $filters['created_to']='2026-08-20'; $this->assertSame(1,$this->repository->paginate(1,50,$filters)['total']); $this->assertSame(20.0,$this->repository->summary($filters)['requested']); $this->assertSame(0,$this->repository->paginate(1,50,['shop_name'=>"' OR 1=1 --"])['total']); } public function test_product_filter_does_not_multiply_main_rows(): void { $filters=['product_id'=>'PRODUCT-A']; $this->assertSame(1,$this->repository->paginate(1,50,$filters)['total']); $this->assertSame(20.0,$this->repository->summary($filters)['requested']); $this->assertSame('NEW',$this->repository->details('A')['data'][0]['transaction_no']); $this->assertSame([],$this->repository->details('missing')['data']); } public function test_status_filters_and_child_limit_are_explicit(): void { DB::connection('business_mirror')->table('fixture_install')->where('Id',2)->update(['kfsh'=>'1','Delete'=>'0','StatusId'=>2]); $this->assertSame(1,$this->repository->paginate(1,50,['customer_review'=>'1','delete_status'=>'0','arranged_status'=>'1'])['total']); $rows=[];for($i=1;$i<=101;$i++)$rows[]=['Id'=>$i+10,'guid'=>'B','shopproid'=>'P'.$i]; DB::connection('business_mirror')->table('fixture_items')->insert($rows); $result=$this->repository->details('B'); $this->assertCount(100,$result['data']); $this->assertTrue($result['has_more']); } public function test_end_date_alone_is_valid_and_invalid_status_is_rejected(): void { request()->merge(['created_to'=>'2026-08-20']); $this->assertSame(['created_to'=>'2026-08-20'],InstallationDetailMirrorRepository::requestFilters()); request()->merge(['arranged_status'=>'unexpected']); $this->expectException(\Illuminate\Validation\ValidationException::class); InstallationDetailMirrorRepository::requestFilters(); } }