diff --git a/PadelClubData/Data/Gen/BasePlayerRegistration.swift b/PadelClubData/Data/Gen/BasePlayerRegistration.swift index 9cdfcef..83dbdf6 100644 --- a/PadelClubData/Data/Gen/BasePlayerRegistration.swift +++ b/PadelClubData/Data/Gen/BasePlayerRegistration.swift @@ -37,6 +37,8 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { public var timeToConfirm: Date? = nil public var registrationStatus: PlayerRegistration.RegistrationStatus = PlayerRegistration.RegistrationStatus.waiting public var paymentId: String? = nil + public var clubCode: String? = nil + public var clubMember: Bool = false public init( id: String = Store.randomId(), @@ -63,7 +65,9 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { registeredOnline: Bool = false, timeToConfirm: Date? = nil, registrationStatus: PlayerRegistration.RegistrationStatus = PlayerRegistration.RegistrationStatus.waiting, - paymentId: String? = nil + paymentId: String? = nil, + clubCode: String? = nil, + clubMember: Bool = false ) { super.init() self.id = id @@ -91,6 +95,8 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { self.timeToConfirm = timeToConfirm self.registrationStatus = registrationStatus self.paymentId = paymentId + self.clubCode = clubCode + self.clubMember = clubMember } required public override init() { super.init() @@ -122,6 +128,8 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { case _timeToConfirm = "timeToConfirm" case _registrationStatus = "registrationStatus" case _paymentId = "paymentId" + case _clubCode = "clubCode" + case _clubMember = "clubMember" } required init(from decoder: Decoder) throws { @@ -151,6 +159,8 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { self.timeToConfirm = try container.decodeIfPresent(Date.self, forKey: ._timeToConfirm) ?? nil self.registrationStatus = try container.decodeIfPresent(PlayerRegistration.RegistrationStatus.self, forKey: ._registrationStatus) ?? PlayerRegistration.RegistrationStatus.waiting self.paymentId = try container.decodeIfPresent(String.self, forKey: ._paymentId) ?? nil + self.clubCode = try container.decodeIfPresent(String.self, forKey: ._clubCode) ?? nil + self.clubMember = try container.decodeIfPresent(Bool.self, forKey: ._clubMember) ?? false try super.init(from: decoder) } @@ -181,6 +191,8 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { try container.encode(self.timeToConfirm, forKey: ._timeToConfirm) try container.encode(self.registrationStatus, forKey: ._registrationStatus) try container.encode(self.paymentId, forKey: ._paymentId) + try container.encode(self.clubCode, forKey: ._clubCode) + try container.encode(self.clubMember, forKey: ._clubMember) try super.encode(to: encoder) } @@ -216,6 +228,8 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable { self.timeToConfirm = playerregistration.timeToConfirm self.registrationStatus = playerregistration.registrationStatus self.paymentId = playerregistration.paymentId + self.clubCode = playerregistration.clubCode + self.clubMember = playerregistration.clubMember } public static func relationships() -> [Relationship] { diff --git a/PadelClubData/Data/Gen/BaseRound.swift b/PadelClubData/Data/Gen/BaseRound.swift index 0c055f2..4ca7cc2 100644 --- a/PadelClubData/Data/Gen/BaseRound.swift +++ b/PadelClubData/Data/Gen/BaseRound.swift @@ -7,11 +7,11 @@ import SwiftUI @Observable public class BaseRound: SyncedModelObject, SyncedStorable { - + public static func resourceName() -> String { return "rounds" } public static func tokenExemptedMethods() -> [HTTPMethod] { return [] } public static var copyServerResponse: Bool = false - + public var id: String = Store.randomId() public var tournament: String = "" public var index: Int = 0 @@ -19,13 +19,13 @@ public class BaseRound: SyncedModelObject, SyncedStorable { public var format: MatchFormat? = nil public var startDate: Date? = nil { didSet { - self.didSetStartDate() + self.didSetStartDate() } } public var groupStageLoserBracket: Bool = false public var loserBracketMode: LoserBracketMode = .automatic public var plannedStartDate: Date? = nil - + public init( id: String = Store.randomId(), tournament: String = "", @@ -51,9 +51,9 @@ public class BaseRound: SyncedModelObject, SyncedStorable { required public override init() { super.init() } - + public func didSetStartDate() {} - + public enum CodingKeys: String, CodingKey { case _id = "id" case _tournament = "tournament" @@ -65,7 +65,7 @@ public class BaseRound: SyncedModelObject, SyncedStorable { case _loserBracketMode = "loserBracketMode" case _plannedStartDate = "plannedStartDate" } - + required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.id = try container.decodeIfPresent(String.self, forKey: ._id) ?? Store.randomId() @@ -79,7 +79,7 @@ public class BaseRound: SyncedModelObject, SyncedStorable { self.plannedStartDate = try container.decodeIfPresent(Date.self, forKey: ._plannedStartDate) ?? nil try super.init(from: decoder) } - + public override func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(self.id, forKey: ._id) @@ -93,11 +93,11 @@ public class BaseRound: SyncedModelObject, SyncedStorable { try container.encode(self.plannedStartDate, forKey: ._plannedStartDate) try super.encode(to: encoder) } - + func tournamentValue() -> Tournament? { return Store.main.findById(tournament) } - + public func copy(from other: any Storable) { guard let round = other as? BaseRound else { return } self.id = round.id @@ -110,10 +110,11 @@ public class BaseRound: SyncedModelObject, SyncedStorable { self.loserBracketMode = round.loserBracketMode self.plannedStartDate = round.plannedStartDate } - + public static func relationships() -> [Relationship] { return [ Relationship(type: Tournament.self, keyPath: \BaseRound.tournament), ] } -} + +} \ No newline at end of file diff --git a/PadelClubData/Data/Gen/BaseTournament.swift b/PadelClubData/Data/Gen/BaseTournament.swift index d837d1e..cbc2bf0 100644 --- a/PadelClubData/Data/Gen/BaseTournament.swift +++ b/PadelClubData/Data/Gen/BaseTournament.swift @@ -81,6 +81,8 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { public var isTemplate: Bool = false public var publishProg: Bool = false public var showTeamsInProg: Bool = false + public var clubMemberFeeDeduction: Double? = nil + public var unregisterDeltaInHours: Int = 24 public init( id: String = Store.randomId(), @@ -151,7 +153,9 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { isCorporateTournament: Bool = false, isTemplate: Bool = false, publishProg: Bool = false, - showTeamsInProg: Bool = false + showTeamsInProg: Bool = false, + clubMemberFeeDeduction: Double? = nil, + unregisterDeltaInHours: Int = 24 ) { super.init() self.id = id @@ -223,6 +227,8 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { self.isTemplate = isTemplate self.publishProg = publishProg self.showTeamsInProg = showTeamsInProg + self.clubMemberFeeDeduction = clubMemberFeeDeduction + self.unregisterDeltaInHours = unregisterDeltaInHours } required public override init() { super.init() @@ -300,6 +306,8 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { case _isTemplate = "isTemplate" case _publishProg = "publishProg" case _showTeamsInProg = "showTeamsInProg" + case _clubMemberFeeDeduction = "clubMemberFeeDeduction" + case _unregisterDeltaInHours = "unregisterDeltaInHours" } private static func _decodePayment(container: KeyedDecodingContainer) throws -> TournamentPayment? { @@ -440,6 +448,8 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { self.isTemplate = try container.decodeIfPresent(Bool.self, forKey: ._isTemplate) ?? false self.publishProg = try container.decodeIfPresent(Bool.self, forKey: ._publishProg) ?? false self.showTeamsInProg = try container.decodeIfPresent(Bool.self, forKey: ._showTeamsInProg) ?? false + self.clubMemberFeeDeduction = try container.decodeIfPresent(Double.self, forKey: ._clubMemberFeeDeduction) ?? nil + self.unregisterDeltaInHours = try container.decodeIfPresent(Int.self, forKey: ._unregisterDeltaInHours) ?? 24 try super.init(from: decoder) } @@ -514,6 +524,8 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { try container.encode(self.isTemplate, forKey: ._isTemplate) try container.encode(self.publishProg, forKey: ._publishProg) try container.encode(self.showTeamsInProg, forKey: ._showTeamsInProg) + try container.encode(self.clubMemberFeeDeduction, forKey: ._clubMemberFeeDeduction) + try container.encode(self.unregisterDeltaInHours, forKey: ._unregisterDeltaInHours) try super.encode(to: encoder) } @@ -593,6 +605,8 @@ public class BaseTournament: SyncedModelObject, SyncedStorable { self.isTemplate = tournament.isTemplate self.publishProg = tournament.publishProg self.showTeamsInProg = tournament.showTeamsInProg + self.clubMemberFeeDeduction = tournament.clubMemberFeeDeduction + self.unregisterDeltaInHours = tournament.unregisterDeltaInHours } public static func relationships() -> [Relationship] { diff --git a/PadelClubData/Data/Gen/PlayerRegistration.json b/PadelClubData/Data/Gen/PlayerRegistration.json index 72dc484..5e723f0 100644 --- a/PadelClubData/Data/Gen/PlayerRegistration.json +++ b/PadelClubData/Data/Gen/PlayerRegistration.json @@ -131,6 +131,16 @@ "name": "paymentId", "type": "String", "optional": true + }, + { + "name": "clubCode", + "type": "String", + "optional": true + }, + { + "name": "clubMember", + "type": "Bool", + "defaultValue": "false" } ] } diff --git a/PadelClubData/Data/Gen/Tournament.json b/PadelClubData/Data/Gen/Tournament.json index 6851964..e058cc5 100644 --- a/PadelClubData/Data/Gen/Tournament.json +++ b/PadelClubData/Data/Gen/Tournament.json @@ -358,6 +358,16 @@ "name": "showTeamsInProg", "type": "Bool", "defaultValue": "false" + }, + { + "name": "clubMemberFeeDeduction", + "type": "Double", + "optional": true + }, + { + "name": "unregisterDeltaInHours", + "type": "Int", + "defaultValue": "24" } ] } diff --git a/PadelClubData/Data/Match.swift b/PadelClubData/Data/Match.swift index 96eb38d..4cdb3ec 100644 --- a/PadelClubData/Data/Match.swift +++ b/PadelClubData/Data/Match.swift @@ -39,6 +39,9 @@ final public class Match: BaseMatch, SideStorable { // MARK: - DidSet public override func didSetStartDate() { + if hasStarted() { + return + } if self.roundValue()?.tournamentObject()?.hasStarted() == false { plannedStartDate = startDate } else if self.groupStageValue()?.tournamentObject()?.hasStarted() == false { diff --git a/PadelClubData/Data/PlayerRegistration.swift b/PadelClubData/Data/PlayerRegistration.swift index 5451fef..3c59cfb 100644 --- a/PadelClubData/Data/PlayerRegistration.swift +++ b/PadelClubData/Data/PlayerRegistration.swift @@ -26,7 +26,7 @@ final public class PlayerRegistration: BasePlayerRegistration, SideStorable { } } - public init(teamRegistration: String? = nil, firstName: String, lastName: String, licenceId: String? = nil, rank: Int? = nil, paymentType: PlayerPaymentType? = nil, sex: PlayerSexType? = nil, tournamentPlayed: Int? = nil, points: Double? = nil, clubName: String? = nil, ligueName: String? = nil, assimilation: String? = nil, phoneNumber: String? = nil, email: String? = nil, birthdate: String? = nil, computedRank: Int = 0, source: PlayerRegistration.PlayerDataSource? = nil, hasArrived: Bool = false, coach: Bool = false, captain: Bool = false, registeredOnline: Bool = false, timeToConfirm: Date? = nil, registrationStatus: PlayerRegistration.RegistrationStatus = PlayerRegistration.RegistrationStatus.waiting, paymentId: String? = nil) { + public init(teamRegistration: String? = nil, firstName: String, lastName: String, licenceId: String? = nil, rank: Int? = nil, paymentType: PlayerPaymentType? = nil, sex: PlayerSexType? = nil, tournamentPlayed: Int? = nil, points: Double? = nil, clubName: String? = nil, ligueName: String? = nil, assimilation: String? = nil, phoneNumber: String? = nil, email: String? = nil, birthdate: String? = nil, computedRank: Int = 0, source: PlayerRegistration.PlayerDataSource? = nil, hasArrived: Bool = false, coach: Bool = false, captain: Bool = false, registeredOnline: Bool = false, timeToConfirm: Date? = nil, registrationStatus: PlayerRegistration.RegistrationStatus = PlayerRegistration.RegistrationStatus.waiting, paymentId: String? = nil, clubCode: String? = nil, clubMember: Bool = false) { super.init() self.teamRegistration = teamRegistration self.firstName = firstName @@ -52,6 +52,8 @@ final public class PlayerRegistration: BasePlayerRegistration, SideStorable { self.timeToConfirm = timeToConfirm self.registrationStatus = registrationStatus self.paymentId = paymentId + self.clubCode = clubCode + self.clubMember = clubMember } required init(from decoder: any Decoder) throws { @@ -204,6 +206,13 @@ final public class PlayerRegistration: BasePlayerRegistration, SideStorable { } } + public func setClubMember(for tournament: Tournament) { + guard let clubCode, clubCode.isEmpty == false, let code = tournament.eventObject()?.clubObject()?.code, code.isEmpty == false else { + return + } + self.clubMember = clubCode.replaceCharactersFromSet(characterSet: .whitespaces).caseInsensitiveCompare(code.replaceCharactersFromSet(characterSet: .whitespaces)) == .orderedSame + } + public func isMalePlayer() -> Bool { sex == .male } @@ -230,6 +239,37 @@ final public class PlayerRegistration: BasePlayerRegistration, SideStorable { registrationStatus = .confirmed } + public func paidAmount(_ tournament: Tournament, accountForGiftOrForfeit: Bool = false) -> Double { + if accountForGiftOrForfeit == false, paymentType == .gift { + return 0.0 + } + if accountForGiftOrForfeit == false, paymentType == .forfeit { + return 0.0 + } + if hasPaid(), let entryFee = tournament.entryFee { + if clubMember, let clubMemberFeeDeduction = tournament.clubMemberFeeDeduction { + return entryFee - clubMemberFeeDeduction + } else { + return entryFee + } + } else { + return 0.0 + } + } + + public func remainingAmount(_ tournament: Tournament) -> Double { + if let entryFee = tournament.entryFee { + if clubMember, let clubMemberFeeDeduction = tournament.clubMemberFeeDeduction { + return entryFee - clubMemberFeeDeduction - paidAmount(tournament, accountForGiftOrForfeit: true) + } else { + return entryFee - paidAmount(tournament, accountForGiftOrForfeit: true) + } + } else { + return 0.0 + } + } + + public enum PlayerDataSource: Int, Codable { case frenchFederation = 0 case beachPadel = 1 diff --git a/PadelClubData/Data/Round.swift b/PadelClubData/Data/Round.swift index 053cbbd..2f57d41 100644 --- a/PadelClubData/Data/Round.swift +++ b/PadelClubData/Data/Round.swift @@ -818,6 +818,7 @@ defer { public func disableUnplayedLoserBracketMatches() { let m = self._matches() + let roundTitle = roundTitle() if let previousRound = self.previousRound() { m.forEach { match in let prmc = previousRound.previousMatches(previousRound: previousRound, match: match).filter({ @@ -839,6 +840,7 @@ defer { match.disabled = false } } + match.setMatchName(roundTitle) } } else if let upperRound = self.parentRound { m.forEach { match in @@ -851,10 +853,12 @@ defer { } else { match.disabled = false } + match.setMatchName(roundTitle) } } + tournamentStore?.matches.addOrUpdate(contentOfs: m) - + loserRounds().forEach { loserRound in loserRound.disableUnplayedLoserBracketMatches() } diff --git a/PadelClubData/Data/Tournament.swift b/PadelClubData/Data/Tournament.swift index 50f9528..41371c8 100644 --- a/PadelClubData/Data/Tournament.swift +++ b/PadelClubData/Data/Tournament.swift @@ -1228,19 +1228,11 @@ defer { } public func earnings() -> Double { - if let entryFee { - return Double(selectedPlayers().filter { $0.hasPaid() }.count) * entryFee - } else { - return 0.0 - } + return selectedPlayers().compactMap { $0.paidAmount(self) }.reduce(0.0, +) } public func remainingAmount() -> Double { - if let entryFee { - return Double(selectedPlayers().filter { $0.hasPaid() == false }.count) * entryFee - } else { - return 0.0 - } + return selectedPlayers().compactMap { $0.remainingAmount(self) }.reduce(0.0, +) } public func paidCompletion() -> Double { @@ -1736,6 +1728,7 @@ defer { public func setupRegistrationSettings(templateTournament: Tournament) { self.enableOnlineRegistration = templateTournament.enableOnlineRegistration + self.unregisterDeltaInHours = templateTournament.unregisterDeltaInHours self.accountIsRequired = templateTournament.accountIsRequired self.licenseIsRequired = templateTournament.licenseIsRequired self.minimumPlayerPerTeam = templateTournament.minimumPlayerPerTeam