Skip to content
This repository was archived by the owner on Sep 12, 2024. It is now read-only.

Commit 3920062

Browse files
author
Jesse Claven
authored
Merge pull request #106 from duffelhq/correct-nullable-offer-payment-requirements-field
Correct Offer.PaymentRequirements fields being nullable
2 parents 7a71aa6 + 39d53e4 commit 3920062

File tree

3 files changed

+252
-6
lines changed

3 files changed

+252
-6
lines changed

duffel_api/models/offer.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,23 @@ def from_json(cls, json: dict):
8686
class PaymentRequirements:
8787
"""The payment requirements for an offer"""
8888

89-
payment_required_by: datetime
90-
price_guarantee_expires_at: datetime
89+
payment_required_by: Optional[datetime]
90+
price_guarantee_expires_at: Optional[datetime]
9191
requires_instant_payment: bool
9292

9393
@classmethod
9494
def from_json(cls, json: dict):
9595
"""Construct a class instance from a JSON response."""
9696
return cls(
97-
payment_required_by=datetime.strptime(
98-
json["payment_required_by"], "%Y-%m-%dT%H:%M:%SZ"
97+
payment_required_by=get_and_transform(
98+
json,
99+
"payment_required_by",
100+
lambda value: datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ"),
99101
),
100-
price_guarantee_expires_at=datetime.strptime(
101-
json["price_guarantee_expires_at"], "%Y-%m-%dT%H:%M:%SZ"
102+
price_guarantee_expires_at=get_and_transform(
103+
json,
104+
"price_guarantee_expires_at",
105+
lambda value: datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ"),
102106
),
103107
requires_instant_payment=json["requires_instant_payment"],
104108
)
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
{
2+
"data": {
3+
"allowed_passenger_identity_document_types": [
4+
"passport"
5+
],
6+
"available_payment_types": "payments",
7+
"available_services": [
8+
{
9+
"id": "ase_00009UhD4ongolulWd9123",
10+
"maximum_quantity": 1,
11+
"metadata": {
12+
"type": "checked"
13+
},
14+
"passenger_ids": [
15+
"pas_00009hj8USM7Ncg31cBCLL"
16+
],
17+
"segment_ids": [
18+
"seg_00009hj8USM7Ncg31cB456"
19+
],
20+
"total_amount": "15.00",
21+
"total_currency": "GBP",
22+
"type": "baggage"
23+
}
24+
],
25+
"base_amount": "30.20",
26+
"base_currency": "GBP",
27+
"conditions": {
28+
"change_before_departure": {
29+
"allowed": true,
30+
"penalty_amount": "100.00",
31+
"penalty_currency": "GBP"
32+
},
33+
"refund_before_departure": {
34+
"allowed": true,
35+
"penalty_amount": "100.00",
36+
"penalty_currency": "GBP"
37+
}
38+
},
39+
"created_at": "2020-01-17T10:12:14.545Z",
40+
"expires_at": "2020-01-17T10:42:14.545Z",
41+
"id": "off_00009htYpSCXrwaB9DnUm0",
42+
"live_mode": true,
43+
"owner": {
44+
"iata_code": "BA",
45+
"id": "aln_00001876aqC8c5umZmrRds",
46+
"name": "British Airways"
47+
},
48+
"passenger_identity_documents_required": false,
49+
"passengers": [
50+
{
51+
"age": 14,
52+
"id": "pas_00009hj8USM7Ncg31cBCL",
53+
"type": "adult"
54+
}
55+
],
56+
"payment_requirements": {
57+
"payment_required_by": null,
58+
"price_guarantee_expires_at": null,
59+
"requires_instant_payment": false
60+
},
61+
"slices": [
62+
{
63+
"conditions": {
64+
"change_before_departure": {
65+
"allowed": true,
66+
"penalty_amount": "100.00",
67+
"penalty_currency": "GBP"
68+
}
69+
},
70+
"destination": {
71+
"airports": [
72+
{
73+
"city": {
74+
"iata_code": "NYC",
75+
"iata_country_code": "US",
76+
"id": "cit_nyc_us",
77+
"name": "New York"
78+
},
79+
"city_name": "New York",
80+
"iata_code": "JFK",
81+
"iata_country_code": "US",
82+
"icao_code": "KJFK",
83+
"id": "arp_jfk_us",
84+
"latitude": 40.640556,
85+
"longitude": -73.778519,
86+
"name": "John F. Kennedy International Airport",
87+
"time_zone": "America/New_York"
88+
}
89+
],
90+
"city": {
91+
"iata_code": "NYC",
92+
"iata_country_code": "US",
93+
"id": "cit_nyc_us",
94+
"name": "New York"
95+
},
96+
"city_name": "New York",
97+
"iata_city_code": "NYC",
98+
"iata_code": "JFK",
99+
"iata_country_code": "US",
100+
"icao_code": "KJFK",
101+
"id": "arp_jfk_us",
102+
"latitude": 40.640556,
103+
"longitude": -73.778519,
104+
"name": "John F. Kennedy International Airport",
105+
"time_zone": "America/New_York",
106+
"type": "airport"
107+
},
108+
"destination_type": "airport",
109+
"duration": "PT02H26M",
110+
"fare_brand_name": "Basic",
111+
"id": "sli_00009htYpSCXrwaB9Dn123",
112+
"origin": {
113+
"airports": [
114+
{
115+
"city": {
116+
"iata_code": "LON",
117+
"iata_country_code": "GB",
118+
"id": "cit_lon_gb",
119+
"name": "London"
120+
},
121+
"city_name": "London",
122+
"iata_code": "LHR",
123+
"iata_country_code": "GB",
124+
"icao_code": "EGLL",
125+
"id": "arp_lhr_gb",
126+
"latitude": 64.068865,
127+
"longitude": -141.951519,
128+
"name": "Heathrow",
129+
"time_zone": "Europe/London"
130+
}
131+
],
132+
"city": {
133+
"iata_code": "LON",
134+
"iata_country_code": "GB",
135+
"id": "cit_lon_gb",
136+
"name": "London"
137+
},
138+
"city_name": "London",
139+
"iata_city_code": "LON",
140+
"iata_code": "LHR",
141+
"iata_country_code": "GB",
142+
"icao_code": "EGLL",
143+
"id": "arp_lhr_gb",
144+
"latitude": 64.068865,
145+
"longitude": -141.951519,
146+
"name": "Heathrow",
147+
"time_zone": "Europe/London",
148+
"type": "airport"
149+
},
150+
"origin_type": "airport",
151+
"segments": [
152+
{
153+
"aircraft": {
154+
"iata_code": "380",
155+
"id": "arc_00009UhD4ongolulWd91Ky",
156+
"name": "Airbus Industries A380"
157+
},
158+
"arriving_at": "2020-06-13T16:38:02",
159+
"departing_at": "2020-06-13T16:38:02",
160+
"destination": {
161+
"city": {
162+
"iata_code": "NYC",
163+
"iata_country_code": "US",
164+
"id": "cit_nyc_us",
165+
"name": "New York"
166+
},
167+
"city_name": "New York",
168+
"iata_code": "JFK",
169+
"iata_country_code": "US",
170+
"icao_code": "KJFK",
171+
"id": "arp_jfk_us",
172+
"latitude": 40.640556,
173+
"longitude": -73.778519,
174+
"name": "John F. Kennedy International Airport",
175+
"time_zone": "America/New_York"
176+
},
177+
"destination_terminal": "5",
178+
"distance": "424.2",
179+
"duration": "PT02H26M",
180+
"id": "seg_00009htYpSCXrwaB9Dn456",
181+
"marketing_carrier": {
182+
"iata_code": "BA",
183+
"id": "aln_00001876aqC8c5umZmrRds",
184+
"name": "British Airways"
185+
},
186+
"marketing_carrier_flight_number": "1234",
187+
"operating_carrier": {
188+
"iata_code": "BA",
189+
"id": "aln_00001876aqC8c5umZmrRds",
190+
"name": "British Airways"
191+
},
192+
"operating_carrier_flight_number": "4321",
193+
"origin": {
194+
"city": {
195+
"iata_code": "LON",
196+
"iata_country_code": "GB",
197+
"id": "cit_lon_gb",
198+
"name": "London"
199+
},
200+
"city_name": "London",
201+
"iata_code": "LHR",
202+
"iata_country_code": "GB",
203+
"icao_code": "EGLL",
204+
"id": "arp_lhr_gb",
205+
"latitude": 64.068865,
206+
"longitude": -141.951519,
207+
"name": "Heathrow",
208+
"time_zone": "Europe/London"
209+
},
210+
"origin_terminal": "B",
211+
"passengers": [
212+
{
213+
"baggages": [
214+
{
215+
"quantity": 1,
216+
"type": "checked"
217+
}
218+
],
219+
"cabin_class": "economy",
220+
"cabin_class_marketing_name": "Economy Basic",
221+
"fare_basis_code": "OXZ0RO",
222+
"passenger_id": "passenger_0"
223+
}
224+
]
225+
}
226+
]
227+
}
228+
],
229+
"tax_amount": "40.80",
230+
"tax_currency": "GBP",
231+
"total_amount": "45.00",
232+
"total_currency": "GBP",
233+
"total_emissions_kg": "460",
234+
"updated_at": "2020-01-17T10:12:14.545Z"
235+
}
236+
}

tests/test_offer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ def test_offer_model_parsing():
77
name = "get-offer-by-id"
88
with raw_fixture(name) as fixture:
99
assert Offer.from_json(fixture["data"])
10+
11+
12+
def test_offer_model_parsing_with_nullable_payment_requirements():
13+
name = "get-offer-by-id-with-null-payment-requirements"
14+
with raw_fixture(name) as fixture:
15+
assert Offer.from_json(fixture["data"])

0 commit comments

Comments
 (0)