doge 2 дней назад
Родитель
Сommit
92e9496c78

+ 5 - 1
app/Services/PlayedGameService.php

@@ -38,10 +38,14 @@ class PlayedGameService
         ];
         $startTimestamp = $start ? Carbon::parse($start, ShareDefaults::TIMEZONE)->timestamp : null;
         $endTimestamp = $end ? Carbon::parse($end, ShareDefaults::TIMEZONE)->timestamp : null;
+        $schema = DB::connection()->getSchemaBuilder();
         foreach ($sources as [$table, $memberColumn, $timeColumn, $category, $statusColumn, $statuses, $timestamp]) {
             $query = DB::table($table)->whereIn($memberColumn, $memberIds)
                 ->whereIn($statusColumn, $statuses)->where('amount', '>', 0);
-            if ($timestamp) $query->where('is_faker', 0);
+            // Historical lottery/sports tables may not contain this optional per-order flag.
+            if (in_array($table, ['sport_order', 'lhc_order'], true) && $schema->hasColumn($table, 'is_faker')) {
+                $query->where('is_faker', 0);
+            }
             if ($table === 'sport_order') $query->where('pay_status', 1)->where('return_status', '<>', 2);
             if ($start && $end) {
                 $query->whereBetween($timeColumn, $timestamp

+ 2 - 0
docs/总后台/用户报表-游戏分类与提充差值.md

@@ -87,3 +87,5 @@ GET /admin/operation/exchangeList?page=1&limit=15&sort_field=withdraw_recharge_d
 - 沿用原有余额流水口径:提现申请扣款已计入,失败/拒绝退回在退回发生日抵扣,因此此处并非仅统计已成功出款订单。会员钱包余额 `money` 仍为当前余额。
 
 本次不需要新增数据库字段或执行数据迁移。
+
+兼容历史表结构:`lhc_order`、`sport_order` 仅在存在 `is_faker` 字段时按该字段排除虚假订单。没有该字段时继续按真实会员、订单状态、投注金额及日期查询,无需补列;会员列表仍排除 `users.from=2` 的虚拟会员。

+ 27 - 0
tests/Integration/OperationExchangeListTest.php

@@ -141,6 +141,33 @@ class OperationExchangeListTest extends TestCase
         $this->assertSame(['third:1', 'self:sport', 'self:lottery'], array_column($this->rows()['100']['played_games'], 'category'));
     }
 
+    public static function sourcesWithoutFakeFlag(): array
+    {
+        return [
+            'lottery' => ['lhc_order', 'self:lottery'],
+            'sport' => ['sport_order', 'self:sport'],
+        ];
+    }
+
+    #[DataProvider('sourcesWithoutFakeFlag')]
+    public function test_missing_optional_fake_flag_does_not_break_the_list_or_date_filters(string $table, string $category): void
+    {
+        DB::statement('ALTER TABLE bot_' . $table . ' DROP COLUMN is_faker');
+        $this->order($table);
+        $this->order($table, '200', at: '2026-11-03 23:59:59');
+        $this->order($table, '300');
+        $this->funds('充值', '100');
+        $this->funds('提现', '-25');
+
+        $rows = $this->rows(['start_time' => '2026-11-04', 'end_time' => '2026-11-04', 'sort_field' => 'recharge']);
+        $this->assertSame(['100', '200'], array_column($rows, 'member_id'));
+        $this->assertSame([$category], array_column($rows['100']['played_games'], 'category'));
+        $this->assertSame('75.00', $rows['100']['withdraw_recharge_difference']);
+        $this->assertSame([], $rows['200']['played_games']);
+        $this->assertArrayNotHasKey('300', $rows);
+        $this->assertSame([$category], array_column($this->rows()['200']['played_games'], 'category'));
+    }
+
     public function test_third_party_identity_supports_user_id_only_and_does_not_mix_members(): void
     {
         $this->order('third_game_orders', extra: ['user_id' => 1, 'member_id' => null, 'game_type' => 1]);