bookalimo 1.0.0__py3-none-any.whl → 1.0.2__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.
- bookalimo/client.py +45 -22
- bookalimo/config.py +1 -1
- bookalimo/integrations/google_places/client_async.py +141 -156
- bookalimo/integrations/google_places/client_sync.py +142 -156
- bookalimo/integrations/google_places/common.py +464 -200
- bookalimo/integrations/google_places/resolve_airport.py +426 -0
- bookalimo/integrations/google_places/transports.py +105 -0
- bookalimo/logging.py +103 -0
- bookalimo/schemas/__init__.py +126 -34
- bookalimo/schemas/base.py +74 -14
- bookalimo/schemas/places/__init__.py +27 -0
- bookalimo/schemas/places/common.py +155 -2
- bookalimo/schemas/places/field_mask.py +212 -0
- bookalimo/schemas/places/google.py +458 -16
- bookalimo/schemas/places/place.py +25 -28
- bookalimo/schemas/requests.py +214 -0
- bookalimo/schemas/responses.py +196 -0
- bookalimo/schemas/{booking.py → shared.py} +55 -218
- bookalimo/services/pricing.py +9 -129
- bookalimo/services/reservations.py +10 -100
- bookalimo/transport/auth.py +2 -2
- bookalimo/transport/httpx_async.py +41 -125
- bookalimo/transport/httpx_sync.py +30 -109
- bookalimo/transport/utils.py +204 -3
- bookalimo-1.0.2.dist-info/METADATA +245 -0
- bookalimo-1.0.2.dist-info/RECORD +40 -0
- bookalimo-1.0.2.dist-info/licenses/LICENSE +21 -0
- bookalimo-1.0.0.dist-info/METADATA +0 -307
- bookalimo-1.0.0.dist-info/RECORD +0 -35
- bookalimo-1.0.0.dist-info/licenses/LICENSE +0 -0
- {bookalimo-1.0.0.dist-info → bookalimo-1.0.2.dist-info}/WHEEL +0 -0
- {bookalimo-1.0.0.dist-info → bookalimo-1.0.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from
|
3
|
+
from enum import IntEnum
|
4
|
+
from typing import Optional
|
4
5
|
|
5
6
|
from pydantic import (
|
6
7
|
AnyUrl,
|
@@ -24,6 +25,7 @@ from .common import (
|
|
24
25
|
EVChargeOptions,
|
25
26
|
FuelOptions,
|
26
27
|
LatLng,
|
28
|
+
LocalizedText,
|
27
29
|
OpeningHours,
|
28
30
|
ParkingOptions,
|
29
31
|
PaymentOptions,
|
@@ -38,7 +40,7 @@ from .common import (
|
|
38
40
|
)
|
39
41
|
|
40
42
|
|
41
|
-
class PriceLevel(
|
43
|
+
class PriceLevel(IntEnum):
|
42
44
|
PRICE_LEVEL_UNSPECIFIED = 0
|
43
45
|
PRICE_LEVEL_FREE = 1
|
44
46
|
PRICE_LEVEL_INEXPENSIVE = 2
|
@@ -47,7 +49,7 @@ class PriceLevel(int):
|
|
47
49
|
PRICE_LEVEL_VERY_EXPENSIVE = 5
|
48
50
|
|
49
51
|
|
50
|
-
class BusinessStatus(
|
52
|
+
class BusinessStatus(IntEnum):
|
51
53
|
BUSINESS_STATUS_UNSPECIFIED = 0
|
52
54
|
OPERATIONAL = 1
|
53
55
|
CLOSED_TEMPORARILY = 2
|
@@ -59,12 +61,14 @@ class AddressComponent(BaseModel):
|
|
59
61
|
|
60
62
|
long_text: str
|
61
63
|
short_text: Optional[str] = None
|
62
|
-
types:
|
64
|
+
types: list[str] = Field(
|
65
|
+
default_factory=list
|
66
|
+
) # limited to https://developers.google.com/maps/documentation/places/web-service/place-types
|
63
67
|
language_code: Optional[str] = None
|
64
68
|
|
65
69
|
@field_validator("types")
|
66
70
|
@classmethod
|
67
|
-
def _types(cls, v:
|
71
|
+
def _types(cls, v: list[str]) -> list[str]:
|
68
72
|
out, seen = [], set()
|
69
73
|
for raw in v:
|
70
74
|
t = raw.strip()
|
@@ -114,13 +118,6 @@ class NeighborhoodSummary(BaseModel):
|
|
114
118
|
disclosure_text: Optional[LocalizedText] = None
|
115
119
|
|
116
120
|
|
117
|
-
class LocalizedText(BaseModel):
|
118
|
-
model_config = ConfigDict(extra="allow")
|
119
|
-
|
120
|
-
text: str
|
121
|
-
language_code: str
|
122
|
-
|
123
|
-
|
124
121
|
class ContainingPlace(BaseModel):
|
125
122
|
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
|
126
123
|
|
@@ -148,7 +145,7 @@ class ContainingPlace(BaseModel):
|
|
148
145
|
return self
|
149
146
|
|
150
147
|
|
151
|
-
class
|
148
|
+
class GooglePlace(BaseModel):
|
152
149
|
model_config = ConfigDict(extra="allow", str_strip_whitespace=True)
|
153
150
|
|
154
151
|
# Identity
|
@@ -157,7 +154,7 @@ class Place(BaseModel):
|
|
157
154
|
|
158
155
|
# Labels & typing
|
159
156
|
display_name: Optional[LocalizedText] = None
|
160
|
-
types:
|
157
|
+
types: list[str] = Field(default_factory=list)
|
161
158
|
primary_type: Optional[str] = None
|
162
159
|
primary_type_display_name: Optional[LocalizedText] = None
|
163
160
|
|
@@ -165,9 +162,10 @@ class Place(BaseModel):
|
|
165
162
|
national_phone_number: Optional[str] = None
|
166
163
|
international_phone_number: Optional[str] = None
|
167
164
|
formatted_address: Optional[str] = None
|
165
|
+
address_descriptor: Optional[AddressDescriptor] = None
|
168
166
|
short_formatted_address: Optional[str] = None
|
169
167
|
postal_address: Optional[PostalAddress] = None
|
170
|
-
address_components:
|
168
|
+
address_components: list[AddressComponent] = Field(default_factory=list)
|
171
169
|
plus_code: Optional[PlusCode] = None
|
172
170
|
|
173
171
|
# Location & map
|
@@ -178,22 +176,22 @@ class Place(BaseModel):
|
|
178
176
|
rating: Optional[float] = None
|
179
177
|
google_maps_uri: Optional[AnyUrl] = None
|
180
178
|
website_uri: Optional[AnyUrl] = None
|
181
|
-
reviews:
|
182
|
-
photos:
|
179
|
+
reviews: list[Review] = Field(default_factory=list)
|
180
|
+
photos: list[Photo] = Field(default_factory=list)
|
183
181
|
|
184
182
|
# Hours
|
185
183
|
regular_opening_hours: Optional[OpeningHours] = None
|
186
184
|
current_opening_hours: Optional[OpeningHours] = None
|
187
|
-
current_secondary_opening_hours:
|
188
|
-
regular_secondary_opening_hours:
|
185
|
+
current_secondary_opening_hours: list[OpeningHours] = Field(default_factory=list)
|
186
|
+
regular_secondary_opening_hours: list[OpeningHours] = Field(default_factory=list)
|
189
187
|
utc_offset_minutes: Optional[int] = None
|
190
188
|
time_zone: Optional[TimeZone] = None
|
191
189
|
|
192
190
|
# Misc attributes
|
193
191
|
adr_format_address: Optional[str] = None
|
194
|
-
business_status: Optional[
|
195
|
-
price_level: Optional[
|
196
|
-
attributions:
|
192
|
+
business_status: Optional[BusinessStatus] = None
|
193
|
+
price_level: Optional[PriceLevel] = None
|
194
|
+
attributions: list[Attribution] = Field(default_factory=list)
|
197
195
|
user_rating_count: Optional[int] = None
|
198
196
|
icon_mask_base_uri: Optional[AnyUrl] = None
|
199
197
|
icon_background_color: Optional[str] = None
|
@@ -227,7 +225,7 @@ class Place(BaseModel):
|
|
227
225
|
# Options & related places
|
228
226
|
payment_options: Optional[PaymentOptions] = None
|
229
227
|
parking_options: Optional[ParkingOptions] = None
|
230
|
-
sub_destinations:
|
228
|
+
sub_destinations: list[SubDestination] = Field(default_factory=list)
|
231
229
|
accessibility_options: Optional[AccessibilityOptions] = None
|
232
230
|
|
233
231
|
# Fuel/EV & AI summaries
|
@@ -239,9 +237,8 @@ class Place(BaseModel):
|
|
239
237
|
neighborhood_summary: Optional[NeighborhoodSummary] = None
|
240
238
|
|
241
239
|
# Context
|
242
|
-
containing_places:
|
240
|
+
containing_places: list[ContainingPlace] = Field(default_factory=list)
|
243
241
|
pure_service_area_business: Optional[bool] = None
|
244
|
-
address_descriptor: Optional[AddressDescriptor] = None
|
245
242
|
price_range: Optional[PriceRange] = None
|
246
243
|
|
247
244
|
# ---------- Validators ----------
|
@@ -273,7 +270,7 @@ class Place(BaseModel):
|
|
273
270
|
|
274
271
|
@field_validator("types")
|
275
272
|
@classmethod
|
276
|
-
def _types(cls, v:
|
273
|
+
def _types(cls, v: list[str]) -> list[str]:
|
277
274
|
out, seen = [], set()
|
278
275
|
for raw in v:
|
279
276
|
t = raw.strip()
|
@@ -324,14 +321,14 @@ class Place(BaseModel):
|
|
324
321
|
|
325
322
|
@field_validator("reviews")
|
326
323
|
@classmethod
|
327
|
-
def _max_reviews(cls, v:
|
324
|
+
def _max_reviews(cls, v: list[Review]) -> list[Review]:
|
328
325
|
if len(v) > 5:
|
329
326
|
raise ValueError("reviews can contain at most 5 items")
|
330
327
|
return v
|
331
328
|
|
332
329
|
@field_validator("photos")
|
333
330
|
@classmethod
|
334
|
-
def _max_photos(cls, v:
|
331
|
+
def _max_photos(cls, v: list[Photo]) -> list[Photo]:
|
335
332
|
if len(v) > 10:
|
336
333
|
raise ValueError("photos can contain at most 10 items")
|
337
334
|
return v
|
@@ -0,0 +1,214 @@
|
|
1
|
+
"""
|
2
|
+
Request models for Book-A-Limo API operations.
|
3
|
+
These models serialize to camelCase by default for API compatibility.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from typing import Optional
|
7
|
+
|
8
|
+
from pydantic import Field, model_validator
|
9
|
+
from typing_extensions import Self
|
10
|
+
|
11
|
+
from .base import RequestModel
|
12
|
+
from .shared import (
|
13
|
+
AccountBase,
|
14
|
+
AddressBase,
|
15
|
+
AirportBase,
|
16
|
+
BreakdownItemBase,
|
17
|
+
CityBase,
|
18
|
+
CreditCardBase,
|
19
|
+
LocationBase,
|
20
|
+
MeetGreetAdditionalBase,
|
21
|
+
MeetGreetBase,
|
22
|
+
PassengerBase,
|
23
|
+
PriceBase,
|
24
|
+
RateType,
|
25
|
+
ReservationBase,
|
26
|
+
RewardBase,
|
27
|
+
StopBase,
|
28
|
+
)
|
29
|
+
|
30
|
+
|
31
|
+
# Request versions of shared models (serialize to camelCase)
|
32
|
+
class City(CityBase, RequestModel):
|
33
|
+
"""City information for requests."""
|
34
|
+
|
35
|
+
pass
|
36
|
+
|
37
|
+
|
38
|
+
class Address(AddressBase, RequestModel):
|
39
|
+
"""Address information for requests."""
|
40
|
+
|
41
|
+
city: Optional[City] = Field(
|
42
|
+
default=None, description="Use only if google_geocode not available"
|
43
|
+
)
|
44
|
+
|
45
|
+
|
46
|
+
class Airport(AirportBase, RequestModel):
|
47
|
+
"""Airport information for requests."""
|
48
|
+
|
49
|
+
arriving_from_city: Optional[City] = None
|
50
|
+
|
51
|
+
|
52
|
+
class Location(LocationBase, RequestModel):
|
53
|
+
"""Location (address or airport) for requests."""
|
54
|
+
|
55
|
+
address: Optional[Address] = None
|
56
|
+
airport: Optional[Airport] = None
|
57
|
+
|
58
|
+
|
59
|
+
class Stop(StopBase, RequestModel):
|
60
|
+
"""Stop information for requests."""
|
61
|
+
|
62
|
+
pass
|
63
|
+
|
64
|
+
|
65
|
+
class Account(AccountBase, RequestModel):
|
66
|
+
"""Travel agency or corporate account info for requests."""
|
67
|
+
|
68
|
+
pass
|
69
|
+
|
70
|
+
|
71
|
+
class Passenger(PassengerBase, RequestModel):
|
72
|
+
"""Passenger information for requests."""
|
73
|
+
|
74
|
+
pass
|
75
|
+
|
76
|
+
|
77
|
+
class Reward(RewardBase, RequestModel):
|
78
|
+
"""Reward account information for requests."""
|
79
|
+
|
80
|
+
pass
|
81
|
+
|
82
|
+
|
83
|
+
class CreditCard(CreditCardBase, RequestModel):
|
84
|
+
"""Credit card information for requests."""
|
85
|
+
|
86
|
+
pass
|
87
|
+
|
88
|
+
|
89
|
+
class BreakdownItem(BreakdownItemBase, RequestModel):
|
90
|
+
"""Price breakdown item for requests."""
|
91
|
+
|
92
|
+
pass
|
93
|
+
|
94
|
+
|
95
|
+
class MeetGreetAdditional(MeetGreetAdditionalBase, RequestModel):
|
96
|
+
"""Additional meet & greet charges for requests."""
|
97
|
+
|
98
|
+
pass
|
99
|
+
|
100
|
+
|
101
|
+
class MeetGreet(MeetGreetBase, RequestModel):
|
102
|
+
"""Meet & greet option for requests."""
|
103
|
+
|
104
|
+
pass
|
105
|
+
|
106
|
+
|
107
|
+
class Price(PriceBase, RequestModel):
|
108
|
+
"""Car class pricing information for requests."""
|
109
|
+
|
110
|
+
pass
|
111
|
+
|
112
|
+
|
113
|
+
class Reservation(ReservationBase, RequestModel):
|
114
|
+
"""Basic reservation information for requests."""
|
115
|
+
|
116
|
+
pass
|
117
|
+
|
118
|
+
|
119
|
+
class EditReservationRequest(RequestModel):
|
120
|
+
"""Editable reservation for modifications (requests)."""
|
121
|
+
|
122
|
+
confirmation: str
|
123
|
+
is_cancel_request: bool = False
|
124
|
+
rate_type: Optional[RateType] = None
|
125
|
+
pickup_date: Optional[str] = Field(default=None, description="MM/dd/yyyy format")
|
126
|
+
pickup_time: Optional[str] = Field(default=None, description="hh:mm tt format")
|
127
|
+
stops: Optional[list[Stop]] = None
|
128
|
+
credit_card: Optional[CreditCard] = None
|
129
|
+
passengers: Optional[int] = None
|
130
|
+
luggage: Optional[int] = None
|
131
|
+
pets: Optional[int] = None
|
132
|
+
car_seats: Optional[int] = None
|
133
|
+
boosters: Optional[int] = None
|
134
|
+
infants: Optional[int] = None
|
135
|
+
other: Optional[str] = Field(default=None, description="Other changes not listed")
|
136
|
+
|
137
|
+
|
138
|
+
# Pure Request Models
|
139
|
+
class PriceRequest(RequestModel):
|
140
|
+
"""Request for getting prices."""
|
141
|
+
|
142
|
+
rate_type: RateType
|
143
|
+
date_time: str = Field(..., description="MM/dd/yyyy hh:mm tt format")
|
144
|
+
pickup: Location
|
145
|
+
dropoff: Location
|
146
|
+
hours: Optional[int] = Field(default=None, description="For hourly rate_type only")
|
147
|
+
passengers: int
|
148
|
+
luggage: int
|
149
|
+
stops: Optional[list[Stop]] = None
|
150
|
+
account: Optional[Account] = Field(
|
151
|
+
default=None, description="TAs must provide for commission"
|
152
|
+
)
|
153
|
+
passenger: Optional[Passenger] = None
|
154
|
+
rewards: Optional[list[Reward]] = None
|
155
|
+
car_class_code: Optional[str] = Field(
|
156
|
+
default=None, description="e.g., 'SD' for specific car class"
|
157
|
+
)
|
158
|
+
pets: Optional[int] = None
|
159
|
+
car_seats: Optional[int] = None
|
160
|
+
boosters: Optional[int] = None
|
161
|
+
infants: Optional[int] = None
|
162
|
+
customer_comment: Optional[str] = None
|
163
|
+
|
164
|
+
|
165
|
+
class DetailsRequest(RequestModel):
|
166
|
+
"""Request for setting reservation details."""
|
167
|
+
|
168
|
+
token: str
|
169
|
+
car_class_code: Optional[str] = None
|
170
|
+
pickup: Optional[Location] = None
|
171
|
+
dropoff: Optional[Location] = None
|
172
|
+
stops: Optional[list[Stop]] = None
|
173
|
+
account: Optional[Account] = None
|
174
|
+
passenger: Optional[Passenger] = None
|
175
|
+
rewards: Optional[list[Reward]] = None
|
176
|
+
pets: Optional[int] = None
|
177
|
+
car_seats: Optional[int] = None
|
178
|
+
boosters: Optional[int] = None
|
179
|
+
infants: Optional[int] = None
|
180
|
+
customer_comment: Optional[str] = None
|
181
|
+
ta_fee: Optional[float] = Field(
|
182
|
+
default=None, description="For Travel Agencies - additional fee in USD"
|
183
|
+
)
|
184
|
+
|
185
|
+
|
186
|
+
class BookRequest(RequestModel):
|
187
|
+
"""Request for booking reservation."""
|
188
|
+
|
189
|
+
token: str
|
190
|
+
promo: Optional[str] = None
|
191
|
+
method: Optional[str] = Field(
|
192
|
+
default=None, description="'charge' for charge accounts"
|
193
|
+
)
|
194
|
+
credit_card: Optional[CreditCard] = None
|
195
|
+
|
196
|
+
@model_validator(mode="after")
|
197
|
+
def validate_book_request(self) -> Self:
|
198
|
+
"""Validate that either method or credit_card is provided."""
|
199
|
+
if not self.method and not self.credit_card:
|
200
|
+
raise ValueError("Either method='charge' or credit_card must be provided")
|
201
|
+
|
202
|
+
return self
|
203
|
+
|
204
|
+
|
205
|
+
class ListReservationsRequest(RequestModel):
|
206
|
+
"""Request for listing reservations."""
|
207
|
+
|
208
|
+
is_archive: bool = False
|
209
|
+
|
210
|
+
|
211
|
+
class GetReservationRequest(RequestModel):
|
212
|
+
"""Request for getting reservation details."""
|
213
|
+
|
214
|
+
confirmation: str
|
@@ -0,0 +1,196 @@
|
|
1
|
+
"""
|
2
|
+
Response models for Book-A-Limo API operations.
|
3
|
+
These models serialize to snake_case by default for better Python DX.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from typing import Optional
|
7
|
+
|
8
|
+
from pydantic import Field
|
9
|
+
|
10
|
+
from .base import ResponseModel
|
11
|
+
from .shared import (
|
12
|
+
AccountBase,
|
13
|
+
AddressBase,
|
14
|
+
AirportBase,
|
15
|
+
BreakdownItemBase,
|
16
|
+
CityBase,
|
17
|
+
CreditCardBase,
|
18
|
+
LocationBase,
|
19
|
+
LocationType,
|
20
|
+
MeetGreetAdditionalBase,
|
21
|
+
MeetGreetBase,
|
22
|
+
PassengerBase,
|
23
|
+
PriceBase,
|
24
|
+
RateType,
|
25
|
+
ReservationBase,
|
26
|
+
ReservationStatus,
|
27
|
+
RewardBase,
|
28
|
+
StopBase,
|
29
|
+
)
|
30
|
+
|
31
|
+
|
32
|
+
# Response versions of shared models (serialize to snake_case)
|
33
|
+
class City(CityBase, ResponseModel):
|
34
|
+
"""City information for responses."""
|
35
|
+
|
36
|
+
pass
|
37
|
+
|
38
|
+
|
39
|
+
class Address(AddressBase, ResponseModel):
|
40
|
+
"""Address information for responses."""
|
41
|
+
|
42
|
+
city: Optional[City] = Field(
|
43
|
+
default=None, description="Use only if google_geocode not available"
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
class Airport(AirportBase, ResponseModel):
|
48
|
+
"""Airport information for responses."""
|
49
|
+
|
50
|
+
arriving_from_city: Optional[City] = None
|
51
|
+
|
52
|
+
|
53
|
+
class Location(LocationBase, ResponseModel):
|
54
|
+
"""Location (address or airport) for responses."""
|
55
|
+
|
56
|
+
address: Optional[Address] = None
|
57
|
+
airport: Optional[Airport] = None
|
58
|
+
|
59
|
+
|
60
|
+
class Stop(StopBase, ResponseModel):
|
61
|
+
"""Stop information for responses."""
|
62
|
+
|
63
|
+
pass
|
64
|
+
|
65
|
+
|
66
|
+
class Account(AccountBase, ResponseModel):
|
67
|
+
"""Travel agency or corporate account info for responses."""
|
68
|
+
|
69
|
+
pass
|
70
|
+
|
71
|
+
|
72
|
+
class Passenger(PassengerBase, ResponseModel):
|
73
|
+
"""Passenger information for responses."""
|
74
|
+
|
75
|
+
pass
|
76
|
+
|
77
|
+
|
78
|
+
class Reward(RewardBase, ResponseModel):
|
79
|
+
"""Reward account information for responses."""
|
80
|
+
|
81
|
+
pass
|
82
|
+
|
83
|
+
|
84
|
+
class CreditCard(CreditCardBase, ResponseModel):
|
85
|
+
"""Credit card information for responses."""
|
86
|
+
|
87
|
+
pass
|
88
|
+
|
89
|
+
|
90
|
+
class BreakdownItem(BreakdownItemBase, ResponseModel):
|
91
|
+
"""Price breakdown item for responses."""
|
92
|
+
|
93
|
+
pass
|
94
|
+
|
95
|
+
|
96
|
+
class MeetGreetAdditional(MeetGreetAdditionalBase, ResponseModel):
|
97
|
+
"""Additional meet & greet charges for responses."""
|
98
|
+
|
99
|
+
pass
|
100
|
+
|
101
|
+
|
102
|
+
class MeetGreet(MeetGreetBase, ResponseModel):
|
103
|
+
"""Meet & greet option for responses."""
|
104
|
+
|
105
|
+
pass
|
106
|
+
|
107
|
+
|
108
|
+
class CarClassPrice(PriceBase, ResponseModel):
|
109
|
+
"""Car class pricing information for responses."""
|
110
|
+
|
111
|
+
pass
|
112
|
+
|
113
|
+
|
114
|
+
class Reservation(ReservationBase, ResponseModel):
|
115
|
+
"""Basic reservation information for responses."""
|
116
|
+
|
117
|
+
pass
|
118
|
+
|
119
|
+
|
120
|
+
# Pure Response Models
|
121
|
+
class ReservationData(ResponseModel):
|
122
|
+
"""Editable reservation data returned in get reservation response."""
|
123
|
+
|
124
|
+
confirmation: str
|
125
|
+
is_cancel_request: bool = False
|
126
|
+
rate_type: Optional[RateType] = None
|
127
|
+
pickup_date: Optional[str] = Field(default=None, description="MM/dd/yyyy format")
|
128
|
+
pickup_time: Optional[str] = Field(default=None, description="hh:mm tt format")
|
129
|
+
stops: Optional[list[Stop]] = None
|
130
|
+
credit_card: Optional[CreditCard] = Field(
|
131
|
+
default=None,
|
132
|
+
description="Conditionally required - unclear from API docs when exactly",
|
133
|
+
)
|
134
|
+
passengers: Optional[int] = None
|
135
|
+
luggage: Optional[int] = None
|
136
|
+
pets: Optional[int] = None
|
137
|
+
car_seats: Optional[int] = None
|
138
|
+
boosters: Optional[int] = None
|
139
|
+
infants: Optional[int] = None
|
140
|
+
other: Optional[str] = Field(default=None, description="Other changes not listed")
|
141
|
+
|
142
|
+
|
143
|
+
class PriceResponse(ResponseModel):
|
144
|
+
"""Response from get prices."""
|
145
|
+
|
146
|
+
token: str
|
147
|
+
prices: list[CarClassPrice]
|
148
|
+
|
149
|
+
|
150
|
+
class DetailsResponse(ResponseModel):
|
151
|
+
"""Response from set details."""
|
152
|
+
|
153
|
+
price: float
|
154
|
+
breakdown: list[BreakdownItem]
|
155
|
+
|
156
|
+
|
157
|
+
class BookResponse(ResponseModel):
|
158
|
+
"""Response from book reservation."""
|
159
|
+
|
160
|
+
reservation_id: str
|
161
|
+
|
162
|
+
|
163
|
+
class ListReservationsResponse(ResponseModel):
|
164
|
+
"""Response from list reservations."""
|
165
|
+
|
166
|
+
success: bool
|
167
|
+
reservations: list[Reservation] = Field(default_factory=list)
|
168
|
+
error: Optional[str] = None
|
169
|
+
|
170
|
+
|
171
|
+
class GetReservationResponse(ResponseModel):
|
172
|
+
"""Response from get reservation."""
|
173
|
+
|
174
|
+
reservation: "ReservationData"
|
175
|
+
is_editable: bool
|
176
|
+
status: Optional[ReservationStatus] = None
|
177
|
+
is_cancellation_pending: bool
|
178
|
+
car_description: Optional[str] = None
|
179
|
+
cancellation_policy: Optional[str] = None
|
180
|
+
pickup_type: LocationType
|
181
|
+
pickup_description: str
|
182
|
+
dropoff_type: LocationType
|
183
|
+
dropoff_description: str
|
184
|
+
additional_services: Optional[str] = None
|
185
|
+
payment_method: Optional[str] = None
|
186
|
+
breakdown: list[BreakdownItem] = Field(default_factory=list)
|
187
|
+
passenger_name: Optional[str] = None
|
188
|
+
evoucher_url: Optional[str] = None
|
189
|
+
receipt_url: Optional[str] = None
|
190
|
+
pending_changes: list[list[str]] = Field(default_factory=list)
|
191
|
+
|
192
|
+
|
193
|
+
class EditReservationResponse(ResponseModel):
|
194
|
+
"""Response from edit reservation."""
|
195
|
+
|
196
|
+
success: bool
|