['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => ''], 'upstream_mirrors.connection' => 'business_mirror', 'upstream_mirrors.datasets' => [BillOffsetMirrorRepository::DATASET => [ 'source_key' => 'operations_replica', 'schema' => 'rpt', 'object' => 'jst_originalBillInfo', 'target' => 'ops_jst_original_bill_info', 'keys' => ['Id'], ]], ]); DB::purge('business_mirror'); $schema = Schema::connection('business_mirror'); $schema->create('business_mirror_table_states', function (Blueprint $table): void { $table->string('dataset_key')->primary(); $table->dateTime('initial_completed_at')->nullable(); $table->string('status')->nullable(); $table->dateTime('last_succeeded_at')->nullable(); }); $schema->create('ops_jst_original_bill_info', function (Blueprint $table): void { $table->integer('Id'); $table->dateTime('fee_time')->nullable(); $table->string('fee_name')->nullable(); $table->string('inout_type')->nullable(); $table->string('so_id')->nullable(); $table->string('p_auto_id')->nullable(); $table->string('sku_id')->nullable(); $table->string('shop_sku_id')->nullable(); $table->string('shop_i_id')->nullable(); $table->decimal('amount', 18, 2)->nullable(); }); $schema->create('ops_jst_orders', function (Blueprint $table): void { $table->integer('o_id'); $table->string('so_id')->nullable(); $table->string('shop_name')->nullable(); $table->string('shop_id')->nullable(); }); $schema->create('ops_jst_order_item', function (Blueprint $table): void { $table->integer('o_id'); $table->string('sku_id')->nullable(); $table->string('i_id')->nullable(); $table->string('shop_sku_id')->nullable(); $table->string('shop_i_id')->nullable(); }); $this->repository = new BillOffsetMirrorRepository(new BusinessMirrorDatasetRegistry(), new GenericBusinessMirrorRepository(app('db'))); } public function test_it_filters_joins_orders_and_calculates_summary(): void { DB::connection('business_mirror')->table('business_mirror_table_states')->insert([ 'dataset_key' => BillOffsetMirrorRepository::DATASET, 'initial_completed_at' => '2026-09-08 09:00:00', 'status' => 'succeeded', 'last_succeeded_at' => '2026-09-08 09:00:00', ]); DB::connection('business_mirror')->table('ops_jst_original_bill_info')->insert([ ['Id' => 1, 'fee_time' => '2026-08-01 10:00:00', 'fee_name' => '500112冲减收入', 'inout_type' => '收入', 'so_id' => 'SO-1', 'sku_id' => 'SKU-1', 'amount' => -20], ['Id' => 2, 'fee_time' => '2026-08-02 10:00:00', 'fee_name' => '500112冲减收入', 'inout_type' => '收入', 'so_id' => 'SO-2', 'sku_id' => 'SKU-2', 'amount' => 18.25], ['Id' => 4, 'fee_time' => '2026-08-01 10:00:00', 'fee_name' => '订单收入', 'inout_type' => '收入', 'so_id' => 'SO-1', 'sku_id' => 'SKU-1', 'amount' => 100], ]); DB::connection('business_mirror')->table('ops_jst_orders')->insert([ ['o_id' => 1001, 'so_id' => 'SO-1', 'shop_name' => '测试店铺', 'shop_id' => 'SHOP-1'], ['o_id' => 1002, 'so_id' => 'SO-2', 'shop_name' => '其他店铺', 'shop_id' => 'SHOP-2'], ]); DB::connection('business_mirror')->table('ops_jst_order_item')->insert([ ['o_id' => 1001, 'sku_id' => 'SKU-1', 'i_id' => 'STYLE-1', 'shop_sku_id' => 'SP-1', 'shop_i_id' => 'SI-1'], ]); $result = $this->repository->paginate(['from' => '2026-08-01', 'to' => '2026-08-01', 'shop_name' => '测试店铺', 'sku_id' => 'SKU-1'], 1, 10); $this->assertSame(1, $result['total']); $this->assertSame('1001', (string) $result['data'][0]['internal_order_no']); $this->assertSame('测试店铺', $result['data'][0]['shop_name']); $this->assertSame('STYLE-1', $result['data'][0]['style_code']); $this->assertSame(-20.0, $result['summary']['amount']); $this->assertSame('succeeded', $result['sync']['status']); } public function test_it_rejects_unready_mirror(): void { $this->expectException(RuntimeException::class); $this->expectExceptionMessage('bill_offset_mirror_not_ready'); $this->repository->paginate([], 1, 10); } public function test_it_reads_bill_rows_when_order_mirror_tables_are_not_available(): void { $schema = Schema::connection('business_mirror'); $schema->dropIfExists('ops_jst_order_item'); $schema->dropIfExists('ops_jst_orders'); DB::connection('business_mirror')->table('business_mirror_table_states')->insert([ 'dataset_key' => BillOffsetMirrorRepository::DATASET, 'initial_completed_at' => '2026-09-08 09:00:00', 'status' => 'succeeded', 'last_succeeded_at' => '2026-09-08 09:00:00', ]); DB::connection('business_mirror')->table('ops_jst_original_bill_info')->insert([ 'Id' => 3, 'fee_time' => '2026-08-03 10:00:00', 'fee_name' => '500112冲减收入', 'inout_type' => '收入', 'so_id' => 'SO-3', 'sku_id' => 'SKU-3', 'amount' => 12.5, ]); $result = $this->repository->paginate([], 1, 10); $this->assertSame(1, $result['total']); $this->assertSame('SO-3', $result['data'][0]['internal_order_no']); $this->assertSame('SKU-3', $result['data'][0]['product_code']); $this->assertSame(12.5, $result['summary']['amount']); $this->assertSame(0, $this->repository->paginate(['shop_name' => '测试店铺'], 1, 10)['total']); } }