Skip to content

Commit a97ede5

Browse files
authored
Merge pull request #141 from purplship/purplship-sdk-2021.8
[release-candidate] purplship sdk 2021.8
2 parents c944302 + 696bab2 commit a97ede5

File tree

170 files changed

+4829
-666
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+4829
-666
lines changed

.vscode/settings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"editor.formatOnPaste": true,
3+
"python.terminal.activateEnvInCurrentTerminal": true,
4+
"editor.formatOnSave": true,
5+
"python.formatting.provider": "black",
6+
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/purplship",
7+
"python.linting.mypyEnabled": true,
8+
"python.linting.enabled": true,
9+
}

extensions/aramex/purplship/providers/aramex/error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def parse_error_response(response: Element, settings: Settings) -> List[Message]
1111

1212

1313
def _extract_error(node: Element, settings: Settings) -> Message:
14-
notification = XP.build(Notification, node)
14+
notification = XP.to_object(Notification, node)
1515

1616
return Message(
1717
# context info

extensions/aramex/purplship/providers/aramex/tracking.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
def parse_tracking_response(response, settings: Settings) -> Tuple[List[TrackingDetails], List[Message]]:
2828
non_existents = next(
29-
(XP.build(ArrayOfstring, n) for n in response.xpath(".//*[local-name() = $name]", name="NonExistingWaybills")),
29+
(XP.to_object(ArrayOfstring, n) for n in response.xpath(".//*[local-name() = $name]", name="NonExistingWaybills")),
3030
ArrayOfstring()
3131
)
3232
results = response.xpath(".//*[local-name() = $name]", name="TrackingResult")
@@ -49,7 +49,7 @@ def _extract_errors(non_existents: ArrayOfstring, settings: Settings) -> List[Me
4949

5050

5151
def _extract_detail(node: Element, settings: Settings) -> TrackingDetails:
52-
detail = XP.build(TrackingResult, node)
52+
detail = XP.to_object(TrackingResult, node)
5353

5454
return TrackingDetails(
5555
carrier_name=settings.carrier_name,

extensions/aramex/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[tool.poetry]
22
name = "purplship.aramex"
3-
version = "2021.7"
3+
version = "2021.8"
44
homepage="https://sdk.purplship.com"
5-
repository="https://github.com/Purplship/purplship"
5+
repository="https://github.com/purplship/purplship"
66
description = "Purplship - Aramex Shipping Extension"
77
authors = ["Dan Kobina <danielkobina@gmail.com>"]
88
license = "LGPLv3"

extensions/asendia_us/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# purplship.asendia_us
2+
3+
This package is a Asendia US extension of the [purplship](https://pypi.org/project/purplship) multi carrier shipping SDK.
4+
5+
## Requirements
6+
7+
`Python 3.7+`
8+
9+
## Installation
10+
11+
```bash
12+
pip install purplship.asendia_us
13+
```
14+
15+
## Usage
16+
17+
```python
18+
import purplship
19+
from purplship.mappers.asendia_us.settings import Settings
20+
21+
22+
# Initialize a carrier gateway
23+
canadapost = purplship.gateway["asendia_us"].create(
24+
Settings(
25+
...
26+
)
27+
)
28+
```
29+
30+
Check the [Purplship Mutli-carrier SDK docs](https://sdk.purplship.com) for Shipping API requests
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from purplship.core.metadata import Metadata
2+
3+
from purplship.mappers.asendia_us.mapper import Mapper
4+
from purplship.mappers.asendia_us.proxy import Proxy
5+
from purplship.mappers.asendia_us.settings import Settings
6+
# import purplship.providers.asendia_us.units as units
7+
8+
9+
METADATA = Metadata(
10+
id="asendia_us",
11+
label="Asendia US",
12+
13+
# Integrations
14+
Mapper=Mapper,
15+
Proxy=Proxy,
16+
Settings=Settings,
17+
18+
# Data Units
19+
# options=units.OptionCode,
20+
# package_presets=units.PackagePresets,
21+
# packaging_types=units.PackagingType,
22+
# services=units.Serives,
23+
)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from typing import List, Tuple
2+
from purplship.core.utils.serializable import Serializable, Deserializable
3+
from purplship.api.mapper import Mapper as BaseMapper
4+
from purplship.core.models import (
5+
AddressValidationRequest,
6+
ShipmentCancelRequest,
7+
ShipmentRequest,
8+
TrackingRequest,
9+
RateRequest,
10+
11+
ConfirmationDetails,
12+
TrackingDetails,
13+
ShipmentDetails,
14+
RateDetails,
15+
Message,
16+
)
17+
from purplship.providers.asendia_us import (
18+
parse_shipment_cancel_response,
19+
parse_shipment_response,
20+
parse_tracking_response,
21+
parse_rate_response,
22+
23+
shipment_cancel_request,
24+
tracking_request,
25+
shipment_request,
26+
rate_request,
27+
)
28+
from purplship.mappers.asendia_us.settings import Settings
29+
30+
31+
class Mapper(BaseMapper):
32+
settings: Settings
33+
34+
def create_rate_request(
35+
self, payload: RateRequest
36+
) -> Serializable:
37+
return rate_request(payload, self.settings)
38+
39+
def create_shipment_request(
40+
self, payload: ShipmentRequest
41+
) -> Serializable:
42+
return shipment_request(payload, self.settings)
43+
44+
def create_cancel_shipment_request(self, payload: ShipmentCancelRequest) -> Serializable:
45+
return shipment_cancel_request(payload, self.settings)
46+
47+
def create_tracking_request(
48+
self, payload: TrackingRequest
49+
) -> Serializable:
50+
return tracking_request(payload, self.settings)
51+
52+
def parse_rate_response(
53+
self, response: Deserializable[str]
54+
) -> Tuple[List[RateDetails], List[Message]]:
55+
return parse_rate_response(response.deserialize(), self.settings)
56+
57+
def parse_shipment_response(
58+
self, response: Deserializable[str]
59+
) -> Tuple[ShipmentDetails, List[Message]]:
60+
return parse_shipment_response(response.deserialize(), self.settings)
61+
62+
def parse_cancel_shipment_response(
63+
self, response: Deserializable[str]
64+
) -> Tuple[ConfirmationDetails, List[Message]]:
65+
return parse_shipment_cancel_response(response.deserialize(), self.settings)
66+
67+
def parse_tracking_response(
68+
self, response: Deserializable[str]
69+
) -> Tuple[List[TrackingDetails], List[Message]]:
70+
return parse_tracking_response(response.deserialize(), self.settings)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import base64
2+
import urllib.parse
3+
from typing import List, Tuple
4+
from purplship.core.utils import DP, Serializable, Deserializable, request as http, exec_async
5+
from purplship.api.proxy import Proxy as BaseProxy
6+
from purplship.mappers.asendia_us.settings import Settings
7+
8+
9+
class Proxy(BaseProxy):
10+
settings: Settings
11+
12+
def _request(self, path: str, method: str = "GET", **kwargs):
13+
return http(
14+
url=f"{self.settings.server_url}{path}",
15+
headers={
16+
"Accept": "application/json",
17+
"Authorization": f"Basic {self.settings.authorization}"
18+
},
19+
method=method,
20+
**kwargs
21+
)
22+
23+
# Proxy Methods
24+
25+
def get_tracking(self, request: Serializable) -> Deserializable[List[str]]:
26+
def _get_tracking(ref: str):
27+
return self._request(
28+
f"/api/A1/v1.0/Tracking/Milestone?trackingNumberVendor={ref}")
29+
30+
responses: List[str] = exec_async(_get_tracking, request.serialize())
31+
32+
return Deserializable(
33+
responses,
34+
lambda res: [DP.to_dict(track) for track in res if any(track.strip())]
35+
)
36+
37+
def get_rates(self, request: Serializable) -> Deserializable[str]:
38+
query = urllib.parse.urlencode(request.serialize())
39+
response = self._request(
40+
f"/api/A1/v1.0/ShippingPlatform/ShippingRate?{query}")
41+
42+
return Deserializable(response, DP.to_dict)
43+
44+
def create_shipment(self, request: Serializable) -> Deserializable[str]:
45+
response = self._request(
46+
f"/api/A1/v1.0/ShippingPlatform/Package", "POST",
47+
data=bytearray(request.serialize(), "utf-8")
48+
)
49+
50+
return Deserializable(response, DP.to_dict)
51+
52+
def cancel_shipment(self, request: Serializable) -> Deserializable[Tuple[str, dict]]:
53+
data = request.serialize()
54+
query = urllib.parse.urlencode(data)
55+
response = self._request(
56+
f"/api/A1/v1.0/ShippingPlatform/Package?{query}", "DELETE")
57+
58+
def deserialize(response: str) -> Tuple[str, dict]:
59+
content = DP.to_dict(response)
60+
labelUrl = next(
61+
(label['content'] for label in (content.get("packageLabel") or {}).get("labels") or []),
62+
None
63+
)
64+
65+
if labelUrl is not None:
66+
label = self._request(
67+
labelUrl, decoder=lambda b: base64.encodebytes(b).decode("utf-8"))
68+
69+
return label, content
70+
71+
return None, content
72+
73+
return Deserializable(response, deserialize)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""Purplship Asendia US settings."""
2+
3+
import attr
4+
from purplship.providers.asendia_us.utils import Settings as BaseSettings
5+
6+
7+
@attr.s(auto_attribs=True)
8+
class Settings(BaseSettings):
9+
"""Asendia US connection settings."""
10+
11+
# Carrier specific properties
12+
username: str
13+
password: str
14+
x_asendia_one_api_key: str
15+
account_number: str = None
16+
17+
# Base properties
18+
id: str = None
19+
test: bool = False
20+
carrier_id: str = "asendia_us"
21+
account_country_code: str = "US"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from purplship.providers.asendia_us.utils import Settings
2+
from purplship.providers.asendia_us.rate import parse_rate_response, rate_request
3+
from purplship.providers.asendia_us.shipment import (
4+
parse_shipment_cancel_response,
5+
parse_shipment_response,
6+
shipment_cancel_request,
7+
shipment_request,
8+
)
9+
from purplship.providers.asendia_us.tracking import (
10+
parse_tracking_response,
11+
tracking_request,
12+
)

0 commit comments

Comments
 (0)