From b90c9a86393fdabc70b6a9eb3610fdca98b09e3d Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 16 Sep 2026 09:33:30 +0200 Subject: [PATCH] feat(TournamentService): add groupId to participants and entrants for knockout match pairing logic --- backend/services/tournamentService.js | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/backend/services/tournamentService.js b/backend/services/tournamentService.js index f796d985..cc1e6dbf 100755 --- a/backend/services/tournamentService.js +++ b/backend/services/tournamentService.js @@ -376,6 +376,7 @@ class TournamentService { participants: (g.participants || []).map((p, index) => ({ id: p.id, clubMemberId: p.isExternal ? null : p.clubMemberId, + groupId: g.groupId, isExternal: !!p.isExternal, place: Number(p.position ?? index + 1), points: Number(p.points ?? 0), @@ -562,6 +563,7 @@ class TournamentService { const entrants = classItems.map(p => ({ id: Number(p.id), + groupId: Number(p.groupId), isExternal: !!p.isExternal, place: p.place || 999, points: p.points ?? 0, @@ -601,6 +603,53 @@ class TournamentService { } uniqueEntrants.sort(compareKnockoutEntrants); + + // Standardsetzung für zwei Gruppen mit je zwei Qualifikanten: + // A1 gegen B2 und B1 gegen A2. Die reine Leistungsreihenfolge + // darf diese Kreuzpaarung nicht in Paarungen innerhalb derselben + // Gruppe verwandeln. + const entrantsByGroup = new Map(); + uniqueEntrants.forEach(entrant => { + const groupId = Number(entrant.groupId); + if (!Number.isFinite(groupId)) return; + const groupEntrants = entrantsByGroup.get(groupId) || []; + groupEntrants.push(entrant); + entrantsByGroup.set(groupId, groupEntrants); + }); + const qualifiedGroups = [...entrantsByGroup.values()]; + const hasStandardTwoGroupSemifinals = bracketSize === 4 + && uniqueEntrants.length === 4 + && qualifiedGroups.length === 2 + && qualifiedGroups.every(group => + group.some(entrant => entrant.place === 1) + && group.some(entrant => entrant.place === 2) + ); + + if (hasStandardTwoGroupSemifinals) { + const [groupA, groupB] = qualifiedGroups; + const a1 = groupA.find(entrant => entrant.place === 1); + const a2 = groupA.find(entrant => entrant.place === 2); + const b1 = groupB.find(entrant => entrant.place === 1); + const b2 = groupB.find(entrant => entrant.place === 2); + const roundName = getRoundName(4); + + for (const [player1, player2] of [[a1, b2], [b1, a2]]) { + await TournamentMatch.create({ + tournamentId, + stageId: toStage.id, + groupId: containerGroup.id, + classId, + groupRound: null, + round: roundName, + player1Id: Number(player1.id), + player2Id: Number(player2.id), + isFinished: false, + isActive: true, + result: null, + }); + } + continue; + } // Paare: Bester gegen Schlechtesten, Zweiter gegen Vorletzten, etc. // Reverse die zweite Hälfte, um das gewünschte Pairing zu erreichen