karrio-royalmail 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.
@@ -0,0 +1,3 @@
1
+ from karrio.mappers.royalmail.mapper import Mapper
2
+ from karrio.mappers.royalmail.proxy import Proxy
3
+ from karrio.mappers.royalmail.settings import Settings
@@ -0,0 +1,117 @@
1
+ from typing import List, Tuple
2
+ from karrio.core.utils.serializable import Serializable, Deserializable
3
+ from karrio.api.mapper import Mapper as BaseMapper
4
+ from karrio.core.models import (
5
+ # AddressValidationRequest,
6
+ # ShipmentCancelRequest,
7
+ # PickupUpdateRequest,
8
+ # PickupCancelRequest,
9
+ # ShipmentRequest,
10
+ TrackingRequest,
11
+ # PickupRequest,
12
+ # RateRequest,
13
+ # AddressValidationDetails,
14
+ # ConfirmationDetails,
15
+ TrackingDetails,
16
+ # ShipmentDetails,
17
+ # PickupDetails,
18
+ # RateDetails,
19
+ Message,
20
+ )
21
+ from karrio.providers.royalmail import (
22
+ # parse_address_validation_response,
23
+ # parse_shipment_cancel_response,
24
+ # parse_pickup_update_response,
25
+ # parse_pickup_cancel_response,
26
+ # parse_shipment_response,
27
+ parse_tracking_response,
28
+ # parse_pickup_response,
29
+ # parse_rate_response,
30
+ # address_validation_request,
31
+ # shipment_cancel_request,
32
+ # pickup_update_request,
33
+ # pickup_cancel_request,
34
+ tracking_request,
35
+ # shipment_request,
36
+ # pickup_request,
37
+ # rate_request,
38
+ )
39
+ from karrio.mappers.royalmail.settings import Settings
40
+
41
+
42
+ class Mapper(BaseMapper):
43
+ settings: Settings
44
+
45
+ # def create_address_validation_request(self, payload: AddressValidationRequest) -> Serializable:
46
+ # return address_validation_request(payload, self.settings)
47
+ #
48
+ # def create_pickup_request(
49
+ # self, payload: PickupRequest
50
+ # ) -> Serializable:
51
+ # return pickup_request(payload, self.settings)
52
+ #
53
+ # def create_pickup_update_request(
54
+ # self, payload: PickupUpdateRequest
55
+ # ) -> Serializable:
56
+ # return pickup_update_request(payload, self.settings)
57
+ #
58
+ # def create_cancel_pickup_request(
59
+ # self, payload: PickupCancelRequest
60
+ # ) -> Serializable:
61
+ # return pickup_cancel_request(payload, self.settings)
62
+
63
+ # def create_rate_request(
64
+ # self, payload: RateRequest
65
+ # ) -> Serializable:
66
+ # return rate_request(payload, self.settings)
67
+
68
+ # def create_shipment_request(
69
+ # self, payload: ShipmentRequest
70
+ # ) -> Serializable:
71
+ # return shipment_request(payload, self.settings)
72
+ #
73
+ # def create_cancel_shipment_request(self, payload: ShipmentCancelRequest) -> Serializable:
74
+ # return shipment_cancel_request(payload, self.settings)
75
+
76
+ def create_tracking_request(self, payload: TrackingRequest) -> Serializable:
77
+ return tracking_request(payload, self.settings)
78
+
79
+ # def parse_address_validation_response(
80
+ # self, response: Deserializable
81
+ # ) -> Tuple[AddressValidationDetails, List[Message]]:
82
+ # return parse_address_validation_response(response, self.settings)
83
+ #
84
+ # def parse_cancel_pickup_response(
85
+ # self, response: Deserializable
86
+ # ) -> Tuple[ConfirmationDetails, List[Message]]:
87
+ # return parse_pickup_cancel_response(response, self.settings)
88
+ #
89
+ # def parse_pickup_response(
90
+ # self, response: Deserializable
91
+ # ) -> Tuple[PickupDetails, List[Message]]:
92
+ # return parse_pickup_response(response, self.settings)
93
+ #
94
+ # def parse_pickup_update_response(
95
+ # self, response: Deserializable
96
+ # ) -> Tuple[PickupDetails, List[Message]]:
97
+ # return parse_pickup_update_response(response, self.settings)
98
+
99
+ # def parse_rate_response(
100
+ # self, response: Deserializable
101
+ # ) -> Tuple[List[RateDetails], List[Message]]:
102
+ # return parse_rate_response(response, self.settings)
103
+
104
+ # def parse_shipment_response(
105
+ # self, response: Deserializable
106
+ # ) -> Tuple[ShipmentDetails, List[Message]]:
107
+ # return parse_shipment_response(response, self.settings)
108
+ #
109
+ # def parse_cancel_shipment_response(
110
+ # self, response: Deserializable
111
+ # ) -> Tuple[ConfirmationDetails, List[Message]]:
112
+ # return parse_shipment_cancel_response(response, self.settings)
113
+
114
+ def parse_tracking_response(
115
+ self, response: Deserializable
116
+ ) -> Tuple[List[TrackingDetails], List[Message]]:
117
+ return parse_tracking_response(response, self.settings)
@@ -0,0 +1,35 @@
1
+ from typing import List
2
+ from karrio.core.utils import (
3
+ DP,
4
+ request as http,
5
+ Serializable,
6
+ Deserializable,
7
+ exec_async,
8
+ )
9
+ from karrio.api.proxy import Proxy as BaseProxy
10
+ from karrio.mappers.royalmail.settings import Settings
11
+
12
+
13
+ class Proxy(BaseProxy):
14
+ settings: Settings
15
+
16
+ """ Proxy Methods """
17
+
18
+ def get_tracking(self, request: Serializable) -> Deserializable:
19
+ def _get_tracking(mail_piece_id: str):
20
+ return http(
21
+ url=f"{self.settings.server_url}/mailpieces/v2/{mail_piece_id}/events",
22
+ trace=self.trace_as("json"),
23
+ method="GET",
24
+ headers={
25
+ "Accept": "application/json",
26
+ "X-IBM-Client-Id": self.settings.client_id,
27
+ "X-IBM-Client-Secret": self.settings.client_secret,
28
+ "X-Accept-RMG-Terms": "yes",
29
+ },
30
+ )
31
+
32
+ responses: List[dict] = exec_async(_get_tracking, request.serialize())
33
+ return Deserializable(
34
+ responses, lambda res: [DP.to_dict(r) for r in res if any(r.strip())]
35
+ )
@@ -0,0 +1,21 @@
1
+ """Karrio Royal Mail settings."""
2
+
3
+ import attr
4
+ from karrio.providers.royalmail.utils import Settings as BaseSettings
5
+
6
+
7
+ @attr.s(auto_attribs=True)
8
+ class Settings(BaseSettings):
9
+ """Royal Mail connection settings."""
10
+
11
+ # Carrier specific properties
12
+ client_id: str
13
+ client_secret: str
14
+
15
+ # Base properties
16
+ id: str = None
17
+ test_mode: bool = False
18
+ carrier_id: str = "royalmail"
19
+ account_country_code: str = "UK"
20
+ metadata: dict = {}
21
+ config: dict = {}
@@ -0,0 +1,21 @@
1
+ import karrio.core.metadata as metadata
2
+ import karrio.mappers.royalmail as mappers
3
+ # import karrio.providers.royalmail.units as units
4
+
5
+
6
+ METADATA = metadata.PluginMetadata(
7
+ status="beta",
8
+ id="royalmail",
9
+ label="Royal Mail",
10
+
11
+ # Integrations
12
+ Mapper=mappers.Mapper,
13
+ Proxy=mappers.Proxy,
14
+ Settings=mappers.Settings,
15
+
16
+ # Data Units
17
+ # options=units.OptionCode,
18
+ # package_presets=units.PackagePresets,
19
+ # packaging_types=units.PackagingType,
20
+ # services=units.Serives,
21
+ )
@@ -0,0 +1,24 @@
1
+ from karrio.providers.royalmail.utils import Settings
2
+ # from karrio.providers.royalmail.rate import parse_rate_response, rate_request
3
+ # from karrio.providers.royalmail.address import (
4
+ # parse_address_validation_response,
5
+ # address_validation_request
6
+ # )
7
+ # from karrio.providers.royalmail.shipment import (
8
+ # parse_shipment_cancel_response,
9
+ # parse_shipment_response,
10
+ # shipment_cancel_request,
11
+ # shipment_request,
12
+ # )
13
+ # from karrio.providers.royalmail.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.royalmail.tracking import (
22
+ parse_tracking_response,
23
+ tracking_request,
24
+ )
@@ -0,0 +1,21 @@
1
+ from typing import List
2
+ from karrio.schemas.royalmail.errors import Errors
3
+ from karrio.providers.royalmail import Settings
4
+ from karrio.core.models import Message
5
+
6
+
7
+ def parse_error_response(response: List[dict], settings: Settings) -> List[Message]:
8
+ errors = [Errors(**e) for e in response]
9
+
10
+ return [
11
+ Message(
12
+ # context info
13
+ carrier_name=settings.carrier_name,
14
+ carrier_id=settings.carrier_id,
15
+ # carrier error info
16
+ code=str(error.httpCode),
17
+ message=error.httpMessage,
18
+ details=dict(information=error.moreInformation, errors=error.errors),
19
+ )
20
+ for error in errors
21
+ ]
@@ -0,0 +1,54 @@
1
+ from typing import List, Tuple
2
+ from karrio.schemas.royalmail.tracking import MailPieces
3
+ from karrio.core.models import (
4
+ TrackingEvent,
5
+ TrackingDetails,
6
+ TrackingRequest,
7
+ Message,
8
+ )
9
+ from karrio.providers.royalmail.utils import Settings
10
+ from karrio.providers.royalmail.error import parse_error_response
11
+ import karrio.lib as lib
12
+
13
+
14
+ def parse_tracking_response(
15
+ _response: lib.Deserializable[List[dict]],
16
+ settings: Settings,
17
+ ) -> Tuple[List[TrackingDetails], List[Message]]:
18
+ response = _response.deserialize()
19
+ errors = [e for e in response if "mailPieces" not in e]
20
+ details = [
21
+ _extract_detail(d["mailPieces"], settings)
22
+ for d in response
23
+ if "mailPieces" in d
24
+ ]
25
+
26
+ return details, parse_error_response(errors, settings)
27
+
28
+
29
+ def _extract_detail(data: dict, settings: Settings) -> TrackingDetails:
30
+ detail = lib.to_object(MailPieces, data)
31
+
32
+ return TrackingDetails(
33
+ carrier_name=settings.carrier_name,
34
+ carrier_id=settings.carrier_id,
35
+ tracking_number=detail.mailPieceId,
36
+ delivered=("Delivered" in detail.summary.lastEventName),
37
+ events=[
38
+ TrackingEvent(
39
+ date=lib.fdate(event.eventDateTime, "%Y-%m-%dT%H:%M:%S%z"),
40
+ description=event.eventName,
41
+ location=event.locationName,
42
+ code=event.eventCode,
43
+ time=lib.flocaltime(event.eventDateTime, "%Y-%m-%dT%H:%M:%S%z"),
44
+ )
45
+ for event in detail.events
46
+ ],
47
+ estimated_delivery=lib.fdate(detail.estimatedDelivery.date, "%Y-%m-%d"),
48
+ )
49
+
50
+
51
+ def tracking_request(payload: TrackingRequest, _) -> lib.Serializable:
52
+ request = payload.tracking_numbers
53
+
54
+ return lib.Serializable(request)
@@ -0,0 +1,46 @@
1
+ """ Royal Mail 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,25 @@
1
+ from karrio.core import Settings as BaseSettings
2
+
3
+
4
+ class Settings(BaseSettings):
5
+ """Royal Mail connection settings."""
6
+
7
+ # Carrier specific properties
8
+ client_id: str
9
+ client_secret: str
10
+
11
+ id: str = None
12
+ account_country_code: str = "UK"
13
+ metadata: dict = {}
14
+
15
+ @property
16
+ def carrier_name(self):
17
+ return "royalmail"
18
+
19
+ @property
20
+ def server_url(self):
21
+ return (
22
+ "https://api.royalmail.net"
23
+ if self.test_mode
24
+ else "https://api.royalmail.net"
25
+ )
File without changes
@@ -0,0 +1,19 @@
1
+ import attr
2
+ import jstruct
3
+ import typing
4
+
5
+
6
+ @attr.s(auto_attribs=True)
7
+ class Error:
8
+ errorCode: typing.Optional[str] = None
9
+ errorDescription: typing.Optional[str] = None
10
+ errorCause: typing.Optional[str] = None
11
+ errorResolution: typing.Optional[str] = None
12
+
13
+
14
+ @attr.s(auto_attribs=True)
15
+ class Errors:
16
+ httpCode: typing.Optional[int] = None
17
+ httpMessage: typing.Optional[str] = None
18
+ moreInformation: typing.Optional[str] = None
19
+ errors: typing.Optional[typing.List[Error]] = jstruct.JList[Error]
@@ -0,0 +1,86 @@
1
+ import attr
2
+ import jstruct
3
+ import typing
4
+
5
+
6
+ @attr.s(auto_attribs=True)
7
+ class EstimatedDelivery:
8
+ date: typing.Optional[str] = None
9
+ startOfEstimatedWindow: typing.Optional[str] = None
10
+ endOfEstimatedWindow: typing.Optional[str] = None
11
+
12
+
13
+ @attr.s(auto_attribs=True)
14
+ class Event:
15
+ eventCode: typing.Optional[str] = None
16
+ eventName: typing.Optional[str] = None
17
+ eventDateTime: typing.Optional[str] = None
18
+ locationName: typing.Optional[str] = None
19
+
20
+
21
+ @attr.s(auto_attribs=True)
22
+ class Redelivery:
23
+ href: typing.Optional[str] = None
24
+ title: typing.Optional[str] = None
25
+ description: typing.Optional[str] = None
26
+
27
+
28
+ @attr.s(auto_attribs=True)
29
+ class Links:
30
+ summary: typing.Optional[Redelivery] = jstruct.JStruct[Redelivery]
31
+ signature: typing.Optional[Redelivery] = jstruct.JStruct[Redelivery]
32
+ redelivery: typing.Optional[Redelivery] = jstruct.JStruct[Redelivery]
33
+
34
+
35
+ @attr.s(auto_attribs=True)
36
+ class Signature:
37
+ recipientName: typing.Optional[str] = None
38
+ signatureDateTime: typing.Optional[str] = None
39
+ imageId: typing.Optional[str] = None
40
+
41
+
42
+ @attr.s(auto_attribs=True)
43
+ class InternationalPostalProvider:
44
+ url: typing.Optional[str] = None
45
+ title: typing.Optional[str] = None
46
+ description: typing.Optional[str] = None
47
+
48
+
49
+ @attr.s(auto_attribs=True)
50
+ class Summary:
51
+ uniqueItemId: typing.Optional[str] = None
52
+ oneDBarcode: typing.Optional[str] = None
53
+ productId: typing.Optional[str] = None
54
+ productName: typing.Optional[str] = None
55
+ productDescription: typing.Optional[str] = None
56
+ productCategory: typing.Optional[str] = None
57
+ destinationCountryCode: typing.Optional[str] = None
58
+ destinationCountryName: typing.Optional[str] = None
59
+ originCountryCode: typing.Optional[str] = None
60
+ originCountryName: typing.Optional[str] = None
61
+ lastEventCode: typing.Optional[str] = None
62
+ lastEventName: typing.Optional[str] = None
63
+ lastEventDateTime: typing.Optional[str] = None
64
+ lastEventLocationName: typing.Optional[str] = None
65
+ statusDescription: typing.Optional[str] = None
66
+ statusCategory: typing.Optional[str] = None
67
+ statusHelpText: typing.Optional[str] = None
68
+ summaryLine: typing.Optional[str] = None
69
+ internationalPostalProvider: typing.Optional[InternationalPostalProvider] = jstruct.JStruct[InternationalPostalProvider]
70
+
71
+
72
+ @attr.s(auto_attribs=True)
73
+ class MailPieces:
74
+ mailPieceId: typing.Optional[str] = None
75
+ carrierShortName: typing.Optional[str] = None
76
+ carrierFullName: typing.Optional[str] = None
77
+ summary: typing.Optional[Summary] = jstruct.JStruct[Summary]
78
+ signature: typing.Optional[Signature] = jstruct.JStruct[Signature]
79
+ estimatedDelivery: typing.Optional[EstimatedDelivery] = jstruct.JStruct[EstimatedDelivery]
80
+ events: typing.Optional[typing.List[Event]] = jstruct.JList[Event]
81
+ links: typing.Optional[Links] = jstruct.JStruct[Links]
82
+
83
+
84
+ @attr.s(auto_attribs=True)
85
+ class Tracking:
86
+ mailPieces: typing.Optional[MailPieces] = jstruct.JStruct[MailPieces]
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.4
2
+ Name: karrio_royalmail
3
+ Version: 2025.5rc1
4
+ Summary: Karrio - Royal Mail Shipping extension
5
+ Author-email: karrio <hello@karrio.io>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/karrioapi/karrio
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: karrio
14
+
15
+ # karrio.royalmail
16
+
17
+ This package is a Royal Mail extension of the [karrio](https://pypi.org/project/karrio) multi carrier shipping SDK.
18
+
19
+ ## Requirements
20
+
21
+ `Python 3.7+`
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install karrio.royalmail
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ import karrio.sdk as karrio
33
+ from karrio.mappers.royalmail.settings import Settings
34
+
35
+
36
+ # Initialize a carrier gateway
37
+ canadapost = karrio.gateway["royalmail"].create(
38
+ Settings(
39
+ ...
40
+ )
41
+ )
42
+ ```
43
+
44
+ Check the [Karrio Mutli-carrier SDK docs](https://docs.karrio.io) for Shipping API requests
@@ -0,0 +1,18 @@
1
+ karrio/mappers/royalmail/__init__.py,sha256=1tG6gGRxAoCPrCGX-uYNNj6TGmpAOBa4xeoWlkvSuBQ,155
2
+ karrio/mappers/royalmail/mapper.py,sha256=1X1n1LwODVVaXT6SjqLfL3wu_or4Cqu1Q6bMAbuMGQI,4091
3
+ karrio/mappers/royalmail/proxy.py,sha256=UhWm1pnDIAB97YQyHOtMX9k4dOKC1GWu_sCVz8lvM0I,1122
4
+ karrio/mappers/royalmail/settings.py,sha256=KRtxvBa67-G124vhUfkDS7MNMtgxbbS_fxE6rGnhttg,482
5
+ karrio/plugins/royalmail/__init__.py,sha256=mk8Ehum7FBkCkVLOE6b_GPSROewpcBRrvzsdtTHhdL8,507
6
+ karrio/providers/royalmail/__init__.py,sha256=qffDByM43WA2dHiclXLtuLmU35EqHwEDuUvGyKSnlNM,781
7
+ karrio/providers/royalmail/error.py,sha256=cGnLQUS7CNHFshTiD4kVeWR_8obeFbk57HYyUPz1htI,680
8
+ karrio/providers/royalmail/tracking.py,sha256=89o5uYXtygDLZygOODRGxytmrRsGs2S8QZ5Uqoze7ek,1752
9
+ karrio/providers/royalmail/units.py,sha256=lVaPNYMl_sIOUOi9VceCGJloNzPSu678GUqBr1DYdEI,1378
10
+ karrio/providers/royalmail/utils.py,sha256=U_mmAnbzYYoULaOhyGOFdcSPEF9mikOIeI0Ewesc5CQ,534
11
+ karrio/schemas/royalmail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ karrio/schemas/royalmail/errors.py,sha256=Va_0E1ETGNkN48w-eWFsarHq1vkp9hCv5mXY7V53P4I,519
13
+ karrio/schemas/royalmail/tracking.py,sha256=kP3N5ISI5Wz8Lq-O9VHi-y1G2Ng3inf4XoFhWo7TVFM,2989
14
+ karrio_royalmail-2025.5rc1.dist-info/METADATA,sha256=ZcoGs6opiLkMpgB-eW5qwD2ieqxDQZPsFVps4Hlb_Wg,1010
15
+ karrio_royalmail-2025.5rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ karrio_royalmail-2025.5rc1.dist-info/entry_points.txt,sha256=xS5bCUhqI29tWlwzL84qemzWJGg4T5z25p61SuAP4WA,63
17
+ karrio_royalmail-2025.5rc1.dist-info/top_level.txt,sha256=FZCY8Nwft8oEGHdl--xku8P3TrnOxu5dETEU_fWpRSM,20
18
+ karrio_royalmail-2025.5rc1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [karrio.plugins]
2
+ royalmail = karrio.plugins.royalmail:METADATA
@@ -0,0 +1,3 @@
1
+ dist
2
+ karrio
3
+ schemas