feat(MatchReportApiDialog): implement double assignment verification and improve match side resolution
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 56s

This commit is contained in:
Torsten Schulz (local)
2026-09-30 12:24:42 +02:00
parent 3c9a7d2cee
commit 8feaf8335e

View File

@@ -2081,6 +2081,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
});
const finalPayload = JSON.parse(JSON.stringify(normalizedByNuScore));
this.applyBraunschweigerMatchFormations(finalPayload);
this.applyCurrentLineupStateToPayload(finalPayload);
this.updatePlayerPositions(finalPayload);
@@ -2296,6 +2297,7 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
// Aufstellungen erneut in genau diesen Rückgabedatensatz
// übernommen werden. Andernfalls werden die Doppel im
// Berichtsbogen als "nicht anwesend" dargestellt.
this.applyBraunschweigerMatchFormations(submitPayload);
this.applyCurrentLineupStateToPayload(submitPayload);
this.updatePlayerPositions(submitPayload);
submitPayload.isCompleted = true;
@@ -2325,10 +2327,16 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
throw new Error(validationMessage || result.error || `HTTP ${response.status}: ${response.statusText}`);
}
console.log('✅ Spielbericht erfolgreich abgesendet:', result);
const doubleVerification = await this.verifySubmittedDoubleAssignments(uuid);
console.log('✅ Spielbericht erfolgreich abgesendet:', result, doubleVerification);
this.submitSucceeded = true;
this.clearLocalDraft();
alert('✅ Spielbericht erfolgreich abgesendet!');
if (!doubleVerification.verified) {
alert(`⚠️ Der Spielbericht wurde von nuScore angenommen, aber die Doppel konnten nicht vollständig zurückgelesen werden.\n\n${doubleVerification.message}\n\nBitte die Doppel direkt in nuScore prüfen. Der Dialog bleibt zur Kontrolle geöffnet.`);
return;
}
alert('✅ Spielbericht erfolgreich abgesendet und Doppelzuordnung von nuScore bestätigt!');
// Dialog schließen
this.$emit('close');
@@ -2405,6 +2413,71 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
}
},
async verifySubmittedDoubleAssignments(uuid) {
try {
const response = await fetch(`${backendBaseUrl}/api/nuscore/meetingdetails/${uuid}`);
if (!response.ok) {
return {
verified: false,
message: `NuScore konnte nach dem Absenden nicht erneut gelesen werden (HTTP ${response.status}).`
};
}
const report = await response.json();
const formations = report?.meetingPlayMode?.matchFormations || [];
const matches = report?.matches || [];
const doubleFormations = formations.filter(formation =>
/^D\d+$/i.test(String(formation?.homeLineupPosition || '')) &&
/^D\d+$/i.test(String(formation?.guestLineupPosition || ''))
);
if (doubleFormations.length === 0) {
return { verified: true, message: 'Das Spielsystem enthält keine Doppelbegegnung.' };
}
const incomplete = doubleFormations.filter(formation => {
const match = matches.find(item => Number(item?.matchNr) === Number(formation.matchNr));
const hasTwoNamesInMatch = (side) => {
const first = this.formatMatchPlayerName(side === 'home' ? match?.playerA1 : match?.playerB1);
const second = this.formatMatchPlayerName(side === 'home' ? match?.playerA2 : match?.playerB2);
return Boolean(first && second);
};
const hasSavedDoublePair = (side) => {
const teamKey = side === 'home' ? 'teamLineupHomePlayers' : 'teamLineupGuestPlayers';
const position = Number(String(side === 'home'
? formation.homeLineupPosition
: formation.guestLineupPosition).slice(1));
return (report?.[teamKey] || []).filter(player =>
Number(player?.nuLigaPersonId) > 0 &&
(Number(player?.positionDouble) === position ||
(player?.positions || []).includes(`D${position}`))
).length === 2;
};
// Manche nuScore-Antworten enthalten bei Doppeln keine
// playerA/B-Felder. In diesem Fall bestätigen die beiden
// gespeicherten D-Positionen die Paarung genauso sicher.
return !(hasTwoNamesInMatch('home') || hasSavedDoublePair('home')) ||
!(hasTwoNamesInMatch('guest') || hasSavedDoublePair('guest'));
});
if (incomplete.length > 0) {
const matchNumbers = incomplete.map(formation => formation.matchNr).join(', ');
return {
verified: false,
message: `Unvollständige Doppelzuordnung in Spiel ${matchNumbers}.`
};
}
return { verified: true, message: 'Alle Doppel wurden von nuScore vollständig zurückgeliefert.' };
} catch (error) {
return {
verified: false,
message: `Doppelzuordnung konnte nicht erneut geprüft werden: ${error.message}`
};
}
},
updateMatchData(matchData, options = {}) {
try {
console.log('🔄 updateMatchData: Verwende kompletten Original-Meeting-Daten...');
@@ -2777,6 +2850,58 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
.trim();
},
isUsableMatchSide(name) {
const normalized = String(name || '')
.replace(/\s+/g, ' ')
.trim()
.toLocaleLowerCase('de-DE');
return Boolean(normalized) && ![
'nicht angegeben',
'nicht angegeben / nicht angegeben',
'not specified',
'unknown',
'unbekannt',
'n/a',
'-'
].includes(normalized);
},
getMatchFormationLabel(match, index) {
const formations = this.meetingDetails?.meetingPlayMode?.matchFormations;
const matchNumber = Number(match?.matchNr ?? match?.matchNumber);
const formation = Array.isArray(formations)
? (formations.find(item => Number(item?.matchNr) === matchNumber) || formations[index])
: null;
if (formation) {
const homeLabel = this.formatLineupPositionLabel(formation.homeLineupPosition, 'home');
const guestLabel = this.formatLineupPositionLabel(formation.guestLineupPosition, 'guest');
if (homeLabel && guestLabel) {
return `${homeLabel} – ${guestLabel}`;
}
}
return this.currentPlayModeMatrix?.[index] || '';
},
resolveMatchSide(match, index, side) {
const assignedName = this.formatMeetingMatchSide(match, side);
if (this.isUsableMatchSide(assignedName)) {
return assignedName;
}
const reportedName = side === 'home' ? match?.homePlayer : match?.guestPlayer;
if (this.isUsableMatchSide(reportedName)) {
return String(reportedName).trim();
}
// NuScore liefert vor allem bei Doppeln gelegentlich nur den
// Platzhalter „nicht angegeben“. Die Paarung wird dann aus der
// Formation und den aktuell gesetzten Doppelpositionen ermittelt.
return this.resolveSide(this.getMatchFormationLabel(match, index), side);
},
formatMeetingMatchSide(match, side) {
if (!match || typeof match !== 'object') {
return '';
@@ -3127,11 +3252,10 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
? this.meetingDetails.matches
: [];
if (serverMatches.length > 0) {
const matrix = this.currentPlayModeMatrix;
this.results = serverMatches.map((match, index) => ({
label: (typeof match?.name === 'string' && match.name.trim()) || matrix[index] || `Spiel ${index + 1}`,
homeName: this.formatMeetingMatchSide(match, 'home') || match?.homePlayer || this.resolveSide(matrix[index] || '', 'home'),
guestName: this.formatMeetingMatchSide(match, 'guest') || match?.guestPlayer || this.resolveSide(matrix[index] || '', 'guest'),
label: (typeof match?.name === 'string' && match.name.trim()) || this.getMatchFormationLabel(match, index) || `Spiel ${index + 1}`,
homeName: this.resolveMatchSide(match, index, 'home'),
guestName: this.resolveMatchSide(match, index, 'guest'),
sets: ['', '', '', '', ''],
completed: false,
result: '1:0'
@@ -3161,19 +3285,17 @@ Wir wünschen den Spielen einen schönen, spannenden und fairen Verlauf und begr
const src = sourceMatches[i] || {};
const dst = this.results[i];
const resolvedHomeName = this.formatMeetingMatchSide(src, 'home');
const resolvedGuestName = this.formatMeetingMatchSide(src, 'guest');
const fallbackHomeName = typeof src.homePlayer === 'string' ? src.homePlayer.trim() : '';
const fallbackGuestName = typeof src.guestPlayer === 'string' ? src.guestPlayer.trim() : '';
const resolvedHomeName = this.resolveMatchSide(src, i, 'home');
const resolvedGuestName = this.resolveMatchSide(src, i, 'guest');
if (typeof src.name === 'string' && src.name.trim() !== '') {
dst.label = src.name.trim();
}
if (resolvedHomeName || fallbackHomeName) {
dst.homeName = resolvedHomeName || fallbackHomeName;
if (resolvedHomeName) {
dst.homeName = resolvedHomeName;
}
if (resolvedGuestName || fallbackGuestName) {
dst.guestName = resolvedGuestName || fallbackGuestName;
if (resolvedGuestName) {
dst.guestName = resolvedGuestName;
}
if (!dst.sets || !Array.isArray(dst.sets)) {