From 7da30df2915df689d60921a250dfee902d82d7c8 Mon Sep 17 00:00:00 2001 From: Malaber Date: Wed, 15 Apr 2026 10:43:21 +0200 Subject: [PATCH] Defer decider checks until groups finish --- app/services/group_stage_service.rb | 15 ++++++++++- spec/services/group_stage_service_spec.rb | 31 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/app/services/group_stage_service.rb b/app/services/group_stage_service.rb index 5297eb2..9003131 100644 --- a/app/services/group_stage_service.rb +++ b/app/services/group_stage_service.rb @@ -271,6 +271,7 @@ class GroupStageService sorted_group_scores = group_scores_for(group).sort advancing_slots = advancing_slots_for_group(group) + group_ready_for_decider_check = regular_group_matches_finished?(group) cache = sorted_group_scores.each_with_index.each_with_object({}) do |(group_score, index), decisions| next if sorted_group_scores.size <= 1 @@ -290,7 +291,8 @@ class GroupStageService hidden_points_result: comparison_reason[:hidden_points_result].to_s, decider_match_id: comparison_reason[:decider_match_id], tied: comparison_reason[:tied], - needs_decider_match: comparison_reason[:tied] && + needs_decider_match: group_ready_for_decider_check && + comparison_reason[:tied] && unresolved_tie_crosses_advancing_cutoff?(sorted_group_scores, group_score, advancing_slots) } end @@ -309,5 +311,16 @@ class GroupStageService def group_score_cache_key(group_score) group_score.id || group_score.object_id end + + def regular_group_matches_finished?(group) + matches = if group.association(:matches).loaded? && group.matches.any? + group.matches + else + group.matches.reload + end + + regular_matches = matches.reject(&:decider?) + regular_matches.any? && regular_matches.all?(&:finished?) + end end end diff --git a/spec/services/group_stage_service_spec.rb b/spec/services/group_stage_service_spec.rb index 0d7a00f..c3d0cf6 100644 --- a/spec/services/group_stage_service_spec.rb +++ b/spec/services/group_stage_service_spec.rb @@ -300,6 +300,37 @@ RSpec.describe GroupStageService do ) end + it 'does not request a decider while regular matches in the group are still unfinished' do + tournament.update!(playoff_teams_amount: 1, instant_finalists_amount: 1, intermediate_round_participants_amount: 0) + + create(:group_match, group: group, state: :in_progress).tap do |match| + create(:match_score, match: match, team: team_a, points: 2) + create(:match_score, match: match, team: team_b, points: 2) + end + + score_a = create(:group_score, group: group, team: team_a, group_points: 1, scored_points: 2, received_points: 2) + score_b = create(:group_score, group: group, team: team_b, group_points: 1, scored_points: 2, received_points: 2) + score_c = create(:group_score, group: group, team: team_c, group_points: 0, scored_points: 0, received_points: 0) + score_d = create(:group_score, group: group, team: team_d, group_points: 0, scored_points: 0, received_points: 0) + + GroupStageService.send(:recalculate_position_of_group_scores!, [score_a, score_b, score_c, score_d]).each(&:save!) + + expect(GroupStageService.ranking_decision_for(score_a)).to include( + resolved_by: 'tie', + direct_comparison_result: 'draw', + hidden_points_result: 'not_played', + tied: true, + needs_decider_match: false + ) + expect(GroupStageService.ranking_decision_for(score_b)).to include( + resolved_by: 'tie', + direct_comparison_result: 'draw', + hidden_points_result: 'not_played', + tied: true, + needs_decider_match: false + ) + end + it 'marks unresolved ties outside the advancing cutoff without requesting a decider' do tournament.update!(playoff_teams_amount: 2, instant_finalists_amount: 2, intermediate_round_participants_amount: 0)