karrio-eshipper 2025.5rc1__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.
Files changed (33) hide show
  1. karrio/mappers/eshipper/__init__.py +3 -0
  2. karrio/mappers/eshipper/mapper.py +50 -0
  3. karrio/mappers/eshipper/proxy.py +65 -0
  4. karrio/mappers/eshipper/settings.py +21 -0
  5. karrio/plugins/eshipper/__init__.py +18 -0
  6. karrio/providers/eshipper/__init__.py +13 -0
  7. karrio/providers/eshipper/error.py +53 -0
  8. karrio/providers/eshipper/metadata.json +13018 -0
  9. karrio/providers/eshipper/rate.py +197 -0
  10. karrio/providers/eshipper/shipment/__init__.py +9 -0
  11. karrio/providers/eshipper/shipment/cancel.py +45 -0
  12. karrio/providers/eshipper/shipment/create.py +295 -0
  13. karrio/providers/eshipper/tracking.py +72 -0
  14. karrio/providers/eshipper/units.py +334 -0
  15. karrio/providers/eshipper/utils.py +76 -0
  16. karrio/schemas/eshipper/__init__.py +0 -0
  17. karrio/schemas/eshipper/cancel_request.py +15 -0
  18. karrio/schemas/eshipper/cancel_response.py +15 -0
  19. karrio/schemas/eshipper/error_response.py +21 -0
  20. karrio/schemas/eshipper/pickup_cancel_response.py +9 -0
  21. karrio/schemas/eshipper/pickup_request.py +25 -0
  22. karrio/schemas/eshipper/pickup_response.py +16 -0
  23. karrio/schemas/eshipper/rate_request.py +181 -0
  24. karrio/schemas/eshipper/rate_response.py +37 -0
  25. karrio/schemas/eshipper/shipping_request.py +184 -0
  26. karrio/schemas/eshipper/shipping_response.py +114 -0
  27. karrio/schemas/eshipper/tracking_request.py +10 -0
  28. karrio/schemas/eshipper/tracking_response.py +62 -0
  29. karrio_eshipper-2025.5rc1.dist-info/METADATA +45 -0
  30. karrio_eshipper-2025.5rc1.dist-info/RECORD +33 -0
  31. karrio_eshipper-2025.5rc1.dist-info/WHEEL +5 -0
  32. karrio_eshipper-2025.5rc1.dist-info/entry_points.txt +2 -0
  33. karrio_eshipper-2025.5rc1.dist-info/top_level.txt +3 -0
@@ -0,0 +1,3 @@
1
+ from karrio.mappers.eshipper.mapper import Mapper
2
+ from karrio.mappers.eshipper.proxy import Proxy
3
+ from karrio.mappers.eshipper.settings import Settings
@@ -0,0 +1,50 @@
1
+ """Karrio eShipper client mapper."""
2
+
3
+ import typing
4
+ import karrio.lib as lib
5
+ import karrio.api.mapper as mapper
6
+ import karrio.core.models as models
7
+ import karrio.providers.eshipper as provider
8
+ import karrio.mappers.eshipper.settings as provider_settings
9
+
10
+
11
+ class Mapper(mapper.Mapper):
12
+ settings: provider_settings.Settings
13
+
14
+ def create_rate_request(self, payload: models.RateRequest) -> lib.Serializable:
15
+ return provider.rate_request(payload, self.settings)
16
+
17
+ def create_tracking_request(
18
+ self, payload: models.TrackingRequest
19
+ ) -> lib.Serializable:
20
+ return provider.tracking_request(payload, self.settings)
21
+
22
+ def create_shipment_request(
23
+ self, payload: models.ShipmentRequest
24
+ ) -> lib.Serializable:
25
+ return provider.shipment_request(payload, self.settings)
26
+
27
+ def create_cancel_shipment_request(
28
+ self, payload: models.ShipmentCancelRequest
29
+ ) -> lib.Serializable[str]:
30
+ return provider.shipment_cancel_request(payload, self.settings)
31
+
32
+ def parse_cancel_shipment_response(
33
+ self, response: lib.Deserializable[str]
34
+ ) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
35
+ return provider.parse_shipment_cancel_response(response, self.settings)
36
+
37
+ def parse_rate_response(
38
+ self, response: lib.Deserializable[str]
39
+ ) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
40
+ return provider.parse_rate_response(response, self.settings)
41
+
42
+ def parse_shipment_response(
43
+ self, response: lib.Deserializable[str]
44
+ ) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
45
+ return provider.parse_shipment_response(response, self.settings)
46
+
47
+ def parse_tracking_response(
48
+ self, response: lib.Deserializable[str]
49
+ ) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
50
+ return provider.parse_tracking_response(response, self.settings)
@@ -0,0 +1,65 @@
1
+ """Karrio eShipper client proxy."""
2
+
3
+ import karrio.lib as lib
4
+ import karrio.api.proxy as proxy
5
+ import karrio.mappers.eshipper.settings as provider_settings
6
+
7
+
8
+ class Proxy(proxy.Proxy):
9
+ settings: provider_settings.Settings
10
+
11
+ def get_rates(self, request: lib.Serializable) -> lib.Deserializable[str]:
12
+ response = lib.request(
13
+ url=f"{self.settings.server_url}/api/v2/quote",
14
+ data=lib.to_json(request.serialize()),
15
+ trace=self.trace_as("json"),
16
+ method="POST",
17
+ headers={
18
+ "content-Type": "application/json",
19
+ "Authorization": f"Bearer {self.settings.access_token}",
20
+ },
21
+ )
22
+
23
+ return lib.Deserializable(response, lib.to_dict)
24
+
25
+ def create_shipment(self, request: lib.Serializable) -> lib.Deserializable[str]:
26
+ response = lib.request(
27
+ url=f"{self.settings.server_url}/api/v2/ship",
28
+ data=lib.to_json(request.serialize()),
29
+ trace=self.trace_as("json"),
30
+ method="PUT",
31
+ headers={
32
+ "content-Type": "application/json",
33
+ "Authorization": f"Bearer {self.settings.access_token}",
34
+ },
35
+ )
36
+
37
+ return lib.Deserializable(response, lib.to_dict)
38
+
39
+ def cancel_shipment(self, request: lib.Serializable) -> lib.Deserializable[str]:
40
+ response = lib.request(
41
+ url=f"{self.settings.server_url}/api/v2/ship/cancel",
42
+ data=lib.to_json(request.serialize()),
43
+ trace=self.trace_as("json"),
44
+ method="DELETE",
45
+ headers={
46
+ "content-Type": "application/json",
47
+ "Authorization": f"Bearer {self.settings.access_token}",
48
+ },
49
+ )
50
+
51
+ return lib.Deserializable(response, lib.to_dict)
52
+
53
+ def get_tracking(self, request: lib.Serializable) -> lib.Deserializable[str]:
54
+ query = lib.to_query_string(request.serialize())
55
+ response = lib.request(
56
+ url=f"{self.settings.server_url}/api/v2/track/events?{query}",
57
+ trace=self.trace_as("json"),
58
+ method="GET",
59
+ headers={
60
+ "content-Type": "application/json",
61
+ "Authorization": f"Bearer {self.settings.access_token}",
62
+ },
63
+ )
64
+
65
+ return lib.Deserializable(response, lib.to_dict)
@@ -0,0 +1,21 @@
1
+ """Karrio eShipper client settings."""
2
+
3
+ import attr
4
+ import karrio.providers.eshipper.utils as provider_utils
5
+
6
+
7
+ @attr.s(auto_attribs=True)
8
+ class Settings(provider_utils.Settings):
9
+ """eShipper connection settings."""
10
+
11
+ # required carrier specific properties
12
+ principal: str
13
+ credential: str
14
+
15
+ # generic properties
16
+ id: str = None
17
+ test_mode: bool = False
18
+ carrier_id: str = "eshipper"
19
+ account_country_code: str = None
20
+ metadata: dict = {}
21
+ config: dict = {}
@@ -0,0 +1,18 @@
1
+ import karrio.core.metadata as metadata
2
+ import karrio.mappers.eshipper as mappers
3
+ import karrio.providers.eshipper.units as units
4
+
5
+
6
+ METADATA = metadata.PluginMetadata(
7
+ status="production-ready",
8
+ id="eshipper",
9
+ label="eShipper",
10
+ # Integrations
11
+ Mapper=mappers.Mapper,
12
+ Proxy=mappers.Proxy,
13
+ Settings=mappers.Settings,
14
+ # Data Units
15
+ is_hub=True,
16
+ services=units.ShippingService,
17
+ options=units.ShippingOption,
18
+ )
@@ -0,0 +1,13 @@
1
+
2
+ from karrio.providers.eshipper.utils import Settings
3
+ from karrio.providers.eshipper.rate import parse_rate_response, rate_request
4
+ from karrio.providers.eshipper.shipment import (
5
+ parse_shipment_cancel_response,
6
+ parse_shipment_response,
7
+ shipment_cancel_request,
8
+ shipment_request,
9
+ )
10
+ from karrio.providers.eshipper.tracking import (
11
+ parse_tracking_response,
12
+ tracking_request,
13
+ )
@@ -0,0 +1,53 @@
1
+ import typing
2
+ import karrio.lib as lib
3
+ import karrio.core.models as models
4
+ import karrio.providers.eshipper.utils as provider_utils
5
+
6
+
7
+ def parse_error_response(
8
+ response: dict,
9
+ settings: provider_utils.Settings,
10
+ **kwargs,
11
+ ) -> typing.List[models.Message]:
12
+ responses = response if isinstance(response, list) else [response]
13
+ errors = [
14
+ *[_ for _ in responses if _.get("code")],
15
+ *sum(
16
+ [
17
+ [dict(code="warning", message=__) for __ in _.get("warnings")]
18
+ for _ in responses
19
+ if _.get("warnings")
20
+ ],
21
+ [],
22
+ ),
23
+ *sum(
24
+ [
25
+ [
26
+ dict(
27
+ code="error",
28
+ message=order["message"]
29
+ )
30
+ for order in _.get("order", [])
31
+ if "message" in order and order["message"].startswith("Error")
32
+ ]
33
+ for _ in responses
34
+ ],
35
+ [],
36
+ )
37
+ ]
38
+
39
+ return [
40
+ models.Message(
41
+ carrier_id=settings.carrier_id,
42
+ carrier_name=settings.carrier_name,
43
+ code=error.get("code"),
44
+ message=error.get("message"),
45
+ details={
46
+ **kwargs,
47
+ "type": error.get("type"),
48
+ "fieldErrors": error.get("fieldErrors"),
49
+ "thirdPartyMessage": error.get("thirdPartyMessage"),
50
+ },
51
+ )
52
+ for error in errors
53
+ ]