From 3fc1760b2c797ad33e77d196406b9b977f3d1043 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Sat, 31 Jan 2026 00:13:01 +0100 Subject: [PATCH] feat(tournament): add logic for creating missing group matches for new participants - Implemented a new method to generate missing group matches when a new participant is added to a group that already has matches, specifically for singles classes. - Enhanced the participant assignment process to ensure all necessary matches are created, improving tournament flow and participant engagement. --- backend/services/tournamentService.js | 58 ++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/backend/services/tournamentService.js b/backend/services/tournamentService.js index 24828ec..a44dea3 100644 --- a/backend/services/tournamentService.js +++ b/backend/services/tournamentService.js @@ -3121,11 +3121,67 @@ Ve // 2. Neues Turnier anlegen ); } + // Fehlende Gruppenspiele für den neuen Teilnehmer erstellen (nur Einzel) + if (dbGroupId != null) { + const isDoubles = participantClassId != null + ? (await TournamentClass.findOne({ where: { id: participantClassId, tournamentId } }))?.isDoubles + : false; + if (!isDoubles) { + await this.addMissingGroupMatchesForNewParticipant(tournamentId, dbGroupId, participantClassId, participantId, isExternal); + } + } + console.log(`[assignParticipantToGroup] Successfully updated participant, loading groups with participants...`); - // Lade aktualisierte Gruppen mit Teilnehmern zurück return await this.getGroupsWithParticipants(userToken, clubId, tournamentId); } + /** + * Erstellt fehlende Gruppenspiele, wenn ein neuer Spieler zu einer Gruppe hinzugefügt wird, + * die bereits Spiele hat. Einzel-Klassen nur. + */ + async addMissingGroupMatchesForNewParticipant(tournamentId, groupId, classId, newParticipantId, isExternal) { + const internalMembers = await TournamentMember.findAll({ where: { groupId } }); + const externalMembers = await ExternalTournamentParticipant.findAll({ where: { groupId } }); + const allMembers = [ + ...internalMembers.map(m => ({ id: m.id, key: `i-${m.id}` })), + ...externalMembers.map(m => ({ id: m.id, key: `e-${m.id}` })) + ]; + if (allMembers.length < 2) return; + + const matchWhere = { tournamentId, groupId, round: 'group' }; + if (classId != null) matchWhere.classId = classId; + else matchWhere.classId = { [Op.is]: null }; + const existingMatches = await TournamentMatch.findAll({ where: matchWhere }); + const pairKey = (a, b) => [a, b].sort((x, y) => x - y).join('-'); + const existingPairs = new Set(); + existingMatches.forEach(m => { + if (m.player1Id && m.player2Id) { + existingPairs.add(pairKey(m.player1Id, m.player2Id)); + } + }); + + const maxRound = existingMatches.reduce((max, m) => Math.max(max, m.groupRound || 0), 0); + let nextRound = maxRound + 1; + + const newMemberKey = isExternal ? `e-${newParticipantId}` : `i-${newParticipantId}`; + for (const other of allMembers) { + if (other.id === newParticipantId) continue; + const key = pairKey(newParticipantId, other.id); + if (existingPairs.has(key)) continue; + + await TournamentMatch.create({ + tournamentId, + groupId, + round: 'group', + player1Id: newParticipantId, + player2Id: other.id, + groupRound: nextRound++, + classId + }); + existingPairs.add(key); + } + } + // services/tournamentService.js async resetGroups(userToken, clubId, tournamentId) { await checkAccess(userToken, clubId);