otf-api 0.2.2__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. otf_api/__init__.py +14 -69
  2. otf_api/api.py +873 -66
  3. otf_api/auth.py +314 -0
  4. otf_api/cli/__init__.py +4 -0
  5. otf_api/cli/_utilities.py +60 -0
  6. otf_api/cli/app.py +172 -0
  7. otf_api/cli/bookings.py +231 -0
  8. otf_api/cli/prompts.py +162 -0
  9. otf_api/models/__init__.py +30 -23
  10. otf_api/models/base.py +205 -2
  11. otf_api/models/responses/__init__.py +29 -29
  12. otf_api/models/responses/body_composition_list.py +304 -0
  13. otf_api/models/responses/book_class.py +405 -0
  14. otf_api/models/responses/bookings.py +211 -37
  15. otf_api/models/responses/cancel_booking.py +93 -0
  16. otf_api/models/responses/challenge_tracker_content.py +6 -6
  17. otf_api/models/responses/challenge_tracker_detail.py +6 -6
  18. otf_api/models/responses/classes.py +205 -7
  19. otf_api/models/responses/enums.py +0 -35
  20. otf_api/models/responses/favorite_studios.py +5 -5
  21. otf_api/models/responses/latest_agreement.py +2 -2
  22. otf_api/models/responses/lifetime_stats.py +92 -0
  23. otf_api/models/responses/member_detail.py +17 -12
  24. otf_api/models/responses/member_membership.py +2 -2
  25. otf_api/models/responses/member_purchases.py +9 -9
  26. otf_api/models/responses/out_of_studio_workout_history.py +4 -4
  27. otf_api/models/responses/performance_summary_detail.py +1 -1
  28. otf_api/models/responses/performance_summary_list.py +13 -13
  29. otf_api/models/responses/studio_detail.py +10 -10
  30. otf_api/models/responses/studio_services.py +8 -8
  31. otf_api/models/responses/telemetry.py +6 -6
  32. otf_api/models/responses/telemetry_hr_history.py +6 -6
  33. otf_api/models/responses/telemetry_max_hr.py +3 -3
  34. otf_api/models/responses/total_classes.py +2 -2
  35. otf_api/models/responses/workouts.py +4 -4
  36. otf_api-0.4.0.dist-info/METADATA +54 -0
  37. otf_api-0.4.0.dist-info/RECORD +42 -0
  38. otf_api-0.4.0.dist-info/entry_points.txt +3 -0
  39. otf_api/__version__.py +0 -1
  40. otf_api/classes_api.py +0 -44
  41. otf_api/member_api.py +0 -380
  42. otf_api/models/auth.py +0 -141
  43. otf_api/performance_api.py +0 -54
  44. otf_api/studios_api.py +0 -96
  45. otf_api/telemetry_api.py +0 -95
  46. otf_api-0.2.2.dist-info/METADATA +0 -284
  47. otf_api-0.2.2.dist-info/RECORD +0 -38
  48. {otf_api-0.2.2.dist-info → otf_api-0.4.0.dist-info}/AUTHORS.md +0 -0
  49. {otf_api-0.2.2.dist-info → otf_api-0.4.0.dist-info}/LICENSE +0 -0
  50. {otf_api-0.2.2.dist-info → otf_api-0.4.0.dist-info}/WHEEL +0 -0
@@ -1,9 +1,76 @@
1
1
  from datetime import datetime
2
+ from enum import Enum
3
+ from typing import ClassVar
2
4
 
3
- from otf_api.models.base import OtfBaseModel
5
+ from humanize import precisedelta
6
+ from inflection import humanize
7
+ from pydantic import Field
8
+ from rich.style import Style
9
+ from rich.styled import Styled
10
+ from rich.table import Table
4
11
 
12
+ from otf_api.models.base import OtfItemBase, OtfListBase
5
13
 
6
- class Address(OtfBaseModel):
14
+
15
+ class DoW(str, Enum):
16
+ monday = "monday"
17
+ tuesday = "tuesday"
18
+ wednesday = "wednesday"
19
+ thursday = "thursday"
20
+ friday = "friday"
21
+ saturday = "saturday"
22
+ sunday = "sunday"
23
+
24
+ @classmethod
25
+ def get_case_insensitive(cls, value: str) -> str:
26
+ lcase_to_actual = {item.value.lower(): item.value for item in cls}
27
+ return lcase_to_actual[value.lower()]
28
+
29
+
30
+ class ClassType(str, Enum):
31
+ ORANGE_60_MIN_2G = "Orange 60 Min 2G"
32
+ TREAD_50 = "Tread 50"
33
+ STRENGTH_50 = "Strength 50"
34
+ ORANGE_3G = "Orange 3G"
35
+ ORANGE_60_TORNADO = "Orange 60 - Tornado"
36
+ ORANGE_TORNADO = "Orange Tornado"
37
+ ORANGE_90_MIN_3G = "Orange 90 Min 3G"
38
+ VIP_CLASS = "VIP Class"
39
+ OTHER = "Other"
40
+
41
+ @classmethod
42
+ def all_statuses(cls) -> list[str]:
43
+ return list(cls.__members__.values())
44
+
45
+ @classmethod
46
+ def get_from_key_insensitive(cls, key: str) -> "ClassType":
47
+ lcase_to_actual = {item.lower(): item for item in cls._member_map_}
48
+ val = cls.__members__.get(lcase_to_actual[key.lower()])
49
+ if not val:
50
+ raise ValueError(f"Invalid ClassType: {key}")
51
+ return val
52
+
53
+ @classmethod
54
+ def get_case_insensitive(cls, value: str) -> str:
55
+ lcase_to_actual = {item.value.lower(): item.value for item in cls}
56
+ return lcase_to_actual[value.lower()]
57
+
58
+
59
+ class ClassTypeCli(str, Enum):
60
+ """Flipped enum so that the CLI does not have values with spaces"""
61
+
62
+ ORANGE_60_MIN_2G = "Orange_60_Min_2G"
63
+ TREAD_50 = "Tread_50"
64
+ STRENGTH_50 = "Strength_50"
65
+ ORANGE_3G = "Orange_3G"
66
+ ORANGE_60_TORNADO = "Orange_60_Tornado"
67
+ ORANGE_TORNADO = "Orange_Tornado"
68
+ ORANGE_90_MIN_3G = "Orange_90_Min_3G"
69
+ VIP_CLASS = "VIP_Class"
70
+ OTHER = "Other"
71
+
72
+
73
+ class Address(OtfItemBase):
7
74
  line1: str
8
75
  city: str
9
76
  state: str
@@ -11,7 +78,7 @@ class Address(OtfBaseModel):
11
78
  postal_code: str
12
79
 
13
80
 
14
- class Studio(OtfBaseModel):
81
+ class Studio(OtfItemBase):
15
82
  id: str
16
83
  name: str
17
84
  mbo_studio_id: str
@@ -23,15 +90,57 @@ class Studio(OtfBaseModel):
23
90
  longitude: float
24
91
 
25
92
 
26
- class Coach(OtfBaseModel):
93
+ class Coach(OtfItemBase):
27
94
  mbo_staff_id: str
28
95
  first_name: str
29
96
  image_url: str | None = None
30
97
 
31
98
 
32
- class OtfClass(OtfBaseModel):
99
+ class OtfClassTimeMixin:
100
+ starts_at_local: datetime
101
+ ends_at_local: datetime
102
+ name: str
103
+
104
+ @property
105
+ def day_of_week(self) -> str:
106
+ return self.starts_at_local.strftime("%A")
107
+
108
+ @property
109
+ def date(self) -> str:
110
+ return self.starts_at_local.strftime("%Y-%m-%d")
111
+
112
+ @property
113
+ def time(self) -> str:
114
+ """Returns time in 12 hour clock format, with no leading 0"""
115
+ val = self.starts_at_local.strftime("%I:%M %p")
116
+ if val[0] == "0":
117
+ val = " " + val[1:]
118
+
119
+ return val
120
+
121
+ @property
122
+ def duration(self) -> str:
123
+ duration = self.ends_at_local - self.starts_at_local
124
+ human_val: str = precisedelta(duration, minimum_unit="minutes")
125
+ if human_val == "1 hour and 30 minutes":
126
+ return "90 minutes"
127
+ return human_val
128
+
129
+ @property
130
+ def class_type(self) -> ClassType:
131
+ for class_type in ClassType:
132
+ if class_type.value in self.name:
133
+ return class_type
134
+
135
+ return ClassType.OTHER
136
+
137
+
138
+ class OtfClass(OtfItemBase, OtfClassTimeMixin):
33
139
  id: str
34
- ot_base_class_uuid: str
140
+ ot_class_uuid: str = Field(
141
+ alias="ot_base_class_uuid",
142
+ description="The OTF class UUID, this is what shows in a booking response and how you can book a class.",
143
+ )
35
144
  starts_at: datetime
36
145
  starts_at_local: datetime
37
146
  ends_at: datetime
@@ -51,7 +160,96 @@ class OtfClass(OtfBaseModel):
51
160
  mbo_class_description_id: str
52
161
  created_at: datetime
53
162
  updated_at: datetime
163
+ is_home_studio: bool | None = Field(None, description="Custom helper field to determine if at home studio")
164
+ is_booked: bool | None = Field(None, description="Custom helper field to determine if class is already booked")
165
+
166
+ @property
167
+ def has_availability(self) -> bool:
168
+ return not self.full
169
+
170
+ @property
171
+ def id_val(self) -> str:
172
+ return self.ot_class_uuid
173
+
174
+ @property
175
+ def day_of_week_enum(self) -> DoW:
176
+ dow = self.starts_at_local.strftime("%A")
177
+ return DoW.get_case_insensitive(dow)
178
+
179
+ @property
180
+ def sidebar_data(self) -> Table:
181
+ data = {
182
+ "class_date": self.date,
183
+ "class_time": self.time.strip(),
184
+ "class_name": self.name,
185
+ "class_id": self.id_val,
186
+ "available": self.has_availability,
187
+ "waitlist_available": self.waitlist_available,
188
+ "studio_address": self.studio.address.line1,
189
+ "coach_name": self.coach.first_name,
190
+ "waitlist_size": self.waitlist_size,
191
+ "max_capacity": self.max_capacity,
192
+ }
193
+
194
+ if not self.full:
195
+ del data["waitlist_available"]
196
+ del data["waitlist_size"]
197
+
198
+ table = Table(expand=True, show_header=False, show_footer=False)
199
+ table.add_column("Key", style="cyan", ratio=1)
200
+ table.add_column("Value", style="magenta", ratio=2)
54
201
 
202
+ for key, value in data.items():
203
+ if value is False:
204
+ table.add_row(key, Styled(str(value), style="red"))
205
+ else:
206
+ table.add_row(key, str(value))
55
207
 
56
- class OtfClassList(OtfBaseModel):
208
+ return table
209
+
210
+ def get_style(self, is_selected: bool = False) -> Style:
211
+ style = super().get_style(is_selected)
212
+ if self.is_booked:
213
+ style = Style(color="grey58")
214
+ return style
215
+
216
+ @classmethod
217
+ def attr_to_column_header(cls, attr: str) -> str:
218
+ attr_map = {k: humanize(k) for k in cls.model_fields}
219
+ overrides = {
220
+ "day_of_week": "Class DoW",
221
+ "date": "Class Date",
222
+ "time": "Class Time",
223
+ "duration": "Class Duration",
224
+ "name": "Class Name",
225
+ "is_home_studio": "Home Studio",
226
+ "is_booked": "Booked",
227
+ }
228
+
229
+ attr_map.update(overrides)
230
+
231
+ return attr_map.get(attr, attr)
232
+
233
+
234
+ class OtfClassList(OtfListBase):
235
+ collection_field: ClassVar[str] = "classes"
57
236
  classes: list[OtfClass]
237
+
238
+ @staticmethod
239
+ def book_class_columns() -> list[str]:
240
+ return [
241
+ "day_of_week",
242
+ "date",
243
+ "time",
244
+ "duration",
245
+ "name",
246
+ "studio.name",
247
+ "is_home_studio",
248
+ "is_booked",
249
+ ]
250
+
251
+ def to_table(self, columns: list[str] | None = None) -> Table:
252
+ if not columns:
253
+ columns = self.book_class_columns()
254
+
255
+ return super().to_table(columns)
@@ -1,19 +1,6 @@
1
1
  from enum import Enum
2
2
 
3
3
 
4
- class StudioStatus(str, Enum):
5
- OTHER = "OTHER"
6
- ACTIVE = "Active"
7
- INACTIVE = "Inactive"
8
- COMING_SOON = "Coming Soon"
9
- TEMP_CLOSED = "Temporarily Closed"
10
- PERM_CLOSED = "Permanently Closed"
11
-
12
- @classmethod
13
- def all_statuses(cls) -> list[str]:
14
- return list(cls.__members__.values())
15
-
16
-
17
4
  class EquipmentType(int, Enum):
18
5
  Treadmill = 2
19
6
  Strider = 3
@@ -36,23 +23,6 @@ class ChallengeType(int, Enum):
36
23
  BackAtIt = 84
37
24
 
38
25
 
39
- class BookingStatus(str, Enum):
40
- CheckedIn = "Checked In"
41
- CancelCheckinPending = "Cancel Checkin Pending"
42
- CancelCheckinRequested = "Cancel Checkin Requested"
43
- Cancelled = "Cancelled"
44
- LateCancelled = "Late Cancelled"
45
- Booked = "Booked"
46
- Waitlisted = "Waitlisted"
47
- CheckinPending = "Checkin Pending"
48
- CheckinRequested = "Checkin Requested"
49
- CheckinCancelled = "Checkin Cancelled"
50
-
51
- @classmethod
52
- def all_statuses(cls) -> list[str]:
53
- return list(cls.__members__.values())
54
-
55
-
56
26
  class HistoryBookingStatus(str, Enum):
57
27
  Attended = "Attended"
58
28
  Cancelled = "Cancelled"
@@ -80,8 +50,3 @@ class HistoryClassStatus(str, Enum):
80
50
  @classmethod
81
51
  def all_statuses(cls) -> list[str]:
82
52
  return list(cls.__members__.values())
83
-
84
-
85
- ALL_CLASS_STATUS = BookingStatus.all_statuses()
86
- ALL_HISTORY_CLASS_STATUS = HistoryClassStatus.all_statuses()
87
- ALL_STUDIO_STATUS = StudioStatus.all_statuses()
@@ -2,10 +2,10 @@ from datetime import datetime
2
2
 
3
3
  from pydantic import Field
4
4
 
5
- from otf_api.models.base import OtfBaseModel
5
+ from otf_api.models.base import OtfItemBase
6
6
 
7
7
 
8
- class Location(OtfBaseModel):
8
+ class Location(OtfItemBase):
9
9
  location_id: int = Field(..., alias="locationId")
10
10
  location_uuid: str = Field(..., alias="locationUUId")
11
11
  studio_id: int = Field(..., alias="studioId")
@@ -21,7 +21,7 @@ class Location(OtfBaseModel):
21
21
  postal_code: str = Field(..., alias="postalCode")
22
22
 
23
23
 
24
- class StudioLocation(OtfBaseModel):
24
+ class StudioLocation(OtfItemBase):
25
25
  bill_to_address: str = Field(..., alias="billToAddress")
26
26
  bill_to_address2: str = Field(..., alias="billToAddress2")
27
27
  bill_to_city: str = Field(..., alias="billToCity")
@@ -51,7 +51,7 @@ class StudioLocation(OtfBaseModel):
51
51
  longitude: str
52
52
 
53
53
 
54
- class FavoriteStudio(OtfBaseModel):
54
+ class FavoriteStudio(OtfItemBase):
55
55
  studio_id: int = Field(..., alias="studioId")
56
56
  studio_uuid: str = Field(..., alias="studioUUId")
57
57
  mbo_studio_id: int = Field(..., alias="mboStudioId")
@@ -94,7 +94,7 @@ class FavoriteStudio(OtfBaseModel):
94
94
  studio_location: StudioLocation = Field(..., alias="studioLocation")
95
95
 
96
96
 
97
- class FavoriteStudioList(OtfBaseModel):
97
+ class FavoriteStudioList(OtfItemBase):
98
98
  studios: list[FavoriteStudio]
99
99
 
100
100
  @property
@@ -2,10 +2,10 @@ from datetime import datetime
2
2
 
3
3
  from pydantic import Field
4
4
 
5
- from otf_api.models.base import OtfBaseModel
5
+ from otf_api.models.base import OtfItemBase
6
6
 
7
7
 
8
- class LatestAgreement(OtfBaseModel):
8
+ class LatestAgreement(OtfItemBase):
9
9
  file_url: str = Field(..., alias="fileUrl")
10
10
  agreement_id: int = Field(..., alias="agreementId")
11
11
  agreement_uuid: str = Field(..., alias="agreementUUId")
@@ -0,0 +1,92 @@
1
+ from enum import Enum
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class StatsTime(str, Enum):
7
+ LastYear = "lastYear"
8
+ ThisYear = "thisYear"
9
+ LastMonth = "lastMonth"
10
+ ThisMonth = "thisMonth"
11
+ LastWeek = "lastWeek"
12
+ ThisWeek = "thisWeek"
13
+ AllTime = "allTime"
14
+
15
+
16
+ class StatsType(str, Enum):
17
+ Home = "outStudio"
18
+ Studio = "inStudio"
19
+ All = "allStats"
20
+
21
+
22
+ class OutStudioMixin(BaseModel):
23
+ walking_distance: float = Field(..., alias="walkingDistance")
24
+ running_distance: float = Field(..., alias="runningDistance")
25
+ cycling_distance: float = Field(..., alias="cyclingDistance")
26
+
27
+
28
+ class InStudioMixin(BaseModel):
29
+ treadmill_distance: float = Field(..., alias="treadmillDistance")
30
+ treadmill_elevation_gained: float = Field(..., alias="treadmillElevationGained")
31
+ rower_distance: float = Field(..., alias="rowerDistance")
32
+ rower_watt: float = Field(..., alias="rowerWatt")
33
+
34
+
35
+ class BaseStatsData(BaseModel):
36
+ calories: float
37
+ splat_point: float = Field(..., alias="splatPoint")
38
+ total_black_zone: float = Field(..., alias="totalBlackZone")
39
+ total_blue_zone: float = Field(..., alias="totalBlueZone")
40
+ total_green_zone: float = Field(..., alias="totalGreenZone")
41
+ total_orange_zone: float = Field(..., alias="totalOrangeZone")
42
+ total_red_zone: float = Field(..., alias="totalRedZone")
43
+ workout_duration: float = Field(..., alias="workoutDuration")
44
+ step_count: float = Field(..., alias="stepCount")
45
+
46
+
47
+ class InStudioStatsData(InStudioMixin, BaseStatsData):
48
+ pass
49
+
50
+
51
+ class OutStudioStatsData(OutStudioMixin, BaseStatsData):
52
+ pass
53
+
54
+
55
+ class AllStatsData(OutStudioMixin, InStudioMixin, BaseStatsData):
56
+ pass
57
+
58
+
59
+ class OutStudioTimeStats(BaseModel):
60
+ last_year: OutStudioStatsData = Field(..., alias="lastYear")
61
+ this_year: OutStudioStatsData = Field(..., alias="thisYear")
62
+ last_month: OutStudioStatsData = Field(..., alias="lastMonth")
63
+ this_month: OutStudioStatsData = Field(..., alias="thisMonth")
64
+ last_week: OutStudioStatsData = Field(..., alias="lastWeek")
65
+ this_week: OutStudioStatsData = Field(..., alias="thisWeek")
66
+ all_time: OutStudioStatsData = Field(..., alias="allTime")
67
+
68
+
69
+ class InStudioTimeStats(BaseModel):
70
+ last_year: InStudioStatsData = Field(..., alias="lastYear")
71
+ this_year: InStudioStatsData = Field(..., alias="thisYear")
72
+ last_month: InStudioStatsData = Field(..., alias="lastMonth")
73
+ this_month: InStudioStatsData = Field(..., alias="thisMonth")
74
+ last_week: InStudioStatsData = Field(..., alias="lastWeek")
75
+ this_week: InStudioStatsData = Field(..., alias="thisWeek")
76
+ all_time: InStudioStatsData = Field(..., alias="allTime")
77
+
78
+
79
+ class AllStatsTimeStats(BaseModel):
80
+ last_year: AllStatsData = Field(..., alias="lastYear")
81
+ this_year: AllStatsData = Field(..., alias="thisYear")
82
+ last_month: AllStatsData = Field(..., alias="lastMonth")
83
+ this_month: AllStatsData = Field(..., alias="thisMonth")
84
+ last_week: AllStatsData = Field(..., alias="lastWeek")
85
+ this_week: AllStatsData = Field(..., alias="thisWeek")
86
+ all_time: AllStatsData = Field(..., alias="allTime")
87
+
88
+
89
+ class StatsResponse(BaseModel):
90
+ all_stats: AllStatsTimeStats = Field(..., alias="allStats")
91
+ in_studio: InStudioTimeStats = Field(..., alias="inStudio")
92
+ out_studio: OutStudioTimeStats = Field(..., alias="outStudio")
@@ -3,12 +3,11 @@ from typing import Any
3
3
 
4
4
  from pydantic import Field
5
5
 
6
- from otf_api.models.base import OtfBaseModel
6
+ from otf_api.models.base import OtfItemBase
7
7
 
8
8
 
9
- class Address(OtfBaseModel):
10
- member_address_uuid: str = Field(..., alias="memberAddressUUId")
11
- memberaddress_uuid: str = Field(..., alias="memberaddressUUId")
9
+ class Address(OtfItemBase):
10
+ member_address_uuid: str | None = Field(None, alias="memberAddressUUId")
12
11
  type: str
13
12
  address1: str
14
13
  address2: str | None = None
@@ -17,28 +16,34 @@ class Address(OtfBaseModel):
17
16
  postal_code: str = Field(..., alias="postalCode")
18
17
  country: str
19
18
 
19
+ def __init__(self, **data):
20
+ if "memberaddressUUId" in data:
21
+ data["memberAddressUUId"] = data.pop("memberaddressUUId")
20
22
 
21
- class MemberCreditCard(OtfBaseModel):
23
+ super().__init__(**data)
24
+
25
+
26
+ class MemberCreditCard(OtfItemBase):
22
27
  name_on_card: str = Field(..., alias="nameOnCard")
23
28
  cc_type: str = Field(..., alias="ccType")
24
29
  cc_last4: str = Field(..., alias="ccLast4")
25
30
 
26
31
 
27
- class PhysicalCountryDetails(OtfBaseModel):
32
+ class PhysicalCountryDetails(OtfItemBase):
28
33
  country_code: str = Field(..., alias="countryCode")
29
34
  description: str
30
35
 
31
36
 
32
- class StudioLocation(OtfBaseModel):
37
+ class StudioLocation(OtfItemBase):
33
38
  physical_country_id: int = Field(..., alias="physicalCountryId")
34
39
  physical_country_details: PhysicalCountryDetails = Field(..., alias="physicalCountryDetails")
35
40
 
36
41
 
37
- class StudioPartner(OtfBaseModel):
42
+ class StudioPartner(OtfItemBase):
38
43
  studio_acs_id: str = Field(..., alias="studioAcsId")
39
44
 
40
45
 
41
- class HomeStudio(OtfBaseModel):
46
+ class HomeStudio(OtfItemBase):
42
47
  studio_id: int = Field(..., alias="studioId")
43
48
  studio_uuid: str = Field(..., alias="studioUUId")
44
49
  studio_name: str = Field(..., alias="studioName")
@@ -51,7 +56,7 @@ class HomeStudio(OtfBaseModel):
51
56
  studio_partner: StudioPartner = Field(..., alias="studioPartner")
52
57
 
53
58
 
54
- class MemberProfile(OtfBaseModel):
59
+ class MemberProfile(OtfItemBase):
55
60
  member_profile_uuid: str = Field(..., alias="memberProfileUUId")
56
61
  unit_of_measure: str = Field(..., alias="unitOfMeasure")
57
62
  max_hr_type: str = Field(..., alias="maxHrType")
@@ -61,7 +66,7 @@ class MemberProfile(OtfBaseModel):
61
66
  member_optin_flow_type_id: int = Field(..., alias="memberOptinFlowTypeId")
62
67
 
63
68
 
64
- class MemberClassSummary(OtfBaseModel):
69
+ class MemberClassSummary(OtfItemBase):
65
70
  total_classes_booked: int = Field(..., alias="totalClassesBooked")
66
71
  total_classes_attended: int = Field(..., alias="totalClassesAttended")
67
72
  total_intro: int = Field(..., alias="totalIntro")
@@ -75,7 +80,7 @@ class MemberClassSummary(OtfBaseModel):
75
80
  last_class_studio_visited: int = Field(..., alias="lastClassStudioVisited")
76
81
 
77
82
 
78
- class MemberDetail(OtfBaseModel):
83
+ class MemberDetail(OtfItemBase):
79
84
  member_id: int = Field(..., alias="memberId")
80
85
  member_uuid: str = Field(..., alias="memberUUId")
81
86
  cognito_id: str = Field(..., alias="cognitoId")
@@ -2,10 +2,10 @@ from datetime import datetime
2
2
 
3
3
  from pydantic import Field
4
4
 
5
- from otf_api.models.base import OtfBaseModel
5
+ from otf_api.models.base import OtfItemBase
6
6
 
7
7
 
8
- class MemberMembership(OtfBaseModel):
8
+ class MemberMembership(OtfItemBase):
9
9
  member_membership_id: int = Field(..., alias="memberMembershipId")
10
10
  member_membership_uuid: str = Field(..., alias="memberMembershipUUId")
11
11
  membership_id: int = Field(..., alias="membershipId")
@@ -2,10 +2,10 @@ from datetime import datetime
2
2
 
3
3
  from pydantic import Field
4
4
 
5
- from otf_api.models.base import OtfBaseModel
5
+ from otf_api.models.base import OtfItemBase
6
6
 
7
7
 
8
- class Location(OtfBaseModel):
8
+ class Location(OtfItemBase):
9
9
  phone: str
10
10
  latitude: str
11
11
  longitude: str
@@ -16,16 +16,16 @@ class Location(OtfBaseModel):
16
16
  postal_code: str = Field(..., alias="postalCode")
17
17
 
18
18
 
19
- class Currency(OtfBaseModel):
19
+ class Currency(OtfItemBase):
20
20
  currency_alphabetic_code: str = Field(..., alias="currencyAlphabeticCode")
21
21
 
22
22
 
23
- class DefaultCurrency(OtfBaseModel):
23
+ class DefaultCurrency(OtfItemBase):
24
24
  currency_id: int = Field(..., alias="currencyId")
25
25
  currency: Currency
26
26
 
27
27
 
28
- class Country(OtfBaseModel):
28
+ class Country(OtfItemBase):
29
29
  country_id: int = Field(..., alias="countryId")
30
30
  country_code: str = Field(..., alias="countryCode")
31
31
  description: str
@@ -33,7 +33,7 @@ class Country(OtfBaseModel):
33
33
  default_currency: DefaultCurrency = Field(..., alias="defaultCurrency")
34
34
 
35
35
 
36
- class StudioLocation(OtfBaseModel):
36
+ class StudioLocation(OtfItemBase):
37
37
  studio_location_id: int = Field(..., alias="studioLocationId")
38
38
  bill_to_address: str = Field(..., alias="billToAddress")
39
39
  bill_to_address2: str = Field(..., alias="billToAddress2")
@@ -65,7 +65,7 @@ class StudioLocation(OtfBaseModel):
65
65
  country: Country
66
66
 
67
67
 
68
- class Studio(OtfBaseModel):
68
+ class Studio(OtfItemBase):
69
69
  studio_id: int = Field(..., alias="studioId")
70
70
  studio_uuid: str = Field(..., alias="studioUUId")
71
71
  mbo_studio_id: int = Field(..., alias="mboStudioId")
@@ -109,7 +109,7 @@ class Studio(OtfBaseModel):
109
109
  studio_location: StudioLocation = Field(..., alias="studioLocation")
110
110
 
111
111
 
112
- class MemberPurchase(OtfBaseModel):
112
+ class MemberPurchase(OtfItemBase):
113
113
  member_purchase_id: int = Field(..., alias="memberPurchaseId")
114
114
  member_purchase_uuid: str = Field(..., alias="memberPurchaseUUId")
115
115
  studio_id: int = Field(..., alias="studioId")
@@ -131,5 +131,5 @@ class MemberPurchase(OtfBaseModel):
131
131
  studio: Studio
132
132
 
133
133
 
134
- class MemberPurchaseList(OtfBaseModel):
134
+ class MemberPurchaseList(OtfItemBase):
135
135
  data: list[MemberPurchase]
@@ -2,16 +2,16 @@ from datetime import datetime
2
2
 
3
3
  from pydantic import Field
4
4
 
5
- from otf_api.models.base import OtfBaseModel
5
+ from otf_api.models.base import OtfItemBase
6
6
 
7
7
 
8
- class WorkoutType(OtfBaseModel):
8
+ class WorkoutType(OtfItemBase):
9
9
  id: int
10
10
  display_name: str = Field(..., alias="displayName")
11
11
  icon: str
12
12
 
13
13
 
14
- class OutOfStudioWorkoutHistory(OtfBaseModel):
14
+ class OutOfStudioWorkoutHistory(OtfItemBase):
15
15
  workout_date: datetime = Field(..., alias="workoutDate")
16
16
  start_time: datetime = Field(..., alias="startTime")
17
17
  end_time: datetime = Field(..., alias="endTime")
@@ -37,5 +37,5 @@ class OutOfStudioWorkoutHistory(OtfBaseModel):
37
37
  max_heartrate: int = Field(..., alias="maxHeartrate")
38
38
 
39
39
 
40
- class OutOfStudioWorkoutHistoryList(OtfBaseModel):
40
+ class OutOfStudioWorkoutHistoryList(OtfItemBase):
41
41
  data: list[OutOfStudioWorkoutHistory]
@@ -74,4 +74,4 @@ class PerformanceSummaryDetail(BaseModel):
74
74
  id: str
75
75
  details: Details
76
76
  ratable: bool
77
- class_: Class = Field(..., alias="class")
77
+ otf_class: Class = Field(..., alias="class")