'baccarat'], [ 'name' => 'Baccarat', 'icon' => 'baccarat', 'description' => 'Baccarat Game', 'enabled' => true, 'params' => [ 'min_bet' => 100, 'max_bet' => 50000, ], ] ); } /** * 验证 superlevel 管理员可以创建百家乐买单活动。 */ public function test_superlevel_admin_can_create_baccarat_loss_cover_event(): void { Queue::fake(); $admin = User::factory()->create(['user_level' => 100]); $response = $this->actingAs($admin)->postJson(route('command.baccarat_loss_cover.store'), [ 'title' => '你玩游戏我买单', 'description' => '测试活动', 'starts_at' => now()->addMinutes(5)->toDateTimeString(), 'ends_at' => now()->addMinutes(35)->toDateTimeString(), 'claim_deadline_at' => now()->addDay()->toDateTimeString(), ]); $response->assertOk()->assertJson(['ok' => true]); $this->assertDatabaseHas('baccarat_loss_cover_events', [ 'title' => '你玩游戏我买单', 'created_by_user_id' => $admin->id, 'status' => 'scheduled', ]); } /** * 验证活动进行中下注会挂到活动并写入用户聚合记录。 */ public function test_bet_during_active_event_is_tracked_in_loss_cover_record(): void { Event::fake(); $user = User::factory()->create(['jjb' => 500]); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'active', 'starts_at' => now()->subMinutes(2), 'ends_at' => now()->addMinutes(20), ]); $round = BaccaratRound::forceCreate([ 'status' => 'betting', 'bet_opens_at' => now(), 'bet_closes_at' => now()->addMinutes(1), '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, ]); $response = $this->actingAs($user)->postJson(route('baccarat.bet'), [ 'round_id' => $round->id, 'bet_type' => 'big', 'amount' => 100, ]); $response->assertOk()->assertJson(['ok' => true]); $this->assertDatabaseHas('baccarat_bets', [ 'round_id' => $round->id, 'user_id' => $user->id, 'loss_cover_event_id' => $event->id, 'amount' => 100, ]); $this->assertDatabaseHas('baccarat_loss_cover_records', [ 'event_id' => $event->id, 'user_id' => $user->id, 'total_bet_amount' => 100, 'claim_status' => 'not_eligible', ]); $this->assertDatabaseHas('baccarat_loss_cover_events', [ 'id' => $event->id, 'participant_count' => 1, ]); } /** * 验证用户领取补偿后会增加金币并写入金币流水。 */ public function test_user_can_claim_baccarat_loss_cover_and_currency_log_is_written(): void { Event::fake([MessageSent::class]); Queue::fake([SaveMessageJob::class]); $user = User::factory()->create(['jjb' => 200]); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'claimable', 'claim_deadline_at' => now()->addHours(12), 'total_loss_amount' => 300, ]); BaccaratLossCoverRecord::factory()->create([ 'event_id' => $event->id, 'user_id' => $user->id, 'total_bet_amount' => 600, 'total_loss_amount' => 300, 'compensation_amount' => 300, 'claim_status' => 'pending', ]); $response = $this->actingAs($user)->postJson(route('baccarat-loss-cover.claim', $event)); $response->assertOk()->assertJson([ 'ok' => true, 'amount' => 300, ]); $this->assertSame(500, (int) $user->fresh()->jjb); $this->assertDatabaseHas('baccarat_loss_cover_records', [ 'event_id' => $event->id, 'user_id' => $user->id, 'claim_status' => 'claimed', 'claimed_amount' => 300, ]); $this->assertDatabaseHas('user_currency_logs', [ 'user_id' => $user->id, 'currency' => 'gold', 'amount' => 300, 'source' => CurrencySource::BACCARAT_LOSS_COVER_CLAIM->value, ]); Event::assertDispatched(MessageSent::class); Queue::assertPushed(SaveMessageJob::class, function (SaveMessageJob $job): bool { return str_contains($job->messageData['content'], '领取了 300 金币补偿') && str_contains($job->messageData['content'], 'claimBaccaratLossCover'); }); } /** * 验证历史接口会返回当前用户在活动中的领取状态。 */ public function test_history_endpoint_contains_my_claim_status(): void { $user = User::factory()->create(); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'completed', 'total_claimed_amount' => 400, ]); BaccaratLossCoverRecord::factory()->create([ 'event_id' => $event->id, 'user_id' => $user->id, 'claim_status' => 'claimed', 'claimed_amount' => 400, 'compensation_amount' => 400, 'claimed_at' => now(), ]); $response = $this->actingAs($user)->getJson(route('baccarat-loss-cover.history')); $response->assertOk(); $response->assertJsonPath('events.0.id', $event->id); $response->assertJsonPath('events.0.my_record.claim_status', 'claimed'); $response->assertJsonPath('events.0.my_record.claimed_amount', 400); } /** * 验证活动进入可领取状态后会为 AI 小班长派发自动领取任务。 */ public function test_claimable_event_dispatches_ai_auto_claim_job(): void { Queue::fake(); $aiUser = User::factory()->create([ 'username' => 'AI小班长', 'jjb' => 1000, ]); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'active', 'starts_at' => now()->subHour(), 'ends_at' => now()->subMinute(), 'claim_deadline_at' => now()->addHours(12), ]); BaccaratLossCoverRecord::factory()->create([ 'event_id' => $event->id, 'user_id' => $aiUser->id, 'compensation_amount' => 260, 'total_loss_amount' => 260, 'claim_status' => 'pending', ]); app(BaccaratLossCoverService::class)->closeDueActiveEvents(); Queue::assertPushed(AiClaimBaccaratLossCoverJob::class, function (AiClaimBaccaratLossCoverJob $job) use ($event): bool { return $job->eventId === $event->id; }); $this->assertDatabaseHas('baccarat_loss_cover_events', [ 'id' => $event->id, 'status' => 'claimable', ]); } /** * 验证 AI 小班长自动领取任务会发放补偿并写入金币流水。 */ public function test_ai_auto_claim_job_claims_compensation_and_writes_currency_log(): void { $aiUser = User::factory()->create([ 'username' => 'AI小班长', 'jjb' => 200, ]); $event = BaccaratLossCoverEvent::factory()->create([ 'status' => 'claimable', 'claim_deadline_at' => now()->addHours(12), 'total_loss_amount' => 320, ]); BaccaratLossCoverRecord::factory()->create([ 'event_id' => $event->id, 'user_id' => $aiUser->id, 'total_bet_amount' => 600, 'total_loss_amount' => 320, 'compensation_amount' => 320, 'claim_status' => 'pending', ]); $job = new AiClaimBaccaratLossCoverJob($event->id); $job->handle(app(BaccaratLossCoverService::class)); $this->assertSame(520, (int) $aiUser->fresh()->jjb); $this->assertDatabaseHas('baccarat_loss_cover_records', [ 'event_id' => $event->id, 'user_id' => $aiUser->id, 'claim_status' => 'claimed', 'claimed_amount' => 320, ]); $this->assertDatabaseHas('user_currency_logs', [ 'user_id' => $aiUser->id, 'currency' => 'gold', 'amount' => 320, 'source' => CurrencySource::BACCARAT_LOSS_COVER_CLAIM->value, ]); } }