resa-padel/resa_padel/models.py

212 lines
6.5 KiB
Python

from enum import Enum
from typing import Optional
import pendulum
from pendulum import Date, Time
from pydantic import BaseModel, ConfigDict, Field, field_validator
from pydantic_extra_types.pendulum_dt import DateTime
class User(BaseModel):
login: str
password: str = Field(repr=False)
club_id: Optional[str] = Field(default=None)
class BookingOpening(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
days_before: Optional[int] = Field(default=7, alias="daysBefore")
opening_time: Optional[str] = Field(alias="time", default=None, repr=False)
time_after_booking: Optional[str] = Field(
alias="timeAfterBookingTime", default=None, repr=False
)
def __repr__(self):
base = super().__repr__()
time = f", time: {self.time})" if self.time else ""
time_after_booking = (
f", time_after_booking_time: {self.time_after_booking_time})"
if self.time_after_booking_time
else ""
)
return base.removesuffix(")") + time + time_after_booking
@property
def time(self):
return pendulum.parse(self.opening_time).time()
@property
def time_after_booking_time(self):
return (
pendulum.parse(self.time_after_booking).time()
if self.time_after_booking
else None
)
class TotalBookings(BaseModel):
peak_hours: int | str = Field(alias="peakHours")
off_peak_hours: int | str = Field(alias="offPeakHours")
class Court(BaseModel):
id: int
name: str
number: int
is_indoor: Optional[bool] = Field(alias="isIndoor")
class Sport(BaseModel):
name: str
id: int
duration: int
price: int
players: int
courts: list[Court]
class Url(BaseModel):
name: str
path: str
payload_template: Optional[str] = Field(default=None, alias="payloadTemplate")
class BookingPlatform(BaseModel):
id: str
club_id: int = Field(alias="clubId")
url: str
hours_before_cancellation: int = Field(alias="hoursBeforeCancellation")
booking_opening: BookingOpening = Field(alias="bookingOpening")
total_bookings: TotalBookings = Field(alias="totalBookings")
sports: list[Sport]
urls: dict[str, Url]
class Club(BaseModel):
id: str
name: str
url: str
booking_platform: BookingPlatform = Field(alias="bookingPlatform")
class PlatformDefinition(BaseModel):
id: str
name: str
url: str
urls: list[Url]
class BookingFilter(BaseModel):
date: DateTime
sport_name: str
@field_validator("sport_name", mode="before")
@classmethod
def to_lower_case(cls, d: str) -> str:
return d.lower()
class Booking(BaseModel):
id: int
booking_date: DateTime = Field(alias="dateResa")
start_time: DateTime = Field(alias="startTime")
sport: str
court: str
game_creation: Optional[int] = Field(default=None, alias="creaPartie")
game_creation_limit: Optional[DateTime] = Field(
default=None, alias="limitCreaPartie"
)
cancel: Optional[bool] = Field(default=True)
block_player_replacement: Optional[int] = Field(
default=None, alias="bloquerRemplacementJoueur"
)
can_remove_parteners: bool = Field(default=True, alias="canRemovePartners")
end_time: Optional[DateTime] = Field(default=None, alias="endTime")
day_fr: Optional[str] = Field(default=None, alias="dayFr")
live_xperience_code: Optional[str] = Field(default=None, alias="codeLiveXperience")
spartime_qr_code: Optional[str] = Field(default=None, alias="qrCodeSpartime")
remaining_places: int = Field(default=3, alias="remainingPlaces")
is_captain: bool = Field(default=True, alias="isCaptain")
dt_start: Optional[DateTime] = Field(default=None, alias="dtStart")
credit_card_guaranty: Optional[str] = Field(default=None, alias="garantieCb")
certificate_validity_duration: Optional[int] = Field(
alias="dureeValidCertif", default=None
)
charge_id: Optional[str] = Field(default=None, alias="chargeId")
partners: Optional[list] = Field(default=[])
player_status: Optional[int] = Field(default=None, alias="playerStatus")
products: Optional[list] = Field(default=[])
@field_validator("booking_date", mode="before")
@classmethod
def validate_date(cls, d: str) -> DateTime:
return pendulum.from_format(
d, "DD/MM/YYYY", tz=pendulum.timezone("Europe/Paris")
)
@field_validator("start_time", "end_time", mode="before")
@classmethod
def validate_time(cls, t: str) -> DateTime:
return pendulum.from_format(t, "HH:mm", tz=pendulum.timezone("Europe/Paris"))
@field_validator("game_creation_limit", mode="before")
@classmethod
def validate_datetime_add_tz(cls, dt: str) -> DateTime:
return pendulum.parse(dt, tz=pendulum.timezone("Europe/Paris"))
@field_validator("dt_start", mode="before")
@classmethod
def validate_datetime(cls, dt: str) -> DateTime:
return pendulum.parse(dt)
@field_validator("sport", mode="before")
@classmethod
def to_lower_case(cls, d: str) -> str:
return d.lower()
def matches(self, booking_filter: BookingFilter) -> bool:
"""
Check if the booking matches the booking filter
:param booking_filter: the conditions the booking should meet
:return: true if the booking matches the conditions, false otherwise
"""
return (
self.is_same_sport(booking_filter.sport_name)
and self.is_same_date(booking_filter.date.date())
and self.is_same_time(booking_filter.date.time())
)
def is_same_sport(self, sport: str) -> bool:
"""
Check if the booking and the booking filter are about the same sport
:param sport: the sport to test
:return: true if the sport matches booking sport, false otherwise
"""
return self.sport == sport
def is_same_date(self, date: Date) -> bool:
"""
Check if the booking filter has the same date as the booking
:param date: the date to test
:return: true if the date matches the booking date, false otherwise
"""
return self.booking_date.date() == date
def is_same_time(self, time: Time) -> bool:
"""
Check if the booking filter has the same time as the booking
:param time: the time to test
:return: true if the time matches the booking time, false otherwise
"""
return self.start_time.time() == time
class Action(Enum):
BOOK = "book"
CANCEL = "cancel"