id) ->where('is_active', true) ->whereNull('completed_at') ->where(function($q) { $q->whereNull('expires_at')->orWhere('expires_at', '>', now()); }) ->get(); foreach ($activeBonuses as $bonus) { DB::transaction(function() use ($bonus, $wagerAmount) { $bonus->refresh(); if (!$bonus->is_active || $bonus->completed_at) return; $bonus->wager_progress += $wagerAmount; if ($bonus->wager_progress >= $bonus->wager_required) { $bonus->completed_at = now(); $bonus->is_active = false; Log::info("BonusService: User {$bonus->user_id} completed bonus {$bonus->id}"); // Logic to unlock real balance if needed } $bonus->save(); }); } } /** * Expire outdated bonuses */ public function expireBonuses(): int { $expiredCount = UserBonus::where('is_active', true) ->whereNotNull('expires_at') ->where('expires_at', '<=', now()) ->update([ 'is_active' => false ]); if ($expiredCount > 0) { Log::info("BonusService: Expired $expiredCount user bonuses"); } return $expiredCount; } }