PIN parser korrigiert.
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 52s

This commit is contained in:
Torsten Schulz (local)
2026-08-10 15:52:28 +02:00
parent cfe2cbeec0
commit 06355552c6

View File

@@ -147,6 +147,9 @@ class PDFParserService {
*/
static parseStandardFormat(lines, clubId, lineEntries = null) {
const matches = [];
// nuLiga PIN lists identify the team's club in the document header. The
// PIN in each row belongs to that team, not inherently to the guest.
const documentTeamName = lines[0]?.trim() || null;
for (let i = 0; i < lines.length; i++) {
@@ -218,6 +221,7 @@ class PDFParserService {
const pinMatch = cleanLine3.match(/(\d{4})$/);
let code = null;
let pin = null;
let homePin = null;
let guestPin = null;
let teamsPart = cleanLine3;
@@ -228,31 +232,8 @@ class PDFParserService {
teamsPart = cleanLine3.substring(0, cleanLine3.length - code.length).trim();
} else if (pinMatch) {
// PIN gefunden (4 Ziffern)
const pin = pinMatch[1];
pin = pinMatch[1];
teamsPart = cleanLine3.substring(0, cleanLine3.length - pin.length).trim();
// Die PIN gehört immer zu "Harheimer TC"
// Prüfe, ob "Harheimer TC" am Anfang oder am Ende steht
const harheimerIndex = teamsPart.indexOf('Harheimer TC');
if (harheimerIndex >= 0) {
// "Harheimer TC" gefunden
let beforeHarheimer = teamsPart.substring(0, harheimerIndex).trim();
// Entferne führende Spielnummer (z.B. "1", "2", etc.)
beforeHarheimer = beforeHarheimer.replace(/^\d+/, '').trim();
if (beforeHarheimer && beforeHarheimer.length > 0) {
// Es gibt einen Team-Namen vor "Harheimer TC" → Harheimer ist Gastteam → guestPin
guestPin = pin;
} else {
// "Harheimer TC" steht am Anfang (nur Spielnummer davor) → Harheimer ist Heimteam → homePin
homePin = pin;
}
} else {
// "Harheimer TC" nicht gefunden → Standardlogik: PIN gehört zum Gastteam
guestPin = pin;
}
}
if (!code && codeFromColumns) {
@@ -264,15 +245,22 @@ class PDFParserService {
// columns unambiguously. Use them directly instead of trying
// to reconstruct column boundaries from the flattened text.
// This also preserves names with characters such as "ä".
if (code && homeFromColumns && guestFromColumns) {
if ((code || pin) && homeFromColumns && guestFromColumns) {
if (pin && documentTeamName) {
if (PDFParserService.namesRoughlyMatch(homeFromColumns, documentTeamName)) {
homePin = pin;
} else if (PDFParserService.namesRoughlyMatch(guestFromColumns, documentTeamName)) {
guestPin = pin;
}
}
matches.push({
date: date,
time: time,
homeTeamName: homeFromColumns,
guestTeamName: guestFromColumns,
code: code,
homePin: null,
guestPin: null,
homePin: homePin,
guestPin: guestPin,
clubId: clubId,
rawLine: line
});
@@ -329,17 +317,18 @@ class PDFParserService {
} else {
// Fallback: Versuche mit einzelnen Leerzeichen zu trennen
// Strategie 1: Suche nach "Harheimer TC" als Heimteam oder Gastteam
if (teamsPart.includes('Harheimer TC')) {
const harheimerIndex = teamsPart.indexOf('Harheimer TC');
let beforeHarheimer = teamsPart.substring(0, harheimerIndex).trim();
let afterHarheimer = teamsPart.substring(harheimerIndex + 'Harheimer TC'.length).trim();
// Strategy 1: use the team named in the document header
// as the split point when PDF text lacks column spacing.
if (documentTeamName && teamsPart.includes(documentTeamName)) {
const documentTeamIndex = teamsPart.indexOf(documentTeamName);
let beforeDocumentTeam = teamsPart.substring(0, documentTeamIndex).trim();
let afterDocumentTeam = teamsPart.substring(documentTeamIndex + documentTeamName.length).trim();
beforeHarheimer = beforeHarheimer
beforeDocumentTeam = beforeDocumentTeam
.replace(/^\(\d+\)/, '')
.replace(/^\d+/, '')
.trim();
afterHarheimer = afterHarheimer
afterDocumentTeam = afterDocumentTeam
.replace(/^\(\d+\)/, '')
.replace(/^\d+/, '')
.trim();
@@ -385,23 +374,23 @@ class PDFParserService {
return { roman: null, tokens: tokensCopy };
};
if (!beforeHarheimer && afterHarheimer) {
const tokens = afterHarheimer.split(/\s+/).filter(Boolean);
if (!beforeDocumentTeam && afterDocumentTeam) {
const tokens = afterDocumentTeam.split(/\s+/).filter(Boolean);
const { roman: homeRoman, tokens: guestTokens } = extractLeadingRomanFromTokens(tokens);
const homeSuffix = homeRoman ? ` ${homeRoman}` : '';
homeTeamName = `Harheimer TC${homeSuffix}`;
homeTeamName = `${documentTeamName}${homeSuffix}`;
guestTeamName = guestTokens.join(' ').trim();
} else if (beforeHarheimer && !afterHarheimer) {
// "Harheimer TC" ist Gastteam ohne weitere Tokens
homeTeamName = beforeHarheimer.replace(/\([^)]*\)/g, '').trim();
guestTeamName = 'Harheimer TC';
} else if (beforeHarheimer && afterHarheimer) {
// "Harheimer TC" steht in der Mitte → Harheimer ist Gast, Tokens nach Harheimer gehören zu ihm
homeTeamName = beforeHarheimer.replace(/\([^)]*\)/g, '').trim();
const tokens = afterHarheimer.split(/\s+/).filter(Boolean);
} else if (beforeDocumentTeam && !afterDocumentTeam) {
// The document team is the guest team without a suffix.
homeTeamName = beforeDocumentTeam.replace(/\([^)]*\)/g, '').trim();
guestTeamName = documentTeamName;
} else if (beforeDocumentTeam && afterDocumentTeam) {
// The document team is guest; trailing tokens can contain its suffix.
homeTeamName = beforeDocumentTeam.replace(/\([^)]*\)/g, '').trim();
const tokens = afterDocumentTeam.split(/\s+/).filter(Boolean);
const { roman: guestRoman, tokens: remainingTokens } = extractLeadingRomanFromTokens(tokens);
const guestSuffix = guestRoman ? ` ${guestRoman}` : '';
guestTeamName = `Harheimer TC${guestSuffix}`;
guestTeamName = `${documentTeamName}${guestSuffix}`;
if (remainingTokens.length > 0) {
const trailingText = remainingTokens.join(' ').trim();
if (trailingText) {
@@ -409,7 +398,7 @@ class PDFParserService {
}
}
} else {
// Nur "Harheimer TC" ohne weitere Kontexteüberspringen
// Only the document team without opponent context → skip.
continue;
}
@@ -437,6 +426,13 @@ class PDFParserService {
}
if (homeTeamName && guestTeamName) {
if (pin && !homePin && !guestPin && documentTeamName) {
if (PDFParserService.namesRoughlyMatch(homeTeamName, documentTeamName)) {
homePin = pin;
} else if (PDFParserService.namesRoughlyMatch(guestTeamName, documentTeamName)) {
guestPin = pin;
}
}
matches.push({
date: date,
@@ -723,9 +719,18 @@ class PDFParserService {
}
if (matchData.homePin) {
updateData.homePin = matchData.homePin;
// Repair a PIN previously imported on the wrong side
// without touching an independently stored guest PIN.
if (matchingMatch.guestPin === matchData.homePin) {
updateData.guestPin = null;
}
}
if (matchData.guestPin) {
updateData.guestPin = matchData.guestPin;
// Repair the corresponding inverse case.
if (matchingMatch.homePin === matchData.guestPin) {
updateData.homePin = null;
}
}
await matchingMatch.update(updateData);