'baccarat'], [ 'name' => 'Baccarat', 'icon' => 'baccarat', 'description' => 'Baccarat Game', 'enabled' => true, 'params' => [ 'min_bet' => 100, 'max_bet' => 50000, ], ] ); Sysparam::updateOrCreate(['alias' => 'chatbot_enabled'], ['body' => '1']); Sysparam::clearCache('chatbot_enabled'); } /** * 买单活动时间窗口命中时,AI 会按百家乐最大下注额下注,并把下注挂到活动名下。 */ public function test_ai_bets_baccarat_max_bet_when_loss_cover_time_window_is_active(): void { Event::fake(); Queue::fake([SaveMessageJob::class]); $this->mock(ChatStateService::class, function (MockInterface $mock): void { $mock->shouldReceive('nextMessageId')->andReturn(1); $mock->shouldReceive('pushMessage')->zeroOrMoreTimes(); $mock->shouldReceive('getAllActiveRoomIds')->andReturn([1]); }); $this->mock(BaccaratPredictionService::class, function (MockInterface $mock): void { $mock->shouldReceive('predict') ->once() ->andReturn([ 'action' => 'big', 'percentage' => 1, 'reason' => '测试用低仓位建议', ]); }); $aiUser = User::factory()->create([ 'username' => 'AI小班长', 'jjb' => 1000000, 'bank_jjb' => 200000, ]); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'scheduled', 'starts_at' => now()->subMinutes(2), 'ends_at' => now()->addMinutes(10), ]); $round = BaccaratRound::forceCreate([ 'status' => 'betting', 'bet_opens_at' => now()->subSeconds(10), 'bet_closes_at' => now()->addMinute(), 'total_bet_big' => 0, 'total_bet_small' => 0, 'total_bet_triple' => 0, 'bet_count' => 0, 'bet_count_big' => 0, 'bet_count_small' => 0, 'bet_count_triple' => 0, 'total_payout' => 0, ]); $job = new AiBaccaratBetJob($round); $job->handle(app(\App\Services\UserCurrencyService::class), app(\App\Services\AiFinanceService::class)); $this->assertDatabaseHas('baccarat_bets', [ 'round_id' => $round->id, 'user_id' => $aiUser->id, 'loss_cover_event_id' => $event->id, 'bet_type' => 'big', 'amount' => 50000, 'status' => 'pending', ]); $this->assertDatabaseHas('baccarat_loss_cover_records', [ 'event_id' => $event->id, 'user_id' => $aiUser->id, 'total_bet_amount' => 50000, 'claim_status' => 'not_eligible', ]); $this->assertDatabaseHas('baccarat_loss_cover_events', [ 'id' => $event->id, 'participant_count' => 1, ]); $this->assertDatabaseHas('users', [ 'id' => $aiUser->id, 'jjb' => 950000, 'bank_jjb' => 200000, ]); } /** * 买单活动时间窗口命中时,即使 AI 返回观望,系统也会强制切回本地策略完成下注。 */ public function test_ai_still_places_bet_when_loss_cover_time_window_is_active_and_ai_returns_pass(): void { Event::fake(); Queue::fake([SaveMessageJob::class]); $this->mock(ChatStateService::class, function (MockInterface $mock): void { $mock->shouldReceive('nextMessageId')->andReturn(1); $mock->shouldReceive('pushMessage')->zeroOrMoreTimes(); $mock->shouldReceive('getAllActiveRoomIds')->andReturn([1]); }); $this->mock(BaccaratPredictionService::class, function (MockInterface $mock): void { $mock->shouldReceive('predict') ->once() ->andReturn([ 'action' => 'pass', 'percentage' => 0, 'reason' => '常规风控建议先观望', ]); }); $aiUser = User::factory()->create([ 'username' => 'AI小班长', 'jjb' => 600000, 'bank_jjb' => 0, ]); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'active', 'starts_at' => now()->subMinutes(2), 'ends_at' => now()->addMinutes(10), ]); $round = BaccaratRound::forceCreate([ 'status' => 'betting', 'bet_opens_at' => now()->subSeconds(10), 'bet_closes_at' => now()->addMinute(), 'total_bet_big' => 0, 'total_bet_small' => 0, 'total_bet_triple' => 0, 'bet_count' => 0, 'bet_count_big' => 0, 'bet_count_small' => 0, 'bet_count_triple' => 0, 'total_payout' => 0, ]); $job = new AiBaccaratBetJob($round); $job->handle(app(\App\Services\UserCurrencyService::class), app(\App\Services\AiFinanceService::class)); $bet = \App\Models\BaccaratBet::query() ->where('round_id', $round->id) ->where('user_id', $aiUser->id) ->first(); $this->assertNotNull($bet); $this->assertContains($bet->bet_type, ['big', 'small', 'triple']); $this->assertSame(50000, (int) $bet->amount); $this->assertSame($event->id, $bet->loss_cover_event_id); $this->assertDatabaseHas('baccarat_loss_cover_records', [ 'event_id' => $event->id, 'user_id' => $aiUser->id, 'total_bet_amount' => 50000, ]); } }