karrio-dhl-poland 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/dhl_poland/__init__.py +3 -0
- karrio/mappers/dhl_poland/mapper.py +51 -0
- karrio/mappers/dhl_poland/proxy.py +59 -0
- karrio/mappers/dhl_poland/settings.py +34 -0
- karrio/plugins/dhl_poland/__init__.py +23 -0
- karrio/providers/dhl_poland/__init__.py +11 -0
- karrio/providers/dhl_poland/error.py +21 -0
- karrio/providers/dhl_poland/shipment/__init__.py +8 -0
- karrio/providers/dhl_poland/shipment/cancel.py +55 -0
- karrio/providers/dhl_poland/shipment/create.py +307 -0
- karrio/providers/dhl_poland/tracking.py +91 -0
- karrio/providers/dhl_poland/units.py +146 -0
- karrio/providers/dhl_poland/utils.py +62 -0
- karrio/schemas/dhl_poland/__init__.py +0 -0
- karrio/schemas/dhl_poland/services.py +43970 -0
- karrio_dhl_poland-2025.5rc1.dist-info/METADATA +44 -0
- karrio_dhl_poland-2025.5rc1.dist-info/RECORD +20 -0
- karrio_dhl_poland-2025.5rc1.dist-info/WHEEL +5 -0
- karrio_dhl_poland-2025.5rc1.dist-info/entry_points.txt +2 -0
- karrio_dhl_poland-2025.5rc1.dist-info/top_level.txt +3 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
"""Karrio DHL Poland 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.universal.providers.rating as universal_provider
|
8
|
+
import karrio.providers.dhl_poland as provider
|
9
|
+
import karrio.mappers.dhl_poland.settings as provider_settings
|
10
|
+
|
11
|
+
|
12
|
+
class Mapper(mapper.Mapper):
|
13
|
+
settings: provider_settings.Settings
|
14
|
+
|
15
|
+
def create_rate_request(self, payload: models.RateRequest) -> lib.Serializable:
|
16
|
+
return universal_provider.rate_request(payload, self.settings)
|
17
|
+
|
18
|
+
def create_tracking_request(
|
19
|
+
self, payload: models.TrackingRequest
|
20
|
+
) -> lib.Serializable:
|
21
|
+
return provider.tracking_request(payload, self.settings)
|
22
|
+
|
23
|
+
def create_shipment_request(
|
24
|
+
self, payload: models.ShipmentRequest
|
25
|
+
) -> lib.Serializable:
|
26
|
+
return provider.shipment_request(payload, self.settings)
|
27
|
+
|
28
|
+
def create_cancel_shipment_request(
|
29
|
+
self, payload: models.ShipmentCancelRequest
|
30
|
+
) -> lib.Serializable:
|
31
|
+
return provider.shipment_cancel_request(payload, self.settings)
|
32
|
+
|
33
|
+
def parse_cancel_shipment_response(
|
34
|
+
self, response: lib.Deserializable
|
35
|
+
) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
|
36
|
+
return provider.parse_shipment_cancel_response(response, self.settings)
|
37
|
+
|
38
|
+
def parse_rate_response(
|
39
|
+
self, response: lib.Deserializable
|
40
|
+
) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
|
41
|
+
return universal_provider.parse_rate_response(response, self.settings)
|
42
|
+
|
43
|
+
def parse_shipment_response(
|
44
|
+
self, response: lib.Deserializable
|
45
|
+
) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
|
46
|
+
return provider.parse_shipment_response(response, self.settings)
|
47
|
+
|
48
|
+
def parse_tracking_response(
|
49
|
+
self, response: lib.Deserializable
|
50
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
51
|
+
return provider.parse_tracking_response(response, self.settings)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
"""Karrio DHL Poland client proxy module."""
|
2
|
+
import karrio.lib as lib
|
3
|
+
import karrio.api.proxy as proxy
|
4
|
+
import karrio.universal.mappers.rating_proxy as rating_proxy
|
5
|
+
import karrio.mappers.dhl_poland.settings as provider_settings
|
6
|
+
|
7
|
+
|
8
|
+
class Proxy(rating_proxy.RatingMixinProxy, proxy.Proxy):
|
9
|
+
settings: provider_settings.Settings
|
10
|
+
|
11
|
+
def _send_request(self, request: lib.Serializable, soapaction: str) -> str:
|
12
|
+
return lib.request(
|
13
|
+
url=f"{self.settings.server_url}",
|
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": soapaction,
|
20
|
+
},
|
21
|
+
)
|
22
|
+
|
23
|
+
def get_rates(self, request: lib.Serializable) -> lib.Deserializable:
|
24
|
+
return super().get_rates(request)
|
25
|
+
|
26
|
+
def get_tracking(self, requests: lib.Serializable) -> lib.Deserializable:
|
27
|
+
responses = lib.run_asynchronously(
|
28
|
+
lambda request: dict(
|
29
|
+
number=request[0],
|
30
|
+
data=self._send_request(
|
31
|
+
lib.Serializable(request[1]),
|
32
|
+
soapaction=f"{self.settings.server_url}#getTrackAndTraceInfo",
|
33
|
+
),
|
34
|
+
),
|
35
|
+
requests.serialize().items(),
|
36
|
+
)
|
37
|
+
|
38
|
+
return lib.Deserializable(
|
39
|
+
responses,
|
40
|
+
lambda results: {
|
41
|
+
result["number"]: lib.to_element(result["data"]) for result in results
|
42
|
+
},
|
43
|
+
)
|
44
|
+
|
45
|
+
def create_shipment(self, request: lib.Serializable) -> lib.Deserializable:
|
46
|
+
response = self._send_request(
|
47
|
+
request,
|
48
|
+
soapaction=f"{self.settings.server_url}#createShipment",
|
49
|
+
)
|
50
|
+
|
51
|
+
return lib.Deserializable(response, lib.to_element)
|
52
|
+
|
53
|
+
def cancel_shipment(self, request: lib.Serializable) -> lib.Deserializable:
|
54
|
+
response = self._send_request(
|
55
|
+
request,
|
56
|
+
soapaction=f"{self.settings.server_url}#deleteShipment",
|
57
|
+
)
|
58
|
+
|
59
|
+
return lib.Deserializable(response, lib.to_element)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
"""Karrio DHL Parcel Poland client settings."""
|
2
|
+
|
3
|
+
import attr
|
4
|
+
import typing
|
5
|
+
import jstruct
|
6
|
+
import karrio.core.models as models
|
7
|
+
import karrio.providers.dhl_poland.units as provider_units
|
8
|
+
import karrio.providers.dhl_poland.utils as provider_utils
|
9
|
+
from karrio.universal.mappers.rating_proxy import RatingMixinSettings
|
10
|
+
|
11
|
+
|
12
|
+
@attr.s(auto_attribs=True)
|
13
|
+
class Settings(provider_utils.Settings, RatingMixinSettings):
|
14
|
+
"""DHL Parcel Poland connection settings."""
|
15
|
+
|
16
|
+
username: str # type: ignore
|
17
|
+
password: str # type: ignore
|
18
|
+
account_number: str = None
|
19
|
+
|
20
|
+
id: str = None
|
21
|
+
test_mode: bool = False
|
22
|
+
carrier_id: str = "dhl_poland"
|
23
|
+
account_country_code: str = "PL"
|
24
|
+
metadata: dict = {}
|
25
|
+
config: dict = {}
|
26
|
+
|
27
|
+
services: typing.List[models.ServiceLevel] = jstruct.JList[models.ServiceLevel, False, dict(default=provider_units.DEFAULT_SERVICES)] # type: ignore
|
28
|
+
|
29
|
+
@property
|
30
|
+
def shipping_services(self) -> typing.List[models.ServiceLevel]:
|
31
|
+
if any(self.services or []):
|
32
|
+
return self.services
|
33
|
+
|
34
|
+
return provider_units.DEFAULT_SERVICES
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import karrio.core.metadata as metadata
|
2
|
+
import karrio.mappers.dhl_poland as mappers
|
3
|
+
from karrio.providers.dhl_poland import units
|
4
|
+
|
5
|
+
|
6
|
+
METADATA = metadata.PluginMetadata(
|
7
|
+
status="production-ready",
|
8
|
+
id="dhl_poland",
|
9
|
+
label="DHL Parcel Poland",
|
10
|
+
# Integrations
|
11
|
+
Mapper=mappers.Mapper,
|
12
|
+
Proxy=mappers.Proxy,
|
13
|
+
Settings=mappers.Settings,
|
14
|
+
# Data Units
|
15
|
+
services=units.Service,
|
16
|
+
options=units.ShippingOption,
|
17
|
+
packaging_types=units.PackagingType,
|
18
|
+
service_levels=units.DEFAULT_SERVICES,
|
19
|
+
# New fields
|
20
|
+
website="https://dhl24.com.pl/en",
|
21
|
+
documentation="https://dhl24.com.pl/en/webapi2/doc.html",
|
22
|
+
description="Global Logistics and International Shipping Poland.",
|
23
|
+
)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from karrio.providers.dhl_poland.utils import Settings
|
2
|
+
from karrio.providers.dhl_poland.shipment import (
|
3
|
+
parse_shipment_cancel_response,
|
4
|
+
parse_shipment_response,
|
5
|
+
shipment_cancel_request,
|
6
|
+
shipment_request,
|
7
|
+
)
|
8
|
+
from karrio.providers.dhl_poland.tracking import (
|
9
|
+
parse_tracking_response,
|
10
|
+
tracking_request,
|
11
|
+
)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from typing import List
|
2
|
+
from pysoap.envelope import Fault
|
3
|
+
from karrio.core.models import Message
|
4
|
+
from karrio.core.utils import Element, XP
|
5
|
+
from karrio.providers.dhl_poland.utils import Settings
|
6
|
+
|
7
|
+
|
8
|
+
def parse_error_response(
|
9
|
+
response: Element, settings: Settings, details: dict = None
|
10
|
+
) -> List[Message]:
|
11
|
+
errors = XP.find("Fault", response, Fault)
|
12
|
+
return [
|
13
|
+
Message(
|
14
|
+
carrier_id=settings.carrier_id,
|
15
|
+
carrier_name=settings.carrier_name,
|
16
|
+
message=error.faultstring,
|
17
|
+
code=error.faultcode,
|
18
|
+
details=details,
|
19
|
+
)
|
20
|
+
for error in errors
|
21
|
+
]
|
@@ -0,0 +1,55 @@
|
|
1
|
+
from typing import List, Tuple
|
2
|
+
from karrio.schemas.dhl_poland.services import (
|
3
|
+
deleteShipment,
|
4
|
+
DeleteShipmentRequest,
|
5
|
+
)
|
6
|
+
from karrio.core.models import ShipmentCancelRequest, ConfirmationDetails, Message
|
7
|
+
from karrio.core.utils import (
|
8
|
+
create_envelope,
|
9
|
+
Envelope,
|
10
|
+
Element,
|
11
|
+
Serializable,
|
12
|
+
)
|
13
|
+
from karrio.providers.dhl_poland.error import parse_error_response
|
14
|
+
from karrio.providers.dhl_poland.utils import Settings
|
15
|
+
import karrio.lib as lib
|
16
|
+
|
17
|
+
|
18
|
+
def parse_shipment_cancel_response(
|
19
|
+
_response: lib.Deserializable[Element], settings: Settings
|
20
|
+
) -> Tuple[ConfirmationDetails, List[Message]]:
|
21
|
+
response = _response.deserialize()
|
22
|
+
errors = parse_error_response(response, settings)
|
23
|
+
success = len(errors) == 0
|
24
|
+
confirmation: ConfirmationDetails = (
|
25
|
+
ConfirmationDetails(
|
26
|
+
carrier_id=settings.carrier_id,
|
27
|
+
carrier_name=settings.carrier_name,
|
28
|
+
success=success,
|
29
|
+
operation="Cancel Shipment",
|
30
|
+
)
|
31
|
+
if success
|
32
|
+
else None
|
33
|
+
)
|
34
|
+
|
35
|
+
return confirmation, errors
|
36
|
+
|
37
|
+
|
38
|
+
def shipment_cancel_request(
|
39
|
+
payload: ShipmentCancelRequest, settings: Settings
|
40
|
+
) -> Serializable:
|
41
|
+
request = create_envelope(
|
42
|
+
body_content=deleteShipment(
|
43
|
+
authData=settings.auth_data,
|
44
|
+
shipment=DeleteShipmentRequest(
|
45
|
+
shipmentIdentificationNumber=payload.shipment_identifier
|
46
|
+
),
|
47
|
+
)
|
48
|
+
)
|
49
|
+
|
50
|
+
return Serializable(
|
51
|
+
request,
|
52
|
+
lambda request: settings.serialize(
|
53
|
+
request, "deleteShipment", settings.server_url
|
54
|
+
),
|
55
|
+
)
|
@@ -0,0 +1,307 @@
|
|
1
|
+
import karrio.schemas.dhl_poland.services as dhl
|
2
|
+
import time
|
3
|
+
import typing
|
4
|
+
import karrio.lib as lib
|
5
|
+
import karrio.core.units as units
|
6
|
+
import karrio.core.models as models
|
7
|
+
import karrio.providers.dhl_poland.error as provider_error
|
8
|
+
import karrio.providers.dhl_poland.units as provider_units
|
9
|
+
import karrio.providers.dhl_poland.utils as provider_utils
|
10
|
+
|
11
|
+
|
12
|
+
def parse_shipment_response(
|
13
|
+
_response: lib.Deserializable[lib.Element], settings: provider_utils.Settings
|
14
|
+
) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
|
15
|
+
response = _response.deserialize()
|
16
|
+
errors = provider_error.parse_error_response(response, settings)
|
17
|
+
shipment = (
|
18
|
+
_extract_details(response, settings)
|
19
|
+
if lib.find_element("createShipmentResult", response, first=True) is not None
|
20
|
+
else None
|
21
|
+
)
|
22
|
+
|
23
|
+
return shipment, errors
|
24
|
+
|
25
|
+
|
26
|
+
def _extract_details(
|
27
|
+
response: lib.Element,
|
28
|
+
settings: provider_utils.Settings,
|
29
|
+
) -> models.ShipmentDetails:
|
30
|
+
shipment: dhl.CreateShipmentResponse = lib.find_element(
|
31
|
+
"createShipmentResult", response, dhl.CreateShipmentResponse, first=True
|
32
|
+
)
|
33
|
+
|
34
|
+
return models.ShipmentDetails(
|
35
|
+
carrier_id=settings.carrier_id,
|
36
|
+
carrier_name=settings.carrier_name,
|
37
|
+
tracking_number=shipment.shipmentNotificationNumber,
|
38
|
+
shipment_identifier=shipment.shipmentTrackingNumber,
|
39
|
+
docs=models.Documents(
|
40
|
+
label=shipment.label.labelContent,
|
41
|
+
invoice=shipment.label.fvProformaContent,
|
42
|
+
),
|
43
|
+
meta=dict(
|
44
|
+
carrier_tracking_link=settings.tracking_url.format(
|
45
|
+
shipment.shipmentNotificationNumber
|
46
|
+
),
|
47
|
+
),
|
48
|
+
)
|
49
|
+
|
50
|
+
|
51
|
+
def shipment_request(
|
52
|
+
payload: models.ShipmentRequest,
|
53
|
+
settings: provider_utils.Settings,
|
54
|
+
) -> lib.Serializable:
|
55
|
+
packages = lib.to_packages(
|
56
|
+
payload.parcels,
|
57
|
+
required=["weight"],
|
58
|
+
package_option_type=provider_units.ShippingOption,
|
59
|
+
)
|
60
|
+
shipper = lib.to_address(payload.shipper)
|
61
|
+
recipient = lib.to_address(payload.recipient)
|
62
|
+
customs = lib.to_customs_info(payload.customs, weight_unit=packages.weight_unit)
|
63
|
+
options = lib.to_shipping_options(
|
64
|
+
payload.options,
|
65
|
+
package_options=packages.options,
|
66
|
+
initializer=provider_units.shipping_options_initializer,
|
67
|
+
)
|
68
|
+
|
69
|
+
is_international = shipper.country_code != recipient.country_code
|
70
|
+
service_type = provider_units.Service.map(payload.service).value_or_key or (
|
71
|
+
provider_units.Service.dhl_poland_polska.value
|
72
|
+
if is_international
|
73
|
+
else provider_units.Service.dhl_poland_09.value
|
74
|
+
)
|
75
|
+
label_type = provider_units.LabelType.map(payload.label_type or "PDF").value
|
76
|
+
payment = payload.payment or models.Payment()
|
77
|
+
quantity = len(customs.commodities or []) if customs.is_defined else 1
|
78
|
+
|
79
|
+
request = lib.create_envelope(
|
80
|
+
body_content=dhl.createShipment(
|
81
|
+
authData=settings.auth_data,
|
82
|
+
shipment=dhl.CreateShipmentRequest(
|
83
|
+
shipmentInfo=dhl.ShipmentInfo(
|
84
|
+
wayBill=None,
|
85
|
+
dropOffType="REGULAR_PICKUP",
|
86
|
+
serviceType=service_type,
|
87
|
+
billing=dhl.Billing(
|
88
|
+
shippingPaymentType=provider_units.PaymentType[
|
89
|
+
payment.paid_by
|
90
|
+
].value,
|
91
|
+
billingAccountNumber=(
|
92
|
+
payment.account_number or settings.account_number
|
93
|
+
),
|
94
|
+
paymentType="BANK_TRANSFER",
|
95
|
+
costsCenter=None,
|
96
|
+
),
|
97
|
+
specialServices=(
|
98
|
+
dhl.ArrayOfService(
|
99
|
+
item=[
|
100
|
+
dhl.Service(
|
101
|
+
serviceType=option.code,
|
102
|
+
serviceValue=lib.to_money(option.state),
|
103
|
+
textInstruction=None,
|
104
|
+
collectOnDeliveryForm=None,
|
105
|
+
)
|
106
|
+
for _, option in options.items()
|
107
|
+
]
|
108
|
+
)
|
109
|
+
if any(options.items())
|
110
|
+
else None
|
111
|
+
),
|
112
|
+
shipmentTime=(
|
113
|
+
dhl.ShipmentTime(
|
114
|
+
shipmentDate=(
|
115
|
+
options.shipment_date.state or time.strftime("%Y-%m-%d")
|
116
|
+
),
|
117
|
+
shipmentStartHour="10:00",
|
118
|
+
shipmentEndHour="10:00",
|
119
|
+
)
|
120
|
+
),
|
121
|
+
labelType=label_type,
|
122
|
+
),
|
123
|
+
content=payload.parcels[0].content or "N/A",
|
124
|
+
comment=None,
|
125
|
+
reference=payload.reference,
|
126
|
+
ship=dhl.Ship(
|
127
|
+
shipper=dhl.Addressat(
|
128
|
+
preaviso=(
|
129
|
+
dhl.PreavisoContact(
|
130
|
+
personName=shipper.person_name,
|
131
|
+
phoneNumber=shipper.phone_number,
|
132
|
+
emailAddress=shipper.email,
|
133
|
+
)
|
134
|
+
if any(
|
135
|
+
[
|
136
|
+
shipper.person_name,
|
137
|
+
shipper.phone_number,
|
138
|
+
shipper.email,
|
139
|
+
]
|
140
|
+
)
|
141
|
+
else None
|
142
|
+
),
|
143
|
+
contact=(
|
144
|
+
dhl.PreavisoContact(
|
145
|
+
personName=shipper.person_name,
|
146
|
+
phoneNumber=shipper.phone_number,
|
147
|
+
emailAddress=shipper.email,
|
148
|
+
)
|
149
|
+
if any(
|
150
|
+
[
|
151
|
+
shipper.person_name,
|
152
|
+
shipper.phone_number,
|
153
|
+
shipper.email,
|
154
|
+
]
|
155
|
+
)
|
156
|
+
else None
|
157
|
+
),
|
158
|
+
address=dhl.Address(
|
159
|
+
name=(shipper.company_name or shipper.person_name),
|
160
|
+
postalCode=(shipper.postal_code or "").replace("-", ""),
|
161
|
+
city=shipper.city,
|
162
|
+
street=shipper.address_line1,
|
163
|
+
houseNumber=(shipper.street_number or "N/A"),
|
164
|
+
apartmentNumber=shipper.address_line2,
|
165
|
+
),
|
166
|
+
),
|
167
|
+
receiver=dhl.ReceiverAddressat(
|
168
|
+
preaviso=(
|
169
|
+
dhl.PreavisoContact(
|
170
|
+
personName=recipient.person_name,
|
171
|
+
phoneNumber=recipient.phone_number,
|
172
|
+
emailAddress=recipient.email,
|
173
|
+
)
|
174
|
+
if any(
|
175
|
+
[
|
176
|
+
recipient.person_name,
|
177
|
+
recipient.phone_number,
|
178
|
+
recipient.email,
|
179
|
+
]
|
180
|
+
)
|
181
|
+
else None
|
182
|
+
),
|
183
|
+
contact=(
|
184
|
+
dhl.PreavisoContact(
|
185
|
+
personName=recipient.person_name,
|
186
|
+
phoneNumber=recipient.phone_number,
|
187
|
+
emailAddress=recipient.email,
|
188
|
+
)
|
189
|
+
if any(
|
190
|
+
[
|
191
|
+
recipient.person_name,
|
192
|
+
recipient.phone_number,
|
193
|
+
recipient.email,
|
194
|
+
]
|
195
|
+
)
|
196
|
+
else None
|
197
|
+
),
|
198
|
+
address=dhl.ReceiverAddress(
|
199
|
+
country=recipient.country_code,
|
200
|
+
isPackstation=None,
|
201
|
+
isPostfiliale=None,
|
202
|
+
postnummer=None,
|
203
|
+
addressType=("C" if recipient.residential else "B"),
|
204
|
+
name=(recipient.company_name or recipient.person_name),
|
205
|
+
postalCode=(recipient.postal_code or "").replace("-", ""),
|
206
|
+
city=recipient.city,
|
207
|
+
street=recipient.address_line1,
|
208
|
+
houseNumber=(shipper.street_number or "N/A"),
|
209
|
+
apartmentNumber=recipient.address_line2,
|
210
|
+
),
|
211
|
+
),
|
212
|
+
neighbour=None,
|
213
|
+
),
|
214
|
+
pieceList=dhl.ArrayOfPackage(
|
215
|
+
item=[
|
216
|
+
dhl.Package(
|
217
|
+
type_=provider_units.PackagingType[
|
218
|
+
package.packaging_type or "your_packaging"
|
219
|
+
].value,
|
220
|
+
euroReturn=None,
|
221
|
+
weight=package.weight.KG,
|
222
|
+
width=package.width.CM,
|
223
|
+
height=package.height.CM,
|
224
|
+
length=package.length.CM,
|
225
|
+
quantity=quantity,
|
226
|
+
nonStandard=None,
|
227
|
+
blpPieceId=None,
|
228
|
+
)
|
229
|
+
for package in packages
|
230
|
+
]
|
231
|
+
),
|
232
|
+
customs=(
|
233
|
+
dhl.CustomsData(
|
234
|
+
customsType="S",
|
235
|
+
firstName=getattr(
|
236
|
+
getattr(customs.duty, "bil_to", shipper.company_name),
|
237
|
+
"company_name",
|
238
|
+
"N/A",
|
239
|
+
),
|
240
|
+
secondaryName=getattr(
|
241
|
+
getattr(customs.duty, "bil_to", shipper.person_name),
|
242
|
+
"person_name",
|
243
|
+
"N/A",
|
244
|
+
),
|
245
|
+
costsOfShipment=(
|
246
|
+
getattr(customs.duty, "declared_value", None)
|
247
|
+
or options.declard_value.state
|
248
|
+
),
|
249
|
+
currency=(
|
250
|
+
getattr(customs.duty, "currency", None)
|
251
|
+
or options.currency.state
|
252
|
+
),
|
253
|
+
nipNr=customs.options.nip_number.state,
|
254
|
+
eoriNr=customs.options.eori_number.state,
|
255
|
+
vatRegistrationNumber=customs.options.vat_registration_number.state,
|
256
|
+
categoryOfItem=provider_units.CustomsContentType[
|
257
|
+
customs.content_type or "other"
|
258
|
+
].value,
|
259
|
+
invoiceNr=customs.invoice,
|
260
|
+
invoice=None,
|
261
|
+
invoiceDate=customs.invoice_date,
|
262
|
+
countryOfOrigin=shipper.country_code,
|
263
|
+
additionalInfo=None,
|
264
|
+
grossWeight=packages.weight.KG,
|
265
|
+
customsItem=(
|
266
|
+
dhl.ArrayOfCustomsitemdata(
|
267
|
+
item=[
|
268
|
+
dhl.CustomsItemData(
|
269
|
+
nameEn=lib.text(
|
270
|
+
item.title or item.description or "N/A",
|
271
|
+
max=35,
|
272
|
+
),
|
273
|
+
namePl=lib.text(
|
274
|
+
item.title or item.description or "N/A",
|
275
|
+
max=35,
|
276
|
+
),
|
277
|
+
quantity=item.quantity,
|
278
|
+
weight=units.Weight(
|
279
|
+
item.weight,
|
280
|
+
units.WeightUnit[item.weight_unit or "KG"],
|
281
|
+
).KG,
|
282
|
+
value=item.value_amount,
|
283
|
+
tariffCode=item.hs_code or item.sku,
|
284
|
+
)
|
285
|
+
for item in customs.commodities
|
286
|
+
]
|
287
|
+
)
|
288
|
+
if any(customs.commodities)
|
289
|
+
else None
|
290
|
+
),
|
291
|
+
customAgreements=dhl.CustomsAgreementData(
|
292
|
+
notExceedValue=True,
|
293
|
+
notProhibitedGoods=True,
|
294
|
+
notRestrictedGoods=True,
|
295
|
+
),
|
296
|
+
)
|
297
|
+
if customs.is_defined
|
298
|
+
else None
|
299
|
+
),
|
300
|
+
),
|
301
|
+
)
|
302
|
+
)
|
303
|
+
|
304
|
+
return lib.Serializable(
|
305
|
+
request,
|
306
|
+
lambda req: settings.serialize(req, "createShipment", settings.server_url),
|
307
|
+
)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
import karrio.schemas.dhl_poland.services as dhl
|
2
|
+
import typing
|
3
|
+
import karrio.lib as lib
|
4
|
+
import karrio.core.models as models
|
5
|
+
import karrio.providers.dhl_poland.error as provider_error
|
6
|
+
import karrio.providers.dhl_poland.utils as provider_utils
|
7
|
+
|
8
|
+
|
9
|
+
def parse_tracking_response(
|
10
|
+
_response: lib.Deserializable[typing.Dict[str, lib.Element]],
|
11
|
+
settings: provider_utils.Settings,
|
12
|
+
) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
|
13
|
+
response = _response.deserialize()
|
14
|
+
details = [
|
15
|
+
_extract_tracking_details(node, settings)
|
16
|
+
for node in response.values()
|
17
|
+
if lib.find_element("getTrackAndTraceInfoResult", node, first=True) is not None
|
18
|
+
]
|
19
|
+
errors: typing.List[models.Message] = sum(
|
20
|
+
[
|
21
|
+
provider_error.parse_error_response(
|
22
|
+
node, settings, dict(tracking_number=number)
|
23
|
+
)
|
24
|
+
for number, node in response.items()
|
25
|
+
if lib.find_element("Fault", node, first=True) is not None
|
26
|
+
],
|
27
|
+
[],
|
28
|
+
)
|
29
|
+
|
30
|
+
return details, errors
|
31
|
+
|
32
|
+
|
33
|
+
def _extract_tracking_details(
|
34
|
+
node: lib.Element,
|
35
|
+
settings: provider_utils.Settings,
|
36
|
+
) -> models.TrackingDetails:
|
37
|
+
track: dhl.TrackAndTraceResponse = lib.find_element(
|
38
|
+
"getTrackAndTraceInfoResult", node, dhl.TrackAndTraceResponse, first=True
|
39
|
+
)
|
40
|
+
events = [
|
41
|
+
lib.to_object(dhl.TrackAndTraceEvent, item)
|
42
|
+
for item in lib.find_element("item", node)
|
43
|
+
]
|
44
|
+
|
45
|
+
return models.TrackingDetails(
|
46
|
+
carrier_name=settings.carrier_name,
|
47
|
+
carrier_id=settings.carrier_id,
|
48
|
+
tracking_number=track.shipmentId,
|
49
|
+
events=[
|
50
|
+
models.TrackingEvent(
|
51
|
+
date=lib.fdate(event.timestamp, "%Y-%m-%d %H:%M:%S"),
|
52
|
+
description=event.description,
|
53
|
+
location=event.terminal,
|
54
|
+
code=event.status,
|
55
|
+
time=lib.flocaltime(event.timestamp, "%Y-%m-%d %H:%M:%S"),
|
56
|
+
)
|
57
|
+
for event in events
|
58
|
+
],
|
59
|
+
delivered=any(track.receivedBy or ""),
|
60
|
+
info=models.TrackingInfo(
|
61
|
+
carrier_tracking_link=settings.tracking_url.format(track.shipmentId),
|
62
|
+
),
|
63
|
+
)
|
64
|
+
|
65
|
+
|
66
|
+
def tracking_request(
|
67
|
+
payload: models.TrackingRequest,
|
68
|
+
settings: provider_utils.Settings,
|
69
|
+
) -> lib.Serializable:
|
70
|
+
requests = {
|
71
|
+
tracking_number: lib.create_envelope(
|
72
|
+
body_prefix="",
|
73
|
+
body_content=dhl.getTrackAndTraceInfo(
|
74
|
+
authData=settings.auth_data,
|
75
|
+
shipmentId=tracking_number,
|
76
|
+
),
|
77
|
+
)
|
78
|
+
for tracking_number in payload.tracking_numbers
|
79
|
+
}
|
80
|
+
|
81
|
+
return lib.Serializable(
|
82
|
+
requests,
|
83
|
+
lambda requests: {
|
84
|
+
number: settings.serialize(
|
85
|
+
request,
|
86
|
+
"getTrackAndTraceInfo",
|
87
|
+
settings.server_url,
|
88
|
+
)
|
89
|
+
for number, request in requests.items()
|
90
|
+
},
|
91
|
+
)
|