karrio-aramex 2025.5rc34__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/aramex/__init__.py +3 -0
- karrio/mappers/aramex/mapper.py +20 -0
- karrio/mappers/aramex/proxy.py +22 -0
- karrio/mappers/aramex/settings.py +24 -0
- karrio/plugins/aramex/__init__.py +24 -0
- karrio/providers/aramex/__init__.py +24 -0
- karrio/providers/aramex/error.py +23 -0
- karrio/providers/aramex/tracking.py +103 -0
- karrio/providers/aramex/units.py +46 -0
- karrio/providers/aramex/utils.py +48 -0
- karrio/schemas/aramex/__init__.py +0 -0
- karrio/schemas/aramex/array_of_string.py +3484 -0
- karrio/schemas/aramex/datatypes.py +1469 -0
- karrio/schemas/aramex/location.py +5809 -0
- karrio/schemas/aramex/rates.py +5526 -0
- karrio/schemas/aramex/shipping.py +11642 -0
- karrio/schemas/aramex/tracking.py +4152 -0
- karrio_aramex-2025.5rc34.dist-info/METADATA +44 -0
- karrio_aramex-2025.5rc34.dist-info/RECORD +22 -0
- karrio_aramex-2025.5rc34.dist-info/WHEEL +5 -0
- karrio_aramex-2025.5rc34.dist-info/entry_points.txt +2 -0
- karrio_aramex-2025.5rc34.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import karrio.lib as lib
|
|
3
|
+
import karrio.api.mapper as mapper
|
|
4
|
+
import karrio.core.models as models
|
|
5
|
+
import karrio.providers.aramex as provider
|
|
6
|
+
import karrio.mappers.aramex.settings as settings
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Mapper(mapper.Mapper):
|
|
10
|
+
settings: settings.Settings
|
|
11
|
+
|
|
12
|
+
def create_tracking_request(
|
|
13
|
+
self, payload: models.TrackingRequest
|
|
14
|
+
) -> lib.Serializable:
|
|
15
|
+
return provider.tracking_request(payload, self.settings)
|
|
16
|
+
|
|
17
|
+
def parse_tracking_response(
|
|
18
|
+
self, response: lib.Deserializable
|
|
19
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
|
20
|
+
return provider.parse_tracking_response(response, self.settings)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from karrio.core.utils import XP, request as http, Serializable, Deserializable
|
|
2
|
+
from karrio.api.proxy import Proxy as BaseProxy
|
|
3
|
+
from karrio.mappers.aramex.settings import Settings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Proxy(BaseProxy):
|
|
7
|
+
settings: Settings
|
|
8
|
+
|
|
9
|
+
""" Proxy Methods """
|
|
10
|
+
|
|
11
|
+
def get_tracking(self, request: Serializable) -> Deserializable:
|
|
12
|
+
response = http(
|
|
13
|
+
url=f"{self.settings.server_url}/ShippingAPI.V2/Tracking/Service_1_0.svc",
|
|
14
|
+
data=request.serialize(),
|
|
15
|
+
trace=self.trace_as("xml"),
|
|
16
|
+
method="POST",
|
|
17
|
+
headers={
|
|
18
|
+
"Content-Type": "text/xml; charset=utf-8",
|
|
19
|
+
"soapAction": "http://ws.aramex.net/ShippingAPI/v1/Service_1_0/TrackShipments",
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
return Deserializable(response, XP.to_xml)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Karrio Aramex settings."""
|
|
2
|
+
|
|
3
|
+
import attr
|
|
4
|
+
from karrio.providers.aramex.utils import Settings as BaseSettings
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@attr.s(auto_attribs=True)
|
|
8
|
+
class Settings(BaseSettings):
|
|
9
|
+
"""Aramex connection settings."""
|
|
10
|
+
|
|
11
|
+
# Carrier specific properties
|
|
12
|
+
username: str
|
|
13
|
+
password: str
|
|
14
|
+
account_pin: str
|
|
15
|
+
account_entity: str
|
|
16
|
+
account_number: str
|
|
17
|
+
account_country_code: str
|
|
18
|
+
|
|
19
|
+
# Base properties
|
|
20
|
+
id: str = None
|
|
21
|
+
test_mode: bool = False
|
|
22
|
+
carrier_id: str = "aramex"
|
|
23
|
+
metadata: dict = {}
|
|
24
|
+
config: dict = {}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import karrio.core.metadata as metadata
|
|
2
|
+
import karrio.mappers.aramex as mappers
|
|
3
|
+
# import karrio.providers.aramex.units as units
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
METADATA = metadata.PluginMetadata(
|
|
7
|
+
status="beta",
|
|
8
|
+
id="aramex",
|
|
9
|
+
label="Aramex",
|
|
10
|
+
# Integrations
|
|
11
|
+
Mapper=mappers.Mapper,
|
|
12
|
+
Proxy=mappers.Proxy,
|
|
13
|
+
Settings=mappers.Settings,
|
|
14
|
+
# Data Units
|
|
15
|
+
# options=units.OptionCode,
|
|
16
|
+
# package_presets=units.PackagePresets,
|
|
17
|
+
# packaging_types=units.PackagingType,
|
|
18
|
+
# services=units.Serives,
|
|
19
|
+
has_intl_accounts=True,
|
|
20
|
+
# New fields
|
|
21
|
+
website="https://www.aramex.com/ae/en",
|
|
22
|
+
documentation="https://www.aramex.com/us/en/developers-solution-center/aramex-apis",
|
|
23
|
+
description="Aramex is the leading global logistics provider.",
|
|
24
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from karrio.providers.aramex.utils import Settings
|
|
2
|
+
# from karrio.providers.aramex.rate import parse_rate_response, rate_request
|
|
3
|
+
# from karrio.providers.aramex.address import (
|
|
4
|
+
# parse_address_validation_response,
|
|
5
|
+
# address_validation_request
|
|
6
|
+
# )
|
|
7
|
+
# from karrio.providers.aramex.shipment import (
|
|
8
|
+
# parse_shipment_cancel_response,
|
|
9
|
+
# parse_shipment_response,
|
|
10
|
+
# shipment_cancel_request,
|
|
11
|
+
# shipment_request,
|
|
12
|
+
# )
|
|
13
|
+
# from karrio.providers.aramex.pickup import (
|
|
14
|
+
# parse_pickup_cancel_response,
|
|
15
|
+
# parse_pickup_update_response,
|
|
16
|
+
# parse_pickup_response,
|
|
17
|
+
# pickup_update_request,
|
|
18
|
+
# pickup_cancel_request,
|
|
19
|
+
# pickup_request,
|
|
20
|
+
# )
|
|
21
|
+
from karrio.providers.aramex.tracking import (
|
|
22
|
+
parse_tracking_response,
|
|
23
|
+
tracking_request,
|
|
24
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from karrio.schemas.aramex.tracking import Notification
|
|
3
|
+
from karrio.core.utils import Element, XP
|
|
4
|
+
from karrio.core.models import Message
|
|
5
|
+
from karrio.providers.aramex import Settings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def parse_error_response(response: Element, settings: Settings) -> List[Message]:
|
|
9
|
+
errors = response.xpath(".//*[local-name() = $name]", name="Notification")
|
|
10
|
+
return [_extract_error(node, settings) for node in errors]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _extract_error(node: Element, settings: Settings) -> Message:
|
|
14
|
+
notification = XP.to_object(Notification, node)
|
|
15
|
+
|
|
16
|
+
return Message(
|
|
17
|
+
# context info
|
|
18
|
+
carrier_name=settings.carrier_name,
|
|
19
|
+
carrier_id=settings.carrier_id,
|
|
20
|
+
# carrier error info
|
|
21
|
+
code=notification.Code,
|
|
22
|
+
message=notification.Message,
|
|
23
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from typing import List, Tuple
|
|
2
|
+
from functools import partial
|
|
3
|
+
from karrio.schemas.aramex.array_of_string import ArrayOfstring
|
|
4
|
+
from karrio.schemas.aramex.tracking import (
|
|
5
|
+
ShipmentTrackingRequest,
|
|
6
|
+
ClientInfo,
|
|
7
|
+
TrackingResult,
|
|
8
|
+
)
|
|
9
|
+
from karrio.core.utils import (
|
|
10
|
+
create_envelope,
|
|
11
|
+
Element,
|
|
12
|
+
Serializable,
|
|
13
|
+
XP,
|
|
14
|
+
DF,
|
|
15
|
+
)
|
|
16
|
+
from karrio.core.models import (
|
|
17
|
+
TrackingEvent,
|
|
18
|
+
TrackingDetails,
|
|
19
|
+
TrackingRequest,
|
|
20
|
+
Message,
|
|
21
|
+
)
|
|
22
|
+
from karrio.providers.aramex.utils import Settings
|
|
23
|
+
from karrio.providers.aramex.error import parse_error_response
|
|
24
|
+
import karrio.lib as lib
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def parse_tracking_response(
|
|
28
|
+
_response: lib.Deserializable[lib.Element],
|
|
29
|
+
settings: Settings,
|
|
30
|
+
) -> Tuple[List[TrackingDetails], List[Message]]:
|
|
31
|
+
response = _response.deserialize()
|
|
32
|
+
non_existents = next(
|
|
33
|
+
(
|
|
34
|
+
XP.to_object(ArrayOfstring, n)
|
|
35
|
+
for n in lib.find_element("NonExistingWaybills", response)
|
|
36
|
+
),
|
|
37
|
+
ArrayOfstring(),
|
|
38
|
+
)
|
|
39
|
+
results = lib.find_element("TrackingResult", response)
|
|
40
|
+
tracking_details = [_extract_detail(node, settings) for node in results]
|
|
41
|
+
errors = _extract_errors(non_existents, settings) + parse_error_response(
|
|
42
|
+
response, settings
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return tracking_details, errors
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _extract_errors(non_existents: ArrayOfstring, settings: Settings) -> List[Message]:
|
|
49
|
+
return [
|
|
50
|
+
Message(
|
|
51
|
+
carrier_name=settings.carrier_name,
|
|
52
|
+
carrier_id=settings.carrier_id,
|
|
53
|
+
message=f'Waybill "{waybill}" Not Found',
|
|
54
|
+
)
|
|
55
|
+
for waybill in non_existents.string
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _extract_detail(node: Element, settings: Settings) -> TrackingDetails:
|
|
60
|
+
detail = XP.to_object(TrackingResult, node)
|
|
61
|
+
|
|
62
|
+
return TrackingDetails(
|
|
63
|
+
carrier_name=settings.carrier_name,
|
|
64
|
+
carrier_id=settings.carrier_id,
|
|
65
|
+
tracking_number=detail.WaybillNumber,
|
|
66
|
+
events=[
|
|
67
|
+
TrackingEvent(
|
|
68
|
+
date=DF.date(detail.UpdateDateTime, "%Y-%m-%dT%H:%M:%S"),
|
|
69
|
+
description=detail.UpdateDescription,
|
|
70
|
+
location=detail.UpdateLocation,
|
|
71
|
+
code=detail.UpdateCode,
|
|
72
|
+
time=DF.ftime(detail.UpdateDateTime, "%Y-%m-%dT%H:%M:%S"),
|
|
73
|
+
)
|
|
74
|
+
],
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def tracking_request(payload: TrackingRequest, settings: Settings) -> Serializable:
|
|
79
|
+
request = create_envelope(
|
|
80
|
+
body_content=ShipmentTrackingRequest(
|
|
81
|
+
ClientInfo=ClientInfo(
|
|
82
|
+
UserName=settings.username,
|
|
83
|
+
Password=settings.password,
|
|
84
|
+
Version="1.0",
|
|
85
|
+
AccountNumber=settings.account_number,
|
|
86
|
+
AccountPin=settings.account_pin,
|
|
87
|
+
AccountEntity=settings.account_entity,
|
|
88
|
+
AccountCountryCode=settings.account_country_code,
|
|
89
|
+
),
|
|
90
|
+
Transaction=None,
|
|
91
|
+
Shipments=ArrayOfstring(string=payload.tracking_numbers),
|
|
92
|
+
GetLastTrackingUpdateOnly=False,
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return Serializable(
|
|
97
|
+
request,
|
|
98
|
+
partial(
|
|
99
|
+
settings.standard_request_serializer,
|
|
100
|
+
extra_namespace='xmlns:arr="http://schemas.microsoft.com/2003/10/Serialization/Arrays',
|
|
101
|
+
special_prefixes=dict(string="arr"),
|
|
102
|
+
),
|
|
103
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
""" Aramex Native Types """
|
|
2
|
+
|
|
3
|
+
# import karrio.lib as lib
|
|
4
|
+
# from karrio.core.utils import Enum, Flag
|
|
5
|
+
#
|
|
6
|
+
# PRESET_DEFAULTS = dict(dimension_unit="CM", weight_unit="KG")
|
|
7
|
+
#
|
|
8
|
+
#
|
|
9
|
+
# class PackagePresets(lib.Enum):
|
|
10
|
+
# # carrier_envelope = PackagePreset(
|
|
11
|
+
# # **dict(weight=0.5, width=35.0, height=27.5, length=1.0, packaging_type="envelope"),
|
|
12
|
+
# # **PRESET_DEFAULTS
|
|
13
|
+
# # )
|
|
14
|
+
# # carrier_box = PackagePreset(
|
|
15
|
+
# # **dict(weight=0.5, width=35.0, height=27.5, length=1.0, packaging_type="medium_box"),
|
|
16
|
+
# # **PRESET_DEFAULTS
|
|
17
|
+
# # )
|
|
18
|
+
# pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# class PackageType(lib.StrEnum):
|
|
22
|
+
# carrier_envelope = "ENVELOPE CODE"
|
|
23
|
+
# carrier_box = "BOX CODE"
|
|
24
|
+
# carrier_your_packaging = "CUSTOM PACKAGING CODE"
|
|
25
|
+
#
|
|
26
|
+
# """ Unified Packaging type mapping """
|
|
27
|
+
# envelope = carrier_envelope
|
|
28
|
+
# pak = carrier_envelope
|
|
29
|
+
# tube = carrier_your_packaging
|
|
30
|
+
# pallet = carrier_your_packaging
|
|
31
|
+
# small_box = carrier_box
|
|
32
|
+
# medium_box = carrier_box
|
|
33
|
+
# large_box = carrier_box
|
|
34
|
+
# your_packaging = carrier_your_packaging
|
|
35
|
+
#
|
|
36
|
+
#
|
|
37
|
+
# class Service(Enum):
|
|
38
|
+
# carrier_standard = "STANDARD CODE"
|
|
39
|
+
# carrier_premium = "PREMIUM CODE"
|
|
40
|
+
# carrier_overnight = "OVERNIGHT CODE"
|
|
41
|
+
#
|
|
42
|
+
#
|
|
43
|
+
# class Option(lib.Enum):
|
|
44
|
+
# carrier_signature = "SIGNATURE CODE"
|
|
45
|
+
# carrier_saturday_delivery = "SATURDAY DELIVERY CODE"
|
|
46
|
+
# carrier_dry_ice = "DRY ICE CODE"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from karrio.core.utils import XP, apply_namespaceprefix, Envelope, Header
|
|
2
|
+
from karrio.core import Settings as BaseSettings
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Settings(BaseSettings):
|
|
6
|
+
"""Aramex connection settings."""
|
|
7
|
+
|
|
8
|
+
# Carrier specific properties
|
|
9
|
+
username: str
|
|
10
|
+
password: str
|
|
11
|
+
account_pin: str
|
|
12
|
+
account_entity: str
|
|
13
|
+
account_number: str
|
|
14
|
+
account_country_code: str
|
|
15
|
+
|
|
16
|
+
id: str = None
|
|
17
|
+
metadata: dict = {}
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def carrier_name(self):
|
|
21
|
+
return "aramex"
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def server_url(self):
|
|
25
|
+
return "http://ws.dev.aramex.net" if self.test_mode else "http://ws.aramex.net"
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def standard_request_serializer(
|
|
29
|
+
envelope: Envelope,
|
|
30
|
+
version: str = "v1",
|
|
31
|
+
extra_namespace: str = "",
|
|
32
|
+
special_prefixes: dict = None,
|
|
33
|
+
) -> str:
|
|
34
|
+
|
|
35
|
+
namespacedef_ = (
|
|
36
|
+
f'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" '
|
|
37
|
+
f'xmlns:{version}="http://ws.aramex.net/ShippingAPI/{version}/" '
|
|
38
|
+
f"{extra_namespace}"
|
|
39
|
+
)
|
|
40
|
+
envelope.ns_prefix_ = "soap"
|
|
41
|
+
envelope.Header = Header()
|
|
42
|
+
envelope.Body.ns_prefix_ = envelope.ns_prefix_
|
|
43
|
+
envelope.Header.ns_prefix_ = envelope.ns_prefix_
|
|
44
|
+
|
|
45
|
+
for node in envelope.Body.anytypeobjs_ + envelope.Header.anytypeobjs_:
|
|
46
|
+
apply_namespaceprefix(node, version, special_prefixes)
|
|
47
|
+
|
|
48
|
+
return XP.export(envelope, namespacedef_=namespacedef_)
|
|
File without changes
|