diff --git a/config/upstream_mirrors.php b/config/upstream_mirrors.php index 9312fc47..585a67d5 100644 --- a/config/upstream_mirrors.php +++ b/config/upstream_mirrors.php @@ -433,6 +433,7 @@ return [ ['Id'], ['fee_time', 'Id', 'inout_type', 'amount'], ['shop_id', 'fee_time', 'Id', 'inout_type', 'amount', 'fee_name'], + ['fee_name'], ], ], 'jiansun.dbo.alipay_Bill_Detail' => [ diff --git a/database/migrations/2026_09_14_160000_index_pinduoduo_bill_filter_options.php b/database/migrations/2026_09_14_160000_index_pinduoduo_bill_filter_options.php new file mode 100644 index 00000000..b078c446 --- /dev/null +++ b/database/migrations/2026_09_14_160000_index_pinduoduo_bill_filter_options.php @@ -0,0 +1,31 @@ +hasTable(self::TABLE) || $schema->hasIndex(self::TABLE, self::INDEX)) return; + + $schema->table(self::TABLE, static fn (Blueprint $table) => $table->index(['fee_name'], self::INDEX)); + } + + public function down(): void + { + if (config('system_database.mode', 'bootstrap') === 'bootstrap') return; + + $schema = Schema::connection((string) config('upstream_mirrors.connection', 'business_mirror')); + if (! $schema->hasTable(self::TABLE) || ! $schema->hasIndex(self::TABLE, self::INDEX)) return; + + $schema->table(self::TABLE, static fn (Blueprint $table) => $table->dropIndex(self::INDEX)); + } +}; diff --git a/modules/EcommerceFinance/Repositories/StoreReceivingAlipayBillMirrorRepository.php b/modules/EcommerceFinance/Repositories/StoreReceivingAlipayBillMirrorRepository.php index 3b629011..96fd4412 100644 --- a/modules/EcommerceFinance/Repositories/StoreReceivingAlipayBillMirrorRepository.php +++ b/modules/EcommerceFinance/Repositories/StoreReceivingAlipayBillMirrorRepository.php @@ -61,7 +61,7 @@ class StoreReceivingAlipayBillMirrorRepository $targetTable = $dataset->targetTable(); $query = $this->billQuery($targetTable); - $this->applyChannel($query, $channel); + $this->applyChannel($query, $channel, $dataset->fixedFilters()); $this->applyFilters($query, $filters); $state = $this->mirror->state($dataset) ?? []; // Completed runs persist an exact COUNT. New incremental batches keep @@ -127,7 +127,7 @@ class StoreReceivingAlipayBillMirrorRepository $targetTable = $dataset->targetTable(); $query = $this->billQuery($targetTable); - $this->applyChannel($query, $channel); + $this->applyChannel($query, $channel, $dataset->fixedFilters()); $this->applyFilters($query, $filters); $shopNames = $this->allShopNames(); $direction = $direction === 'desc' ? 'desc' : 'asc'; @@ -152,7 +152,7 @@ class StoreReceivingAlipayBillMirrorRepository } $channelQuery = $this->billQuery($dataset->targetTable()); - $this->applyChannel($channelQuery, $channel); + $this->applyChannel($channelQuery, $channel, $dataset->fixedFilters()); $shopIds = (clone $channelQuery) ->whereNotNull('b.shop_id') @@ -384,11 +384,12 @@ class StoreReceivingAlipayBillMirrorRepository } } - private function applyChannel(Builder $query, ?string $channel): void + /** @param array $fixedFilters */ + private function applyChannel(Builder $query, ?string $channel, array $fixedFilters): void { - if ($channel !== null && $channel !== '') { - $query->where('b.channel', $channel); - } + if ($this->channelCoversDataset($channel, $fixedFilters)) return; + + $query->where('b.channel', $channel); } /** @param array $fixedFilters */ diff --git a/tests/Unit/EcommerceFinance/StoreReceivingAlipayBillMirrorRepositoryTest.php b/tests/Unit/EcommerceFinance/StoreReceivingAlipayBillMirrorRepositoryTest.php index f68fad4a..d0608f97 100644 --- a/tests/Unit/EcommerceFinance/StoreReceivingAlipayBillMirrorRepositoryTest.php +++ b/tests/Unit/EcommerceFinance/StoreReceivingAlipayBillMirrorRepositoryTest.php @@ -364,6 +364,38 @@ class StoreReceivingAlipayBillMirrorRepositoryTest extends TestCase $this->assertSame(['交易佣金', '订单收入'], $options['bill_items']); } + public function test_shared_dataset_keeps_channel_predicates_for_all_query_entry_points(): void + { + $this->markReady(); + $db = DB::connection('business_mirror'); + $db->table('ops_jst_shop_info')->insert([ + ['Id' => 10, 'shop_id' => 7, 'shop_name' => '淘系店铺'], + ['Id' => 11, 'shop_id' => 8, 'shop_name' => '其他店铺'], + ]); + $db->table('ops_jst_original_bill_info')->insert([ + $this->row(1, 7, '2026-08-01 09:00:00', '1', 100.25, 'CommonBillTGCPay', '交易收入'), + $this->row(2, 8, '2026-08-02 09:00:00', '1', 88.00, 'OtherChannel', '其他收入'), + ]); + $db->flushQueryLog(); + $db->enableQueryLog(); + + $result = $this->repository->paginateChannel([], 'occurred_at', 'desc', 1, 10, 'CommonBillTGCPay'); + $options = $this->repository->filterOptionsForChannel('CommonBillTGCPay'); + $export = iterator_to_array($this->repository->exportChannelRows([], 'occurred_at', 'asc', 'CommonBillTGCPay')); + + $this->assertSame(1, $result['total']); + $this->assertSame(['淘系店铺'], $options['shops']); + $this->assertSame(['交易收入'], $options['bill_items']); + $this->assertCount(1, $export); + $channelQueries = array_filter( + $db->getQueryLog(), + static fn (array $query): bool => str_contains($query['query'], '"b"."channel" = ?') + && in_array('CommonBillTGCPay', $query['bindings'], true), + ); + $this->assertGreaterThanOrEqual(6, count($channelQueries)); + $db->disableQueryLog(); + } + private function markReady(): void { foreach ([StoreReceivingAlipayBillMirrorRepository::DATASET, StoreReceivingAlipayBillMirrorRepository::SHOP_DATASET] as $dataset) { diff --git a/tests/Unit/EcommerceFinance/StoreReceivingPinduoduoBillMirrorRepositoryTest.php b/tests/Unit/EcommerceFinance/StoreReceivingPinduoduoBillMirrorRepositoryTest.php index a4f28d7c..09e318dc 100644 --- a/tests/Unit/EcommerceFinance/StoreReceivingPinduoduoBillMirrorRepositoryTest.php +++ b/tests/Unit/EcommerceFinance/StoreReceivingPinduoduoBillMirrorRepositoryTest.php @@ -72,7 +72,7 @@ class StoreReceivingPinduoduoBillMirrorRepositoryTest extends TestCase $this->markReady(); } - public function test_it_reads_only_pinduoduo_goods_account_rows_and_maps_source_fields(): void + public function test_it_reads_the_pinduoduo_dedicated_dataset_and_maps_source_fields(): void { DB::connection('business_mirror')->table('ops_jst_shop_info')->insert([ ['Id' => 10, 'shop_id' => 7, 'shop_name' => '拼多多-测试店'], @@ -81,7 +81,6 @@ class StoreReceivingPinduoduoBillMirrorRepositoryTest extends TestCase DB::connection('business_mirror')->table('js_jst_pdd_receiving_bill_rows')->insert([ $this->row(1, 7, 'PinduoduoImport', '2026-09-09 23:55:47', '1', 91.64), $this->row(2, 7, 'PinduoduoImport', '2026-09-09 23:58:52', '-1', 0.66), - $this->row(3, 8, 'TouTiaoFXGZJ', '2026-09-09 23:59:00', '1', 999.00), ]); $result = $this->repository->paginate([], 'occurred_at', 'desc', 1, 10); @@ -99,7 +98,7 @@ class StoreReceivingPinduoduoBillMirrorRepositoryTest extends TestCase $this->assertSame(90.98, $result['summary']['balance']); } - public function test_filters_options_and_export_keep_the_fixed_channel(): void + public function test_filters_options_and_export_do_not_repeat_the_dataset_fixed_channel(): void { DB::connection('business_mirror')->table('ops_jst_shop_info')->insert([ ['Id' => 10, 'shop_id' => 7, 'shop_name' => '拼多多-A店'], @@ -109,8 +108,10 @@ class StoreReceivingPinduoduoBillMirrorRepositoryTest extends TestCase DB::connection('business_mirror')->table('js_jst_pdd_receiving_bill_rows')->insert([ $this->row(1, 7, 'PinduoduoImport', '2026-08-12 09:00:00', '1', 22.80, '交易收入'), $this->row(2, 8, 'PinduoduoImport', '2026-08-13 09:00:00', '-1', 0.14, '技术服务费'), - $this->row(3, 9, 'TouTiaoFXGZJ', '2026-08-13 09:00:00', '1', 99.00, '订单收入'), ]); + $connection = DB::connection('business_mirror'); + $connection->flushQueryLog(); + $connection->enableQueryLog(); $result = $this->repository->paginate([ 'store_name' => 'A店', @@ -128,6 +129,16 @@ class StoreReceivingPinduoduoBillMirrorRepositoryTest extends TestCase $this->assertSame(['交易收入', '技术服务费'], $options['bill_items']); $this->assertCount(1, $export); $this->assertSame('380000002', $export[0]['record_code']); + $targetQueries = array_filter( + $connection->getQueryLog(), + static fn (array $query): bool => str_contains($query['query'], 'js_jst_pdd_receiving_bill_rows'), + ); + $this->assertNotEmpty($targetQueries); + $this->assertCount(0, array_filter( + $targetQueries, + static fn (array $query): bool => str_contains($query['query'], '"b"."channel" = ?'), + )); + $connection->disableQueryLog(); } public function test_unfiltered_total_uses_the_exact_mirror_count(): void @@ -154,6 +165,30 @@ class StoreReceivingPinduoduoBillMirrorRepositoryTest extends TestCase $connection->disableQueryLog(); } + public function test_fee_name_index_config_and_migration_are_idempotent_and_reversible(): void + { + $configured = require base_path('config/upstream_mirrors.php'); + $indexes = $configured['datasets'][StoreReceivingPinduoduoBillMirrorRepository::DATASET]['indexes']; + $this->assertContains(['fee_name'], $indexes); + + config(['system_database.mode' => 'connected']); + $table = DB::connection('business_mirror')->table('js_jst_pdd_receiving_bill_rows'); + $table->insert($this->row(1, 7, 'PinduoduoImport', '2026-08-12 09:00:00', '1', 22.80)); + $before = (array) $table->first(); + $migration = require base_path('database/migrations/2026_09_14_160000_index_pinduoduo_bill_filter_options.php'); + + $migration->up(); + $migration->up(); + + $schema = Schema::connection('business_mirror'); + $this->assertTrue($schema->hasIndex('js_jst_pdd_receiving_bill_rows', 'idx_pdd_receiving_bill_fee_name')); + $this->assertEquals($before, (array) $table->first()); + + $migration->down(); + $this->assertFalse($schema->hasIndex('js_jst_pdd_receiving_bill_rows', 'idx_pdd_receiving_bill_fee_name')); + $this->assertEquals($before, (array) $table->first()); + } + private function markReady(): void { foreach ([StoreReceivingPinduoduoBillMirrorRepository::DATASET, StoreReceivingAlipayBillMirrorRepository::SHOP_DATASET] as $dataset) {