diff --git a/PadelClub/Data/PlayerRegistration.swift b/PadelClub/Data/PlayerRegistration.swift index dfe7da0..525423b 100644 --- a/PadelClub/Data/PlayerRegistration.swift +++ b/PadelClub/Data/PlayerRegistration.swift @@ -44,6 +44,7 @@ final class PlayerRegistration: ModelObject, Storable { var clubCode: String? var sourceName: String? var isNveq: Bool = false + var isEQConfirmed: Bool? func localizedSourceLabel() -> String { switch source { @@ -196,9 +197,16 @@ final class PlayerRegistration: ModelObject, Storable { var duplicatePlayers: Int? - func championshipAlerts(tournament: Tournament, allPlayers: [(String, String)]) -> [ChampionshipAlert] { + func championshipAlerts(tournament: Tournament, allPlayers: [(String, String)], forRegional: Bool) -> [ChampionshipAlert] { var alerts = [ChampionshipAlert]() + if forRegional { + if isNveq == false && (isEQConfirmed == false || isEQConfirmed == nil) { + alerts.append(.notEQ(isEQConfirmed, self)) + + } + } + if duplicatePlayers == nil { let teamClubCode = self.team()?.clubCode let strippedLicense = self.licenceId?.strippedLicense @@ -347,7 +355,25 @@ final class PlayerRegistration: ModelObject, Storable { return "non classé" + (isMalePlayer() ? "" : "e") } } - + + func verifyEQ(from sources: [CSVParser]) async throws { +#if DEBUG_TIME //DEBUGING TIME +let start = Date() +defer { + let duration = Duration.milliseconds(Date().timeIntervalSince(start) * 1_000) + print("func updateRank()", id, duration.formatted(.units(allowed: [.seconds, .milliseconds]))) +} +#endif + + if let dataFound = try await history(from: sources) { + print("dataFound.clubCode == clubCode", dataFound.clubCode, clubCode) + isEQConfirmed = dataFound.clubCode == clubCode + } else { + print("not found") + isEQConfirmed = nil + } + } + func updateRank(from sources: [CSVParser], lastRank: Int) async throws { #if DEBUG_TIME //DEBUGING TIME let start = Date() diff --git a/PadelClub/Data/TeamRegistration.swift b/PadelClub/Data/TeamRegistration.swift index f0e981e..091fb90 100644 --- a/PadelClub/Data/TeamRegistration.swift +++ b/PadelClub/Data/TeamRegistration.swift @@ -460,7 +460,7 @@ final class TeamRegistration: ModelObject, Storable { } players.forEach { pr in - alerts.append(contentsOf: pr.championshipAlerts(tournament: tournament, allPlayers: allPlayers)) + alerts.append(contentsOf: pr.championshipAlerts(tournament: tournament, allPlayers: allPlayers, forRegional: teamIndex <= 16)) } return alerts diff --git a/PadelClub/Data/Tournament.swift b/PadelClub/Data/Tournament.swift index 0c0827b..618edb0 100644 --- a/PadelClub/Data/Tournament.swift +++ b/PadelClub/Data/Tournament.swift @@ -1678,6 +1678,27 @@ defer { try await player.updateRank(from: sources, lastRank: (player.sex == .female ? lastRankWoman : lastRankMan) ?? 0) } } + + func verifyEQ() async throws { + +#if DEBUG_TIME //DEBUGING TIME +let start = Date() +defer { + let duration = Duration.milliseconds(Date().timeIntervalSince(start) * 1_000) + print("func updateRank()", id, duration.formatted(.units(allowed: [.seconds, .milliseconds]))) +} +#endif + + guard let newDate = URL.importDateFormatter.date(from: "08-2024") else { return } + let dataURLs = SourceFileManager.shared.allFiles.filter { $0.dateFromPath == newDate } + let sources = dataURLs.map { CSVParser(url: $0) } + let teams = selectedSortedTeams().prefix(16) + let players = teams.flatMap({ $0.unsortedPlayers() }) + + try await players.concurrentForEach { player in + try await player.verifyEQ(from: sources) + } + } func missingUnrankedValue() -> Bool { return maleUnrankedValue == nil || femaleUnrankedValue == nil diff --git a/PadelClub/Utils/FileImportManager.swift b/PadelClub/Utils/FileImportManager.swift index 04a3cdd..0eed585 100644 --- a/PadelClub/Utils/FileImportManager.swift +++ b/PadelClub/Utils/FileImportManager.swift @@ -778,9 +778,12 @@ enum ChampionshipAlert: LocalizedError { case playerAgeInvalid(PlayerRegistration) case playerSexInvalid(PlayerRegistration) case duplicate(Int, PlayerRegistration) - + case notEQ(Bool?, PlayerRegistration) + var errorDescription: String? { switch self { + case .notEQ(_, let playerRegistration): + return playerRegistration.errorDescription(championshipAlert: self) case .duplicate(_, let playerRegistration): return playerRegistration.errorDescription(championshipAlert: self) case .clubCodeInvalid(let teamRegistration): @@ -813,6 +816,12 @@ extension PlayerRegistration { func errorDescription(championshipAlert: ChampionshipAlert) -> String? { var message = self.playerLabel() + " - " + self.formattedLicense() + " -> " switch championshipAlert { + case .notEQ(let bool, _): + if bool == nil { + message += "EQ INVERIFIABLE" + } else { + message += "EQ INVALIDE" + } case .duplicate(let count, _): message += "DOUBLON : " + count.formatted() case .clubCodeInvalid, .tooManyNVEQ, .tooManyPlayers: diff --git a/PadelClub/Utils/SwiftParser.swift b/PadelClub/Utils/SwiftParser.swift index de0bda2..5601e8b 100644 --- a/PadelClub/Utils/SwiftParser.swift +++ b/PadelClub/Utils/SwiftParser.swift @@ -65,6 +65,10 @@ struct Line: Identifiable { var assimilation: String? { data[7] } + + var clubCode: String? { + data[10]?.replaceCharactersFromSet(characterSet: .whitespaces) + } } struct CSVParser: AsyncSequence, AsyncIteratorProtocol { diff --git a/PadelClub/Views/Navigation/Umpire/PadelClubView.swift b/PadelClub/Views/Navigation/Umpire/PadelClubView.swift index 341c928..ca70995 100644 --- a/PadelClub/Views/Navigation/Umpire/PadelClubView.swift +++ b/PadelClub/Views/Navigation/Umpire/PadelClubView.swift @@ -269,7 +269,7 @@ func fetchPlayerData(for licenseID: String) async throws -> [Player]? { request.setValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With") // Add cookies if needed (example cookie header value shown, replace with valid cookies) - request.setValue("JSESSIONID=C27A8C305B9B1A3E8DD70300AFB8980E; AWSALB=qZ18nw7AsrBeo+X8yPL5RPFGerM9nePHqhVS3EasXJ3vRSskWtrVlkSQS7rhugIkndpGm918I4UqvfxpaDJxjgsVwXY6AoC40AfUXdFosITMK9hLbxbLlqm/XK3/; AWSALBCORS=qZ18nw7AsrBeo+X8yPL5RPFGerM9nePHqhVS3EasXJ3vRSskWtrVlkSQS7rhugIkndpGm918I4UqvfxpaDJxjgsVwXY6AoC40AfUXdFosITMK9hLbxbLlqm/XK3/; datadome=phzBnXmnx632ekfRiFl~WQEPoMTPKvFn~OfNIMzjCyv9vbaigh9182wiJhvkRJvddV8EvlHyszjEovY0zYcQ2k45QCdLMPuKlBIVOTh~OWk1HF8EIszhio6USnidWq5Y; tc_cj_v2=%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQMMORPMMMQNNZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQMMQMPMPMKOPZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQMPLNJNKJQQJZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQMPLNJNLQOJKZZZ%5D; tc_cj_v2_cmp=; tc_cj_v2_med=; SSESS7ba44afc36c80c3faa2b8fa87e7742c5=EFTV9aCrNCaJM7Soo-1OemOQ0qdJXpp7cqiYrMSoQRQ; incap_ses_188_2712217=bHGnCqoz+kuioZ6sNumbAhntfGcAAAAAyRoEUqalcEb2ssM0ElLpsQ==; TCSESSION=1251114295811051390969; incap_ses_2222_2712217=TZW0OzHRREDHgyiHhyHWHtPae2cAAAAAZtkxEWEK6Umt8kLgVqiHxg==; nlbi_2712217=xjnrKu85cRfbMwOCb9lUTgAAAADQ43pUbl/hRFX1Q8fYrJlG; _pcid=%7B%22browserId%22%3A%22m42mi4kbtfuyj367%22%2C%22_t%22%3A%22mjr1fm32%7Cm42mi4r2%22%7D; _pctx=%7Bu%7DN4IgrgzgpgThIC4B2YA2qA05owMoBcBDfSREQpAeyRCwgEt8oBJAE0RXSwH18yBbAFYwAjADN%2BAZgCsAH34AWAEz96CmNJABfIA; _pprv=eyJjb25zZW50Ijp7IjAiOnsibW9kZSI6ImVzc2VudGlhbCJ9LCI3Ijp7Im1vZGUiOiJvcHQtaW4ifX0sInB1cnBvc2VzIjpudWxsLCJfdCI6Im1qcjFmbHdofG00Mm1pNGtoIn0%3D; xtan=-; xtant=1; TCID=124122155494907703483; TCPID=124115115191501043230; xtvrn=$548419$; visid_incap_2712217=PSfJngzoSuiowsuXXhvOu5K+7mUAAAAAQUIPAAAAAAAleL9ldvN/FC1VykkU9ret; SessionStatId=10.91.140.42.1662124965429001", forHTTPHeaderField: "Cookie") + request.setValue("JSESSIONID=C4B647EB27A036891E29D27FD83CE29B; AWSALB=1btRrmQjbf1VjZH74hBI3+OcfTO/HfJWbf+wm0kpBEVz9jUgvXb+UO4FkcIimuferhUjEfWmENKUS1SYmHCkndtiaR5x89W9uHYi/JTO3zn1ZO2JRCjvEgY7BNJm; AWSALBCORS=1btRrmQjbf1VjZH74hBI3+OcfTO/HfJWbf+wm0kpBEVz9jUgvXb+UO4FkcIimuferhUjEfWmENKUS1SYmHCkndtiaR5x89W9uHYi/JTO3zn1ZO2JRCjvEgY7BNJm; datadome=thpudGMDaIXBt6W8GjURPii9mF0ovaPnNozziskvWhA0uZ7bt~ZX3CICjEZEV5J4GXL151J19_NsLGL5wNT2BZ9NJUbJciEo9YJdFp_OKwlM13_dYqIrJ5rlKW65SPOg; _pcid=%7B%22browserId%22%3A%22m42mi4kbtfuyj367%22%2C%22_t%22%3A%22mjr1fm32%7Cm42mi4r2%22%7D; _pctx=%7Bu%7DN4IgrgzgpgThIC4B2YA2qA05owMoBcBDfSREQpAeyRCwgEt8oBJAE0RXSwH18yBbAFYwAjADN%2BAZgCsAH34AWAEz96CmNJABfIA; _pprv=eyJjb25zZW50Ijp7IjAiOnsibW9kZSI6ImVzc2VudGlhbCJ9LCI3Ijp7Im1vZGUiOiJvcHQtaW4ifX0sInB1cnBvc2VzIjpudWxsLCJfdCI6Im1qcjFmbHdofG00Mm1pNGtoIn0%3D; tc_cj_v2=%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQMMORPMMMQNNZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQMMQMPMPMKOPZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQMPLNJNKJQQJZZZ%5D777m_iZZZ%22**%22%27%20ZZZKQMPLNJNLQOJKZZZ%5D777%5Ecl_%5Dny%5B%5D%5D_mmZZZZZZKQMPLONOQNSNSZZZ%5D; tc_cj_v2_cmp=; tc_cj_v2_med=; SSESS7ba44afc36c80c3faa2b8fa87e7742c5=EFTV9aCrNCaJM7Soo-1OemOQ0qdJXpp7cqiYrMSoQRQ; xtan=-; xtant=1; TCID=124122155494907703483; TCPID=124115115191501043230; xtvrn=$548419$; visid_incap_2712217=PSfJngzoSuiowsuXXhvOu5K+7mUAAAAAQUIPAAAAAAAleL9ldvN/FC1VykkU9ret; SessionStatId=10.91.140.42.1662124965429001", forHTTPHeaderField: "Cookie") let (data, _) = try await URLSession.shared.data(for: request) let decoder = JSONDecoder() diff --git a/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift b/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift index 2faf3f0..d879276 100644 --- a/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift +++ b/PadelClub/Views/Tournament/Screen/InscriptionManagerView.swift @@ -948,6 +948,9 @@ struct InscriptionManagerView: View { _setHash() } + RowButtonView("Verify EQ") { + await try? tournament.verifyEQ() + } Button("Generate file") { self.shareFile = tournament.pasteDataForImporting(.championship).createFile(self.tournament.tournamentTitle()+"-inscriptions", .championship) }