karrio-easyship 2025.5.6__py3-none-any.whl → 2026.1__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.
- karrio/mappers/easyship/proxy.py +26 -10
- karrio/providers/easyship/tracking.py +17 -0
- karrio/providers/easyship/units.py +8 -0
- karrio/providers/easyship/utils.py +0 -65
- {karrio_easyship-2025.5.6.dist-info → karrio_easyship-2026.1.dist-info}/METADATA +1 -1
- {karrio_easyship-2025.5.6.dist-info → karrio_easyship-2026.1.dist-info}/RECORD +9 -9
- {karrio_easyship-2025.5.6.dist-info → karrio_easyship-2026.1.dist-info}/WHEEL +0 -0
- {karrio_easyship-2025.5.6.dist-info → karrio_easyship-2026.1.dist-info}/entry_points.txt +0 -0
- {karrio_easyship-2025.5.6.dist-info → karrio_easyship-2026.1.dist-info}/top_level.txt +0 -0
karrio/mappers/easyship/proxy.py
CHANGED
|
@@ -8,14 +8,23 @@ import karrio.mappers.easyship.settings as provider_settings
|
|
|
8
8
|
class Proxy(proxy.Proxy):
|
|
9
9
|
settings: provider_settings.Settings
|
|
10
10
|
|
|
11
|
+
def authenticate(self, _=None) -> lib.Deserializable[str]:
|
|
12
|
+
"""Return the access_token for API authentication.
|
|
13
|
+
|
|
14
|
+
Easyship uses a direct access token (no OAuth flow required).
|
|
15
|
+
This method provides a consistent interface with other carriers.
|
|
16
|
+
"""
|
|
17
|
+
return lib.Deserializable(self.settings.access_token)
|
|
18
|
+
|
|
11
19
|
def get_rates(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
20
|
+
access_token = self.authenticate().deserialize()
|
|
12
21
|
response = lib.request(
|
|
13
22
|
url=f"{self.settings.server_url}/2023-01/rates",
|
|
14
23
|
data=lib.to_json(request.serialize()),
|
|
15
24
|
trace=self.trace_as("json"),
|
|
16
25
|
method="POST",
|
|
17
26
|
headers={
|
|
18
|
-
"Authorization": f"Bearer {
|
|
27
|
+
"Authorization": f"Bearer {access_token}",
|
|
19
28
|
"Content-Type": "application/json",
|
|
20
29
|
"user-agent": "app/1.0",
|
|
21
30
|
},
|
|
@@ -24,29 +33,32 @@ class Proxy(proxy.Proxy):
|
|
|
24
33
|
return lib.Deserializable(response, lib.to_dict)
|
|
25
34
|
|
|
26
35
|
def create_shipment(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
27
|
-
|
|
36
|
+
access_token = self.authenticate().deserialize()
|
|
37
|
+
# create shipment with retry for transient failures (e.g., Cloudflare 522 timeouts)
|
|
28
38
|
response = lib.request(
|
|
29
39
|
url=f"{self.settings.server_url}/2023-01/shipments",
|
|
30
40
|
data=lib.to_json(request.serialize()),
|
|
31
41
|
trace=self.trace_as("json"),
|
|
32
42
|
method="POST",
|
|
33
43
|
headers={
|
|
34
|
-
"Authorization": f"Bearer {
|
|
44
|
+
"Authorization": f"Bearer {access_token}",
|
|
35
45
|
"Content-Type": "application/json",
|
|
36
46
|
"user-agent": "app/1.0",
|
|
37
47
|
},
|
|
48
|
+
max_retries=2,
|
|
38
49
|
)
|
|
39
50
|
|
|
40
|
-
return lib.Deserializable(response, lib.
|
|
51
|
+
return lib.Deserializable(response, lib.to_dict_safe, request.ctx)
|
|
41
52
|
|
|
42
53
|
def cancel_shipment(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
54
|
+
access_token = self.authenticate().deserialize()
|
|
43
55
|
easyship_shipment_id = request.serialize().get("easyship_shipment_id")
|
|
44
56
|
response = lib.request(
|
|
45
57
|
url=f"{self.settings.server_url}/2023-01/shipments/{easyship_shipment_id}/cancel",
|
|
46
58
|
trace=self.trace_as("json"),
|
|
47
59
|
method="POST",
|
|
48
60
|
headers={
|
|
49
|
-
"Authorization": f"Bearer {
|
|
61
|
+
"Authorization": f"Bearer {access_token}",
|
|
50
62
|
"Content-Type": "application/json",
|
|
51
63
|
"user-agent": "app/1.0",
|
|
52
64
|
},
|
|
@@ -55,6 +67,7 @@ class Proxy(proxy.Proxy):
|
|
|
55
67
|
return lib.Deserializable(response, lib.to_dict)
|
|
56
68
|
|
|
57
69
|
def get_tracking(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
70
|
+
access_token = self.authenticate().deserialize()
|
|
58
71
|
responses = lib.run_asynchronously(
|
|
59
72
|
lambda data: (
|
|
60
73
|
data["shipment_id"],
|
|
@@ -63,7 +76,7 @@ class Proxy(proxy.Proxy):
|
|
|
63
76
|
trace=self.trace_as("json"),
|
|
64
77
|
method="GET",
|
|
65
78
|
headers={
|
|
66
|
-
"Authorization": f"Bearer {
|
|
79
|
+
"Authorization": f"Bearer {access_token}",
|
|
67
80
|
"Content-Type": "application/json",
|
|
68
81
|
"user-agent": "app/1.0",
|
|
69
82
|
},
|
|
@@ -78,13 +91,14 @@ class Proxy(proxy.Proxy):
|
|
|
78
91
|
)
|
|
79
92
|
|
|
80
93
|
def schedule_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
94
|
+
access_token = self.authenticate().deserialize()
|
|
81
95
|
response = lib.request(
|
|
82
96
|
url=f"{self.settings.server_url}/2023-01/pickups",
|
|
83
97
|
data=lib.to_json(request.serialize()),
|
|
84
98
|
trace=self.trace_as("json"),
|
|
85
99
|
method="POST",
|
|
86
100
|
headers={
|
|
87
|
-
"Authorization": f"Bearer {
|
|
101
|
+
"Authorization": f"Bearer {access_token}",
|
|
88
102
|
"Content-Type": "application/json",
|
|
89
103
|
"user-agent": "app/1.0",
|
|
90
104
|
},
|
|
@@ -101,13 +115,14 @@ class Proxy(proxy.Proxy):
|
|
|
101
115
|
return lib.Deserializable(response, lib.to_dict, request.ctx)
|
|
102
116
|
|
|
103
117
|
def cancel_pickup(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
118
|
+
access_token = self.authenticate().deserialize()
|
|
104
119
|
easyship_pickup_id = request.serialize().get("easyship_pickup_id")
|
|
105
120
|
response = lib.request(
|
|
106
121
|
url=f"{self.settings.server_url}/2023-01/pickups/{easyship_pickup_id}/cancel",
|
|
107
122
|
trace=self.trace_as("json"),
|
|
108
123
|
method="POST",
|
|
109
124
|
headers={
|
|
110
|
-
"Authorization": f"Bearer {
|
|
125
|
+
"Authorization": f"Bearer {access_token}",
|
|
111
126
|
"Content-Type": "application/json",
|
|
112
127
|
"user-agent": "app/1.0",
|
|
113
128
|
},
|
|
@@ -116,6 +131,7 @@ class Proxy(proxy.Proxy):
|
|
|
116
131
|
return lib.Deserializable(response, lib.to_dict)
|
|
117
132
|
|
|
118
133
|
def create_manifest(self, request: lib.Serializable) -> lib.Deserializable[str]:
|
|
134
|
+
access_token = self.authenticate().deserialize()
|
|
119
135
|
# create manifest
|
|
120
136
|
response = lib.to_dict(
|
|
121
137
|
lib.request(
|
|
@@ -124,7 +140,7 @@ class Proxy(proxy.Proxy):
|
|
|
124
140
|
trace=self.trace_as("json"),
|
|
125
141
|
method="POST",
|
|
126
142
|
headers={
|
|
127
|
-
"Authorization": f"Bearer {
|
|
143
|
+
"Authorization": f"Bearer {access_token}",
|
|
128
144
|
"Content-Type": "application/json",
|
|
129
145
|
"user-agent": "app/1.0",
|
|
130
146
|
},
|
|
@@ -143,7 +159,7 @@ class Proxy(proxy.Proxy):
|
|
|
143
159
|
url=manifest_url,
|
|
144
160
|
method="GET",
|
|
145
161
|
headers={
|
|
146
|
-
"Authorization": f"Bearer {
|
|
162
|
+
"Authorization": f"Bearer {access_token}",
|
|
147
163
|
"origin": "http://localhost:5002",
|
|
148
164
|
"user-agent": "app/1.0",
|
|
149
165
|
},
|
|
@@ -62,6 +62,23 @@ def _extract_details(
|
|
|
62
62
|
date=lib.ftime(details.updated_at, "%Y-%m-%dT%H:%M:%SZ"),
|
|
63
63
|
time=lib.ftime(details.updated_at, "%Y-%m-%dT%H:%M:%SZ"),
|
|
64
64
|
description="",
|
|
65
|
+
timestamp=lib.fiso_timestamp(details.updated_at, current_format="%Y-%m-%dT%H:%M:%SZ"),
|
|
66
|
+
status=next(
|
|
67
|
+
(
|
|
68
|
+
s.name
|
|
69
|
+
for s in list(provider_units.TrackingStatus)
|
|
70
|
+
if getattr(master, "tracking_state", None) in s.value
|
|
71
|
+
),
|
|
72
|
+
None,
|
|
73
|
+
),
|
|
74
|
+
reason=next(
|
|
75
|
+
(
|
|
76
|
+
r.name
|
|
77
|
+
for r in list(provider_units.TrackingIncidentReason)
|
|
78
|
+
if str(master.leg_number) in r.value
|
|
79
|
+
),
|
|
80
|
+
None,
|
|
81
|
+
),
|
|
65
82
|
)
|
|
66
83
|
],
|
|
67
84
|
)
|
|
@@ -106,6 +106,14 @@ class TrackingStatus(lib.Enum):
|
|
|
106
106
|
ready_for_pickup = ["ready_for_pickup"]
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
class TrackingIncidentReason(lib.Enum):
|
|
110
|
+
"""Maps Easyship exception codes to normalized TrackingIncidentReason."""
|
|
111
|
+
carrier_damaged_parcel = []
|
|
112
|
+
consignee_refused = []
|
|
113
|
+
consignee_not_home = []
|
|
114
|
+
unknown = []
|
|
115
|
+
|
|
116
|
+
|
|
109
117
|
def to_service_code(service: typing.Dict[str, str]) -> str:
|
|
110
118
|
return lib.to_slug(
|
|
111
119
|
f'easyship_{to_carrier_code(service)}_{lib.to_snake_case(service["service_name"])}'
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
import datetime
|
|
3
1
|
import karrio.lib as lib
|
|
4
2
|
import karrio.core as core
|
|
5
|
-
import karrio.core.errors as errors
|
|
6
3
|
|
|
7
4
|
|
|
8
5
|
class Settings(core.Settings):
|
|
9
6
|
"""Easyship connection settings."""
|
|
10
7
|
|
|
11
|
-
# Add carrier specific api connection properties here
|
|
12
8
|
access_token: str
|
|
13
9
|
|
|
14
10
|
@property
|
|
@@ -19,17 +15,6 @@ class Settings(core.Settings):
|
|
|
19
15
|
def server_url(self):
|
|
20
16
|
return "https://api.easyship.com"
|
|
21
17
|
|
|
22
|
-
# """uncomment the following code block to expose a carrier tracking url."""
|
|
23
|
-
# @property
|
|
24
|
-
# def tracking_url(self):
|
|
25
|
-
# return "https://www.carrier.com/tracking?tracking-id={}"
|
|
26
|
-
|
|
27
|
-
# """uncomment the following code block to implement the Basic auth."""
|
|
28
|
-
# @property
|
|
29
|
-
# def authorization(self):
|
|
30
|
-
# pair = "%s:%s" % (self.username, self.password)
|
|
31
|
-
# return base64.b64encode(pair.encode("utf-8")).decode("ascii")
|
|
32
|
-
|
|
33
18
|
@property
|
|
34
19
|
def connection_config(self) -> lib.units.Options:
|
|
35
20
|
return lib.to_connection_config(
|
|
@@ -38,56 +23,6 @@ class Settings(core.Settings):
|
|
|
38
23
|
)
|
|
39
24
|
|
|
40
25
|
|
|
41
|
-
# """uncomment the following code block to implement the oauth login."""
|
|
42
|
-
# @property
|
|
43
|
-
# def access_token(self):
|
|
44
|
-
# """Retrieve the access_token using the client_id|client_secret pair
|
|
45
|
-
# or collect it from the cache if an unexpired access_token exist.
|
|
46
|
-
# """
|
|
47
|
-
# cache_key = f"{self.carrier_name}|{self.client_id}|{self.client_secret}"
|
|
48
|
-
# now = datetime.datetime.now() + datetime.timedelta(minutes=30)
|
|
49
|
-
|
|
50
|
-
# auth = self.connection_cache.get(cache_key) or {}
|
|
51
|
-
# token = auth.get("access_token")
|
|
52
|
-
# expiry = lib.to_date(auth.get("expiry"), current_format="%Y-%m-%d %H:%M:%S")
|
|
53
|
-
|
|
54
|
-
# if token is not None and expiry is not None and expiry > now:
|
|
55
|
-
# return token
|
|
56
|
-
|
|
57
|
-
# self.connection_cache.set(cache_key, lambda: login(self))
|
|
58
|
-
# new_auth = self.connection_cache.get(cache_key)
|
|
59
|
-
|
|
60
|
-
# return new_auth["access_token"]
|
|
61
|
-
|
|
62
|
-
# """uncomment the following code block to implement the oauth login."""
|
|
63
|
-
# def login(settings: Settings):
|
|
64
|
-
# import karrio.providers.easyship.error as error
|
|
65
|
-
|
|
66
|
-
# result = lib.request(
|
|
67
|
-
# url=f"{settings.server_url}/oauth/token",
|
|
68
|
-
# method="POST",
|
|
69
|
-
# headers={"content-Type": "application/x-www-form-urlencoded"},
|
|
70
|
-
# data=lib.to_query_string(
|
|
71
|
-
# dict(
|
|
72
|
-
# grant_type="client_credentials",
|
|
73
|
-
# client_id=settings.client_id,
|
|
74
|
-
# client_secret=settings.client_secret,
|
|
75
|
-
# )
|
|
76
|
-
# ),
|
|
77
|
-
# )
|
|
78
|
-
|
|
79
|
-
# response = lib.to_dict(result)
|
|
80
|
-
# messages = error.parse_error_response(response, settings)
|
|
81
|
-
|
|
82
|
-
# if any(messages):
|
|
83
|
-
# raise errors.ParsedMessagesError(messages)
|
|
84
|
-
|
|
85
|
-
# expiry = datetime.datetime.now() + datetime.timedelta(
|
|
86
|
-
# seconds=float(response.get("expires_in", 0))
|
|
87
|
-
# )
|
|
88
|
-
# return {**response, "expiry": lib.fdatetime(expiry)}
|
|
89
|
-
|
|
90
|
-
|
|
91
26
|
class ConnectionConfig(lib.Enum):
|
|
92
27
|
"""Carrier specific connection configs"""
|
|
93
28
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
karrio/mappers/easyship/__init__.py,sha256=aLA1ENTKZ7CGHtXQ0t5BQYucVdOnKMDPKGrdRXWZyGw,151
|
|
2
2
|
karrio/mappers/easyship/mapper.py,sha256=fLIBDvC8BkNAi2viZuuBy_zj1sjLSF7cEEbfxtXCz5E,3703
|
|
3
|
-
karrio/mappers/easyship/proxy.py,sha256=
|
|
3
|
+
karrio/mappers/easyship/proxy.py,sha256=UkI9TuvFQ5bN4XDVLd5fm8xkTPf8lRnNqDaMZw53fVE,6537
|
|
4
4
|
karrio/mappers/easyship/settings.py,sha256=ghyujn4gy5XtjCggAI59tzEAHNX_GxA0RC2-vxxv_mo,489
|
|
5
5
|
karrio/plugins/easyship/__init__.py,sha256=ENXQAYszRmxCvdVoY8EJtRAJBL0u31AlUhEmKD3Kpx0,543
|
|
6
6
|
karrio/providers/easyship/__init__.py,sha256=dWvRdjJLzka87iVfszU3cWVDJJBQn2YKKrT7-rZjAAU,759
|
|
@@ -8,9 +8,9 @@ karrio/providers/easyship/error.py,sha256=sqp_d9TMhjB1dg6UxJ-cIi8QW1UMV2pI_Xp623
|
|
|
8
8
|
karrio/providers/easyship/manifest.py,sha256=BoFk5beASPeIbdToB5yi_naVzUSTLcIB11rLBmgJ7kY,2243
|
|
9
9
|
karrio/providers/easyship/metadata.json,sha256=EuukQpPGZST6ANmXCz5QqTYYAhFUxHvt3QAnxlrqyvk,229126
|
|
10
10
|
karrio/providers/easyship/rate.py,sha256=PSKu8wDJH0i3xeUpk6OLmIe7Pyio6_i4tiXmP8ekqpk,9005
|
|
11
|
-
karrio/providers/easyship/tracking.py,sha256=
|
|
12
|
-
karrio/providers/easyship/units.py,sha256=
|
|
13
|
-
karrio/providers/easyship/utils.py,sha256=
|
|
11
|
+
karrio/providers/easyship/tracking.py,sha256=pQy4hNbOWfP-V4JXhwenMMofHRYq2totoM10O9Va4fs,4220
|
|
12
|
+
karrio/providers/easyship/units.py,sha256=_O45dD2La7FYJdA6NA-o-h6svrt-RRxUASfgDlMGrTw,4508
|
|
13
|
+
karrio/providers/easyship/utils.py,sha256=Sbthof9MMLjZoex3BYcztQ5RRlSuq6NAC18ro0x2KKI,906
|
|
14
14
|
karrio/providers/easyship/pickup/__init__.py,sha256=vObZR6snWBhZb09L-klqUgNbb3Ib9g0NTSEQpF_T4mM,299
|
|
15
15
|
karrio/providers/easyship/pickup/cancel.py,sha256=Kq6T0AvWjV1QSs43tbvRxiuJx0nP5v7cVa6Ls-0cQ1Y,1251
|
|
16
16
|
karrio/providers/easyship/pickup/create.py,sha256=YX4pFPdZIgvIH5tB5SpcxiBo-4Rxp3c4msZKy-Ib_4E,3118
|
|
@@ -32,8 +32,8 @@ karrio/schemas/easyship/shipment_request.py,sha256=nowz5CWtxdZg4zb81a_QsrmEI0dEt
|
|
|
32
32
|
karrio/schemas/easyship/shipment_response.py,sha256=9uJJs4xR0bLLz7vmZMCSaIyz59dBl4kvHjMKwVvLs7g,11002
|
|
33
33
|
karrio/schemas/easyship/tracking_request.py,sha256=XQ735p0jyG46fzaNlSqb2Wu8Ral6UgID8HFM6fBQsPw,1620
|
|
34
34
|
karrio/schemas/easyship/tracking_response.py,sha256=QwuvI_8-YQXo-2q6uMAJA5IQrgX2gfoPtg1TGBHoZA4,1830
|
|
35
|
-
karrio_easyship-
|
|
36
|
-
karrio_easyship-
|
|
37
|
-
karrio_easyship-
|
|
38
|
-
karrio_easyship-
|
|
39
|
-
karrio_easyship-
|
|
35
|
+
karrio_easyship-2026.1.dist-info/METADATA,sha256=DMFvo0r3dlTrMm_R6iqj_wbGchzhkIkgjCKVdQ6IKLs,995
|
|
36
|
+
karrio_easyship-2026.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
+
karrio_easyship-2026.1.dist-info/entry_points.txt,sha256=fWVjIqvIorXvb1UVUMceu3i7pP0ba6gJnaZm7HLkZIY,61
|
|
38
|
+
karrio_easyship-2026.1.dist-info/top_level.txt,sha256=FZCY8Nwft8oEGHdl--xku8P3TrnOxu5dETEU_fWpRSM,20
|
|
39
|
+
karrio_easyship-2026.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|