bookalimo 1.0.1__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/integrations/google_places/client_async.py +56 -102
- bookalimo/integrations/google_places/client_sync.py +56 -100
- bookalimo/integrations/google_places/common.py +290 -12
- bookalimo/integrations/google_places/resolve_airport.py +148 -119
- bookalimo/integrations/google_places/transports.py +14 -7
- bookalimo/logging.py +103 -0
- bookalimo/schemas/__init__.py +121 -35
- bookalimo/schemas/base.py +74 -14
- bookalimo/schemas/places/__init__.py +3 -1
- bookalimo/schemas/places/common.py +1 -1
- bookalimo/schemas/places/field_mask.py +0 -9
- bookalimo/schemas/places/google.py +165 -10
- 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.1.dist-info/METADATA +0 -370
- bookalimo-1.0.1.dist-info/RECORD +0 -38
- {bookalimo-1.0.1.dist-info → bookalimo-1.0.2.dist-info}/WHEEL +0 -0
- {bookalimo-1.0.1.dist-info → bookalimo-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {bookalimo-1.0.1.dist-info → bookalimo-1.0.2.dist-info}/top_level.txt +0 -0
@@ -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
|