karrio-laposte 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.
- karrio/mappers/laposte/__init__.py +3 -0
- karrio/mappers/laposte/mapper.py +22 -0
- karrio/mappers/laposte/proxy.py +23 -0
- karrio/mappers/laposte/settings.py +21 -0
- karrio/plugins/laposte/__init__.py +20 -0
- karrio/providers/laposte/__init__.py +6 -0
- karrio/providers/laposte/error.py +32 -0
- karrio/providers/laposte/tracking.py +79 -0
- karrio/providers/laposte/units.py +57 -0
- karrio/providers/laposte/utils.py +24 -0
- karrio/schemas/laposte/__init__.py +0 -0
- karrio/schemas/laposte/error.py +14 -0
- karrio/schemas/laposte/tracking_response.py +61 -0
- karrio_laposte-2025.5rc1.dist-info/METADATA +45 -0
- karrio_laposte-2025.5rc1.dist-info/RECORD +18 -0
- karrio_laposte-2025.5rc1.dist-info/WHEEL +5 -0
- karrio_laposte-2025.5rc1.dist-info/entry_points.txt +2 -0
- karrio_laposte-2025.5rc1.dist-info/top_level.txt +3 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
"""Karrio La Poste 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.laposte as provider
|
8
|
+
import karrio.mappers.laposte.settings as provider_settings
|
9
|
+
|
10
|
+
|
11
|
+
class Mapper(mapper.Mapper):
|
12
|
+
settings: provider_settings.Settings
|
13
|
+
|
14
|
+
def create_tracking_request(
|
15
|
+
self, payload: models.TrackingRequest
|
16
|
+
) -> lib.Serializable:
|
17
|
+
return provider.tracking_request(payload, self.settings)
|
18
|
+
|
19
|
+
def parse_tracking_response(
|
20
|
+
self, response: lib.Deserializable
|
21
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
22
|
+
return provider.parse_tracking_response(response, self.settings)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""Karrio La Poste client proxy."""
|
2
|
+
|
3
|
+
import karrio.lib as lib
|
4
|
+
import karrio.api.proxy as proxy
|
5
|
+
import karrio.mappers.laposte.settings as provider_settings
|
6
|
+
|
7
|
+
|
8
|
+
class Proxy(proxy.Proxy):
|
9
|
+
settings: provider_settings.Settings
|
10
|
+
|
11
|
+
def get_tracking(self, request: lib.Serializable) -> lib.Deserializable:
|
12
|
+
idships = ",".join(request.serialize())
|
13
|
+
response = lib.request(
|
14
|
+
url=f"{self.settings.server_url}/idships/{idships}?lang={self.settings.lang}",
|
15
|
+
trace=self.trace_as("json"),
|
16
|
+
headers={
|
17
|
+
"accept": "application/json",
|
18
|
+
"X-Okapi-Key": self.settings.api_key,
|
19
|
+
},
|
20
|
+
method="GET",
|
21
|
+
)
|
22
|
+
|
23
|
+
return lib.Deserializable(response, lib.to_dict)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
"""Karrio La Poste client settings."""
|
2
|
+
|
3
|
+
import attr
|
4
|
+
import karrio.providers.laposte.utils as utils
|
5
|
+
|
6
|
+
|
7
|
+
@attr.s(auto_attribs=True)
|
8
|
+
class Settings(utils.Settings):
|
9
|
+
"""La Poste connection settings."""
|
10
|
+
|
11
|
+
# required carrier specific properties
|
12
|
+
api_key: str
|
13
|
+
lang: utils.LangEnum = "fr_FR" # type: ignore
|
14
|
+
|
15
|
+
# generic properties
|
16
|
+
id: str = ""
|
17
|
+
test_mode: bool = False
|
18
|
+
carrier_id: str = "laposte"
|
19
|
+
account_country_code: str = "FR"
|
20
|
+
metadata: dict = {}
|
21
|
+
config: dict = {}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import karrio.core.metadata as metadata
|
2
|
+
import karrio.mappers.laposte as mappers
|
3
|
+
import karrio.providers.laposte.units as units
|
4
|
+
|
5
|
+
|
6
|
+
METADATA = metadata.PluginMetadata(
|
7
|
+
status="production-ready",
|
8
|
+
id="laposte",
|
9
|
+
label="La Poste",
|
10
|
+
# Integrations
|
11
|
+
Mapper=mappers.Mapper,
|
12
|
+
Proxy=mappers.Proxy,
|
13
|
+
Settings=mappers.Settings,
|
14
|
+
# Data Units
|
15
|
+
is_hub=False,
|
16
|
+
# New fields
|
17
|
+
website="https://www.laposte.fr/",
|
18
|
+
documentation="https://www.lapostegroupe.com/en/services-mail-parcels-business-unit",
|
19
|
+
description="La Poste is a postal service company in France, operating in Metropolitan France and French overseas territories. The company provides mail delivery, parcel shipping, banking services, and digital solutions.",
|
20
|
+
)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import karrio.schemas.laposte.error as laposte
|
2
|
+
import typing
|
3
|
+
import karrio.lib as lib
|
4
|
+
import karrio.core.models as models
|
5
|
+
import karrio.providers.laposte.utils as provider_utils
|
6
|
+
|
7
|
+
|
8
|
+
def parse_error_response(
|
9
|
+
response: typing.Union[dict, typing.List[dict]],
|
10
|
+
settings: provider_utils.Settings,
|
11
|
+
**kwargs,
|
12
|
+
) -> typing.List[models.Message]:
|
13
|
+
responses = response if isinstance(response, list) else [response]
|
14
|
+
errors = [
|
15
|
+
lib.to_object(laposte.Error, res)
|
16
|
+
for res in responses
|
17
|
+
if (
|
18
|
+
not str(res.get("returnCode")).startswith("20")
|
19
|
+
or res.get("code") is not None
|
20
|
+
)
|
21
|
+
]
|
22
|
+
|
23
|
+
return [
|
24
|
+
models.Message(
|
25
|
+
carrier_id=settings.carrier_id,
|
26
|
+
carrier_name=settings.carrier_name,
|
27
|
+
code=error.returnCode or error.code,
|
28
|
+
message=error.returnMessage or error.message,
|
29
|
+
details={**kwargs},
|
30
|
+
)
|
31
|
+
for error in errors
|
32
|
+
]
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import karrio.schemas.laposte.tracking_response as laposte
|
2
|
+
import typing
|
3
|
+
import karrio.lib as lib
|
4
|
+
import karrio.core.units as units
|
5
|
+
import karrio.core.models as models
|
6
|
+
import karrio.providers.laposte.error as error
|
7
|
+
import karrio.providers.laposte.utils as provider_utils
|
8
|
+
import karrio.providers.laposte.units as provider_units
|
9
|
+
|
10
|
+
|
11
|
+
def parse_tracking_response(
|
12
|
+
_response: lib.Deserializable[typing.Union[dict, typing.List[dict]]],
|
13
|
+
settings: provider_utils.Settings,
|
14
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
15
|
+
response = _response.deserialize()
|
16
|
+
responses = response if isinstance(response, list) else [response]
|
17
|
+
messages = error.parse_error_response(responses, settings)
|
18
|
+
tracking_details = [
|
19
|
+
_extract_details(res["shipment"], settings)
|
20
|
+
for res in responses
|
21
|
+
if str(res.get("returnCode")).startswith("20")
|
22
|
+
]
|
23
|
+
|
24
|
+
return tracking_details, messages
|
25
|
+
|
26
|
+
|
27
|
+
def _extract_details(
|
28
|
+
data: dict,
|
29
|
+
settings: provider_utils.Settings,
|
30
|
+
) -> models.TrackingDetails:
|
31
|
+
shipment = lib.to_object(laposte.Shipment, data)
|
32
|
+
status = next(
|
33
|
+
(
|
34
|
+
status.name
|
35
|
+
for status in list(provider_units.TrackingStatus)
|
36
|
+
if shipment.event[0].code in status.value
|
37
|
+
),
|
38
|
+
provider_units.TrackingStatus.in_transit.name,
|
39
|
+
)
|
40
|
+
|
41
|
+
return models.TrackingDetails(
|
42
|
+
carrier_id=settings.carrier_id,
|
43
|
+
carrier_name=settings.carrier_name,
|
44
|
+
tracking_number=shipment.idShip,
|
45
|
+
status=status,
|
46
|
+
events=[
|
47
|
+
models.TrackingEvent(
|
48
|
+
date=lib.fdate(event.date, "%Y-%m-%dT%H:%M:%S%z"),
|
49
|
+
description=event.label,
|
50
|
+
code=event.code,
|
51
|
+
time=lib.flocaltime(event.date, "%Y-%m-%dT%H:%M:%S%z"),
|
52
|
+
location=None,
|
53
|
+
)
|
54
|
+
for event in shipment.event
|
55
|
+
],
|
56
|
+
estimated_delivery=lib.fdate(shipment.deliveryDate, "%Y-%m-%dT%H:%M:%S%z"),
|
57
|
+
delivered=shipment.isFinal,
|
58
|
+
info=models.TrackingInfo(
|
59
|
+
carrier_tracking_link=shipment.url,
|
60
|
+
expected_delivery=lib.fdate(shipment.estimDate, "%Y-%m-%dT%H:%M:%S%z"),
|
61
|
+
shipment_service=shipment.product,
|
62
|
+
shipping_date=lib.fdate(shipment.entryDate, "%Y-%m-%dT%H:%M:%S%z"),
|
63
|
+
shipment_origin_country=getattr(
|
64
|
+
shipment.contextData, "originCountry", None
|
65
|
+
),
|
66
|
+
shipment_destination_country=getattr(
|
67
|
+
shipment.contextData, "arrivalCountry", None
|
68
|
+
),
|
69
|
+
),
|
70
|
+
)
|
71
|
+
|
72
|
+
|
73
|
+
def tracking_request(
|
74
|
+
payload: models.TrackingRequest,
|
75
|
+
settings: provider_utils.Settings,
|
76
|
+
) -> lib.Serializable:
|
77
|
+
request = payload.tracking_numbers
|
78
|
+
|
79
|
+
return lib.Serializable(request)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import karrio.lib as lib
|
2
|
+
import karrio.core.units as units
|
3
|
+
|
4
|
+
|
5
|
+
class PackagingType(lib.StrEnum):
|
6
|
+
"""Carrier specific packaging type"""
|
7
|
+
|
8
|
+
PACKAGE = "PACKAGE"
|
9
|
+
|
10
|
+
""" Unified Packaging type mapping """
|
11
|
+
envelope = PACKAGE
|
12
|
+
pak = PACKAGE
|
13
|
+
tube = PACKAGE
|
14
|
+
pallet = PACKAGE
|
15
|
+
small_box = PACKAGE
|
16
|
+
medium_box = PACKAGE
|
17
|
+
your_packaging = PACKAGE
|
18
|
+
|
19
|
+
|
20
|
+
class ShippingService(lib.StrEnum):
|
21
|
+
"""Carrier specific services"""
|
22
|
+
|
23
|
+
laposte_standard_service = "La Poste Standard Service"
|
24
|
+
|
25
|
+
|
26
|
+
class ShippingOption(lib.Enum):
|
27
|
+
"""Carrier specific options"""
|
28
|
+
|
29
|
+
# laposte_option = lib.OptionEnum("code")
|
30
|
+
|
31
|
+
""" Unified Option type mapping """
|
32
|
+
# insurance = laposte_coverage # maps unified karrio option to carrier specific
|
33
|
+
|
34
|
+
pass
|
35
|
+
|
36
|
+
|
37
|
+
def shipping_options_initializer(
|
38
|
+
options: dict,
|
39
|
+
package_options: units.ShippingOptions = None,
|
40
|
+
) -> units.ShippingOptions:
|
41
|
+
"""
|
42
|
+
Apply default values to the given options.
|
43
|
+
"""
|
44
|
+
|
45
|
+
if package_options is not None:
|
46
|
+
options.update(package_options.content)
|
47
|
+
|
48
|
+
def items_filter(key: str) -> bool:
|
49
|
+
return key in ShippingOption # type: ignore
|
50
|
+
|
51
|
+
return units.ShippingOptions(options, ShippingOption, items_filter=items_filter)
|
52
|
+
|
53
|
+
|
54
|
+
class TrackingStatus(lib.Enum):
|
55
|
+
delivered = ["DI1"]
|
56
|
+
in_transit = [""]
|
57
|
+
out_for_delivery = ["MD2", "ET1"]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import karrio.lib as lib
|
2
|
+
import karrio.core as core
|
3
|
+
|
4
|
+
|
5
|
+
LangEnum = lib.units.create_enum("LangEnum", ["fr_FR", "en_US"])
|
6
|
+
|
7
|
+
|
8
|
+
class Settings(core.Settings):
|
9
|
+
"""La Poste connection settings."""
|
10
|
+
|
11
|
+
api_key: str
|
12
|
+
lang: LangEnum = "fr_FR" # type: ignore
|
13
|
+
|
14
|
+
@property
|
15
|
+
def carrier_name(self):
|
16
|
+
return "laposte"
|
17
|
+
|
18
|
+
@property
|
19
|
+
def server_url(self):
|
20
|
+
return "https://api.laposte.fr/suivi/v2"
|
21
|
+
|
22
|
+
@property
|
23
|
+
def tracking_url(self):
|
24
|
+
return "https://www.laposte.fr/outils/suivre-vos-envois?code={}"
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import attr
|
2
|
+
import jstruct
|
3
|
+
import typing
|
4
|
+
|
5
|
+
|
6
|
+
@attr.s(auto_attribs=True)
|
7
|
+
class Error:
|
8
|
+
returnCode: typing.Optional[int] = None
|
9
|
+
returnMessage: typing.Optional[str] = None
|
10
|
+
lang: typing.Optional[str] = None
|
11
|
+
scope: typing.Optional[str] = None
|
12
|
+
idShip: typing.Optional[str] = None
|
13
|
+
code: typing.Optional[str] = None
|
14
|
+
message: typing.Optional[str] = None
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import attr
|
2
|
+
import jstruct
|
3
|
+
import typing
|
4
|
+
|
5
|
+
|
6
|
+
@attr.s(auto_attribs=True)
|
7
|
+
class DeliveryChoice:
|
8
|
+
deliveryChoice: typing.Optional[int] = None
|
9
|
+
|
10
|
+
|
11
|
+
@attr.s(auto_attribs=True)
|
12
|
+
class ContextData:
|
13
|
+
deliveryChoice: typing.Optional[DeliveryChoice] = jstruct.JStruct[DeliveryChoice]
|
14
|
+
originCountry: typing.Optional[str] = None
|
15
|
+
arrivalCountry: typing.Optional[str] = None
|
16
|
+
|
17
|
+
|
18
|
+
@attr.s(auto_attribs=True)
|
19
|
+
class Event:
|
20
|
+
code: typing.Optional[str] = None
|
21
|
+
label: typing.Optional[str] = None
|
22
|
+
date: typing.Optional[str] = None
|
23
|
+
|
24
|
+
|
25
|
+
@attr.s(auto_attribs=True)
|
26
|
+
class Timeline:
|
27
|
+
shortLabel: typing.Optional[str] = None
|
28
|
+
longLabel: typing.Optional[str] = None
|
29
|
+
id: typing.Optional[int] = None
|
30
|
+
country: typing.Optional[str] = None
|
31
|
+
status: typing.Optional[bool] = None
|
32
|
+
type: typing.Optional[int] = None
|
33
|
+
date: typing.Optional[str] = None
|
34
|
+
|
35
|
+
|
36
|
+
@attr.s(auto_attribs=True)
|
37
|
+
class Shipment:
|
38
|
+
idShip: typing.Optional[str] = None
|
39
|
+
holder: typing.Optional[int] = None
|
40
|
+
product: typing.Optional[str] = None
|
41
|
+
isFinal: typing.Optional[bool] = None
|
42
|
+
deliveryDate: typing.Optional[str] = None
|
43
|
+
entryDate: typing.Optional[str] = None
|
44
|
+
timeline: typing.Optional[typing.List[Timeline]] = jstruct.JList[Timeline]
|
45
|
+
event: typing.Optional[typing.List[Event]] = jstruct.JList[Event]
|
46
|
+
contextData: typing.Optional[ContextData] = jstruct.JStruct[ContextData]
|
47
|
+
estimDate: typing.Optional[str] = None
|
48
|
+
url: typing.Optional[str] = None
|
49
|
+
|
50
|
+
|
51
|
+
@attr.s(auto_attribs=True)
|
52
|
+
class Response:
|
53
|
+
lang: typing.Optional[str] = None
|
54
|
+
scope: typing.Optional[str] = None
|
55
|
+
returnCode: typing.Optional[int] = None
|
56
|
+
shipment: typing.Optional[Shipment] = jstruct.JStruct[Shipment]
|
57
|
+
|
58
|
+
|
59
|
+
@attr.s(auto_attribs=True)
|
60
|
+
class TrackingResponse:
|
61
|
+
responses: typing.Optional[typing.List[Response]] = jstruct.JList[Response]
|
@@ -0,0 +1,45 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: karrio_laposte
|
3
|
+
Version: 2025.5rc1
|
4
|
+
Summary: Karrio - La Poste 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.11
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
Requires-Dist: karrio
|
14
|
+
|
15
|
+
|
16
|
+
# karrio.laposte
|
17
|
+
|
18
|
+
This package is a La Poste extension of the [karrio](https://pypi.org/project/karrio) multi carrier shipping SDK.
|
19
|
+
|
20
|
+
## Requirements
|
21
|
+
|
22
|
+
`Python 3.11+`
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
```bash
|
27
|
+
pip install karrio.laposte
|
28
|
+
```
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
```python
|
33
|
+
import karrio.sdk as karrio
|
34
|
+
from karrio.mappers.laposte.settings import Settings
|
35
|
+
|
36
|
+
|
37
|
+
# Initialize a carrier gateway
|
38
|
+
laposte = karrio.gateway["laposte"].create(
|
39
|
+
Settings(
|
40
|
+
...
|
41
|
+
)
|
42
|
+
)
|
43
|
+
```
|
44
|
+
|
45
|
+
Check the [Karrio Mutli-carrier SDK docs](https://docs.karrio.io) for Shipping API requests
|
@@ -0,0 +1,18 @@
|
|
1
|
+
karrio/mappers/laposte/__init__.py,sha256=Vc5jW0ohCxnxsv_msdf4ftlVcg5tF9_ETsne2u-UxYk,148
|
2
|
+
karrio/mappers/laposte/mapper.py,sha256=TFfFyez_qeX94yxlFMydzNp2B7NvynTHY_8o0irGiMk,735
|
3
|
+
karrio/mappers/laposte/proxy.py,sha256=NQyWL0rc-ky80o1NF2eNOpLTq9q6k6RQHosSjDrwgsQ,745
|
4
|
+
karrio/mappers/laposte/settings.py,sha256=k7J2BUyX4U8g2T3xFTrNbwvSq0TkSjdBwl3BzPgv98w,498
|
5
|
+
karrio/plugins/laposte/__init__.py,sha256=s5MbbVNYqW4OLp_lHKlAR8q-Ws0pLv9JPFa1Kp2fdc0,749
|
6
|
+
karrio/providers/laposte/__init__.py,sha256=UmsiUvmZL8zOhAcoZMippZ6okpCPa8BcnWCfNEkSYWw,154
|
7
|
+
karrio/providers/laposte/error.py,sha256=oohq1_PrH_AwIbMzDHAwN9Q6pSCdifUw8z6Dz-bt6VA,948
|
8
|
+
karrio/providers/laposte/tracking.py,sha256=LgrZYJl8TF7XM6UQ3ZKh0d9cr14Z8ZG1iPYqHAeHdo0,2757
|
9
|
+
karrio/providers/laposte/units.py,sha256=dOC62QEibI0bmI4Ukobvj81cH1udqnzHTbIGNBAsQEk,1332
|
10
|
+
karrio/providers/laposte/utils.py,sha256=BYbMIdsf-vIQltFPMTy53JlyTF6g9Wva1shPmheIczI,529
|
11
|
+
karrio/schemas/laposte/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
+
karrio/schemas/laposte/error.py,sha256=JUKNxIEHhNVZ6aTGyA9QeF6WJRcnv4z_T-lEe4DPNHk,370
|
13
|
+
karrio/schemas/laposte/tracking_response.py,sha256=x_VPNtzg4LSrNKPFffzZ0H-tzZNrkLcnQIVXsKJRo7A,1822
|
14
|
+
karrio_laposte-2025.5rc1.dist-info/METADATA,sha256=ME6McQbh1vvJHh9T17Dr085pefSCn6aAUy_TOr2sTqs,996
|
15
|
+
karrio_laposte-2025.5rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
karrio_laposte-2025.5rc1.dist-info/entry_points.txt,sha256=jFXL-V5ZRLAXwmk3DrdkzFpby2AHihbknUW_61y9Ft8,59
|
17
|
+
karrio_laposte-2025.5rc1.dist-info/top_level.txt,sha256=FZCY8Nwft8oEGHdl--xku8P3TrnOxu5dETEU_fWpRSM,20
|
18
|
+
karrio_laposte-2025.5rc1.dist-info/RECORD,,
|