Skip to content

Commit 9091e19

Browse files
authored
Merge pull request #34 from PurplShip/CollectDeliveryEstimates
Collect delivery estimates
2 parents 604cbd3 + a362787 commit 9091e19

File tree

30 files changed

+1100
-1205
lines changed

30 files changed

+1100
-1205
lines changed

purplship/domain/Types/datatypes.py

Lines changed: 53 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""PurplShip Unified datatypes module."""
22
from typing import List, NamedTuple, Dict
3+
import attr
34

45

56
class party(NamedTuple):
@@ -182,155 +183,98 @@ class pickup_cancellation_request(NamedTuple):
182183
""" Generic response data types """
183184

184185

186+
@attr.s(auto_attribs=True)
185187
class Error:
186188
"""PurplShip Error type."""
187189

188-
def __init__(self, message: str = None, code: str = None, carrier: str = None):
189-
"""Error type constructor."""
190-
self.message = message
191-
self.code = code
192-
self.carrier = carrier
190+
message: str = None
191+
code: str = None
192+
carrier: str = None
193193

194194

195+
@attr.s(auto_attribs=True)
195196
class ChargeDetails:
196197
"""PurplShip charge type."""
197198

198-
def __init__(self, name: str = None, amount: float = None, currency: str = None):
199-
"""Charge details type constructor."""
200-
self.name = name
201-
self.amount = amount
202-
self.currency = currency
199+
name: str = None
200+
amount: float = None
201+
currency: str = None
203202

204203

204+
@attr.s(auto_attribs=True)
205205
class ReferenceDetails:
206206
"""PurplShip reference details type."""
207207

208-
def __init__(self, value: str, type: str = None):
209-
"""Purplship Reference details type constructor."""
210-
self.value = value
211-
self.type = type
208+
value: str
209+
type: str = None
212210

213211

212+
@attr.s(auto_attribs=True)
214213
class TimeDetails:
215214
"""PurplShip time details type."""
216215

217-
def __init__(self, value: str, name: str = None):
218-
"""Time details type constructor."""
219-
self.value = value
220-
self.name = name
216+
value: str
217+
name: str = None
221218

222219

220+
@attr.s(auto_attribs=True)
223221
class TrackingEvent:
224222
"""PurplShip tracking event type."""
225223

226-
def __init__(
227-
self,
228-
date: str,
229-
description: str,
230-
location: str,
231-
code: str,
232-
time: str = None,
233-
signatory: str = None,
234-
):
235-
"""Tracking event type constructor."""
236-
self.date = date
237-
self.time = time
238-
self.description = description
239-
self.location = location
240-
self.code = code
241-
self.signatory = signatory
224+
date: str
225+
description: str
226+
location: str
227+
code: str
228+
time: str = None
229+
signatory: str = None
242230

243231

232+
@attr.s(auto_attribs=True)
244233
class QuoteDetails:
245234
"""PurplShip quote details type."""
246235

247-
def __init__(
248-
self,
249-
carrier: str,
250-
service_name: str,
251-
service_type: str,
252-
base_charge: float,
253-
duties_and_taxes: float,
254-
total_charge: float,
255-
currency: str,
256-
pickup_time: str = None,
257-
delivery_date: str = None,
258-
pickup_date: str = None,
259-
discount: float = None,
260-
extra_charges: List[ChargeDetails] = [],
261-
):
262-
"""Quotes details type constructor."""
263-
self.carrier = carrier
264-
self.service_name = service_name
265-
self.service_type = service_type
266-
self.base_charge = base_charge
267-
self.duties_and_taxes = duties_and_taxes
268-
self.total_charge = total_charge
269-
self.currency = currency
270-
self.discount = discount
271-
self.extra_charges = extra_charges
272-
273-
self.pickup_time = pickup_time
274-
self.delivery_date = delivery_date
275-
self.pickup_date = pickup_date
236+
carrier: str
237+
service_name: str
238+
service_type: str
239+
base_charge: float
240+
duties_and_taxes: float
241+
total_charge: float
242+
currency: str
243+
delivery_date: str = None
244+
discount: float = None
245+
extra_charges: List[ChargeDetails] = []
276246

277247

248+
@attr.s(auto_attribs=True)
278249
class TrackingDetails:
279250
"""PurplShip tracking details type."""
280251

281-
def __init__(
282-
self,
283-
carrier: str,
284-
tracking_number: str,
285-
shipment_date: str = None,
286-
events: List[TrackingEvent] = [],
287-
):
288-
"""Tracking details type constructor."""
289-
self.carrier = carrier
290-
self.events = events
291-
self.shipment_date = shipment_date
292-
self.tracking_number = tracking_number
252+
carrier: str
253+
tracking_number: str
254+
shipment_date: str = None
255+
events: List[TrackingEvent] = []
293256

294257

258+
@attr.s(auto_attribs=True)
295259
class ShipmentDetails:
296260
"""PurplShip shipment details type."""
297261

298-
def __init__(
299-
self,
300-
carrier: str,
301-
tracking_numbers: List[str],
302-
total_charge: ChargeDetails,
303-
charges: List[ChargeDetails],
304-
shipment_date: str = None,
305-
services: List[str] = None,
306-
documents: List[str] = [],
307-
reference: ReferenceDetails = None,
308-
):
309-
"""Shipment details type constructor."""
310-
self.carrier = carrier
311-
self.tracking_numbers = tracking_numbers
312-
self.shipment_date = shipment_date
313-
self.documents = documents
314-
self.services = services
315-
self.reference = reference
316-
self.total_charge = total_charge
317-
self.charges = charges
262+
carrier: str
263+
tracking_numbers: List[str]
264+
total_charge: ChargeDetails
265+
charges: List[ChargeDetails]
266+
shipment_date: str = None
267+
services: List[str] = None
268+
documents: List[str] = []
269+
reference: ReferenceDetails = None
318270

319271

272+
@attr.s(auto_attribs=True)
320273
class PickupDetails:
321274
"""PurplShip pickup details type."""
322275

323-
def __init__(
324-
self,
325-
carrier: str,
326-
confirmation_number: str,
327-
pickup_date: str = None,
328-
pickup_charge: ChargeDetails = None,
329-
ref_times: List[TimeDetails] = None,
330-
):
331-
"""Pickup details type constructor."""
332-
self.carrier = carrier
333-
self.confirmation_number = confirmation_number
334-
self.pickup_date = pickup_date
335-
self.pickup_charge = pickup_charge
336-
self.ref_times = ref_times
276+
carrier: str
277+
confirmation_number: str
278+
pickup_date: str = None
279+
pickup_charge: ChargeDetails = None
280+
ref_times: List[TimeDetails] = None

purplship/mappers/caps/caps_mapper/partials/rate.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ def create_mailing_scenario(self, payload: T.shipment_request) -> mailing_scenar
8383
contract_id=payload.shipment.extra.get("contract-id"),
8484
promo_code=payload.shipment.extra.get("promo-code"),
8585
quote_type=payload.shipment.extra.get("quote-type"),
86-
expected_mailing_date=payload.shipment.extra.get("expected-mailing-date"),
86+
expected_mailing_date=(
87+
payload.shipment.extra.get("expected-mailing-date") or
88+
datetime.today().strftime('%Y-%m-%d')
89+
),
8790
options=optionsType(
8891
option=[
8992
optionType(

purplship/mappers/dhl/dhl_mapper/partials/rate.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ def _extract_quote(
4848
carrier=self.client.carrier_name,
4949
currency=qtdshp.CurrencyCode,
5050
delivery_date=str(qtdshp.DeliveryDate[0].DlvyDateTime),
51-
pickup_date=str(qtdshp.PickupDate),
52-
pickup_time=str(qtdshp.PickupCutoffTime),
5351
service_name=qtdshp.LocalProductName,
5452
service_type=qtdshp.NetworkTypeCode,
5553
base_charge=float(qtdshp.WeightCharge or 0),

purplship/mappers/ups/ups_mapper/partials/rate.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import time
21
from lxml import etree
32
from pyups import freight_rate as Rate, package_rate as PRate, common as Common
43
from .interface import reduce, Tuple, List, T, UPSMapperBase
@@ -94,6 +93,12 @@ def _extract_package_rate(
9493

9594
extra_charges = itemized_charges + [rate.ServiceOptionsCharges]
9695

96+
arrival = PRate.PickupType()
97+
[
98+
arrival.build(arrival) for arrival in
99+
detailNode.xpath(".//*[local-name() = $name]", name="Arrival")
100+
]
101+
97102
return rates + [
98103
T.QuoteDetails(
99104
carrier=self.client.carrier_name,
@@ -120,6 +125,7 @@ def _extract_package_rate(
120125
[charge for charge in extra_charges if charge != None],
121126
[],
122127
),
128+
delivery_date=str(arrival.Date)
123129
)
124130
]
125131

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
license='LGPL',
1515
packages=find_packages(".", exclude=["tests"]),
1616
install_requires=[
17+
'attrs==18.2.0',
1718
'py-fedex==1.1',
1819
'py-dhl==1.2',
1920
'py-soap==1.1',

tests/caps/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from tests.caps.tracking import *
22
from tests.caps.quote import *
33
from tests.caps.shipment import *
4-
from tests.caps.pickup import *
4+
from tests.caps.pickup import *

tests/caps/fixture.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from purplship.mappers.caps import CanadaPostClient, CanadaPostProxy
22

3-
proxy = CanadaPostProxy(CanadaPostClient(
4-
server_url="https://ct.soa-gw.canadapost.ca",
5-
username="username",
6-
password="password",
7-
customer_number="1234567"
8-
))
3+
proxy = CanadaPostProxy(
4+
CanadaPostClient(
5+
server_url="https://ct.soa-gw.canadapost.ca",
6+
username="username",
7+
password="password",
8+
customer_number="1234567",
9+
)
10+
)

tests/caps/pickup.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ def setUp(self):
1212
self.PickupRequest = PickupRequestDetailsType()
1313
self.PickupRequest.build(to_xml(PickupRequestXml))
1414

15-
@patch("purplship.mappers.caps.caps_proxy.http", return_value='<a></a>')
15+
@patch("purplship.mappers.caps.caps_proxy.http", return_value="<a></a>")
1616
def test_request_pickup(self, http_mock):
1717
proxy.request_pickup(self.PickupRequest)
1818

19-
xmlStr = http_mock.call_args[1]['data'].decode("utf-8")
19+
xmlStr = http_mock.call_args[1]["data"].decode("utf-8")
2020
self.assertEqual(strip(xmlStr), strip(PickupRequestXml))
2121

22-
@patch.object(proxy, 'request_pickup')
22+
@patch.object(proxy, "request_pickup")
2323
def test_modify_pickup(self, proxy_mock):
2424
proxy.modify_pickup(self.PickupRequest)
2525

2626
proxy_mock.assert_called()
2727

2828

29-
if __name__ == '__main__':
29+
if __name__ == "__main__":
3030
unittest.main()
3131

3232
PickupRequestXml = """<pickup-request-details xmlns="http://www.canadapost.ca/ws/pickuprequest">

0 commit comments

Comments
 (0)