karrio-teleship 2025.5__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/teleship/__init__.py +4 -0
- karrio/mappers/teleship/hooks.py +27 -0
- karrio/mappers/teleship/mapper.py +114 -0
- karrio/mappers/teleship/proxy.py +239 -0
- karrio/mappers/teleship/settings.py +21 -0
- karrio/plugins/teleship/__init__.py +32 -0
- karrio/providers/teleship/__init__.py +41 -0
- karrio/providers/teleship/duties.py +115 -0
- karrio/providers/teleship/error.py +44 -0
- karrio/providers/teleship/hooks/__init__.py +5 -0
- karrio/providers/teleship/hooks/event.py +163 -0
- karrio/providers/teleship/hooks/oauth.py +103 -0
- karrio/providers/teleship/manifest.py +68 -0
- karrio/providers/teleship/pickup/__init__.py +8 -0
- karrio/providers/teleship/pickup/cancel.py +43 -0
- karrio/providers/teleship/pickup/schedule.py +66 -0
- karrio/providers/teleship/rate.py +287 -0
- karrio/providers/teleship/shipment/__init__.py +9 -0
- karrio/providers/teleship/shipment/cancel.py +48 -0
- karrio/providers/teleship/shipment/create.py +322 -0
- karrio/providers/teleship/tracking.py +100 -0
- karrio/providers/teleship/units.py +154 -0
- karrio/providers/teleship/utils.py +57 -0
- karrio/providers/teleship/webhook/__init__.py +8 -0
- karrio/providers/teleship/webhook/deregister.py +47 -0
- karrio/providers/teleship/webhook/register.py +48 -0
- karrio/schemas/teleship/__init__.py +0 -0
- karrio/schemas/teleship/duties_taxes_request.py +82 -0
- karrio/schemas/teleship/duties_taxes_response.py +28 -0
- karrio/schemas/teleship/error_response.py +17 -0
- karrio/schemas/teleship/manifest_request.py +39 -0
- karrio/schemas/teleship/manifest_response.py +31 -0
- karrio/schemas/teleship/pickup_request.py +31 -0
- karrio/schemas/teleship/pickup_response.py +48 -0
- karrio/schemas/teleship/rate_request.py +128 -0
- karrio/schemas/teleship/rate_response.py +66 -0
- karrio/schemas/teleship/shipment_cancel_request.py +8 -0
- karrio/schemas/teleship/shipment_cancel_response.py +17 -0
- karrio/schemas/teleship/shipment_request.py +137 -0
- karrio/schemas/teleship/shipment_response.py +247 -0
- karrio/schemas/teleship/tracking_request.py +8 -0
- karrio/schemas/teleship/tracking_response.py +52 -0
- karrio/schemas/teleship/webhook_request.py +18 -0
- karrio/schemas/teleship/webhook_response.py +20 -0
- karrio_teleship-2025.5.dist-info/METADATA +44 -0
- karrio_teleship-2025.5.dist-info/RECORD +49 -0
- karrio_teleship-2025.5.dist-info/WHEEL +5 -0
- karrio_teleship-2025.5.dist-info/entry_points.txt +2 -0
- karrio_teleship-2025.5.dist-info/top_level.txt +4 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""Karrio Teleship rate API implementation."""
|
|
2
|
+
|
|
3
|
+
import karrio.schemas.teleship.rate_request as teleship_req
|
|
4
|
+
import karrio.schemas.teleship.rate_response as teleship_res
|
|
5
|
+
|
|
6
|
+
import typing
|
|
7
|
+
import karrio.lib as lib
|
|
8
|
+
import karrio.core.units as units
|
|
9
|
+
import karrio.core.models as models
|
|
10
|
+
import karrio.providers.teleship.error as error
|
|
11
|
+
import karrio.providers.teleship.utils as provider_utils
|
|
12
|
+
import karrio.providers.teleship.units as provider_units
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_rate_response(
|
|
16
|
+
_response: lib.Deserializable[typing.List[dict]],
|
|
17
|
+
settings: provider_utils.Settings,
|
|
18
|
+
) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
|
|
19
|
+
responses = _response.deserialize()
|
|
20
|
+
|
|
21
|
+
messages: typing.List[models.Message] = sum(
|
|
22
|
+
[error.parse_error_response(response, settings) for response in responses],
|
|
23
|
+
start=[],
|
|
24
|
+
)
|
|
25
|
+
package_rates: typing.List[typing.Tuple[str, typing.List[models.RateDetails]]] = [
|
|
26
|
+
(
|
|
27
|
+
f"{_}",
|
|
28
|
+
[_extract_details(rate, settings) for rate in response.get("rates") or []],
|
|
29
|
+
)
|
|
30
|
+
for _, response in enumerate(responses, start=1)
|
|
31
|
+
]
|
|
32
|
+
rates = lib.to_multi_piece_rates(package_rates)
|
|
33
|
+
|
|
34
|
+
return rates, messages
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _extract_details(
|
|
38
|
+
data: dict,
|
|
39
|
+
settings: provider_utils.Settings,
|
|
40
|
+
) -> models.RateDetails:
|
|
41
|
+
"""Extract rate details from carrier response data"""
|
|
42
|
+
rate = lib.to_object(teleship_res.RateType, data)
|
|
43
|
+
service = provider_units.ShippingService.map(
|
|
44
|
+
rate.service.code if rate.service else ""
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
return models.RateDetails(
|
|
48
|
+
carrier_id=settings.carrier_id,
|
|
49
|
+
carrier_name=settings.carrier_name,
|
|
50
|
+
service=service.name_or_key,
|
|
51
|
+
total_charge=lib.to_money(rate.price),
|
|
52
|
+
currency=rate.currency,
|
|
53
|
+
transit_days=rate.transit,
|
|
54
|
+
extra_charges=[
|
|
55
|
+
models.ChargeDetails(
|
|
56
|
+
name=charge.name or "",
|
|
57
|
+
amount=lib.to_money(charge.amount),
|
|
58
|
+
currency=charge.currency,
|
|
59
|
+
)
|
|
60
|
+
for charge in (rate.charges or [])
|
|
61
|
+
],
|
|
62
|
+
meta=dict(
|
|
63
|
+
service_name=service.name_or_key,
|
|
64
|
+
estimated_delivery=lib.fdate(
|
|
65
|
+
rate.estimatedDelivery,
|
|
66
|
+
try_formats=["%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%SZ"],
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def rate_request(
|
|
73
|
+
payload: models.RateRequest,
|
|
74
|
+
settings: provider_utils.Settings,
|
|
75
|
+
) -> lib.Serializable:
|
|
76
|
+
"""Create a rate request for the carrier API"""
|
|
77
|
+
# Convert karrio models using functional lib utilities
|
|
78
|
+
shipper = lib.to_address(payload.shipper)
|
|
79
|
+
recipient = lib.to_address(payload.recipient)
|
|
80
|
+
billing_address = lib.to_address(payload.billing_address)
|
|
81
|
+
return_address = lib.to_address(payload.return_address)
|
|
82
|
+
is_intl = payload.recipient.country_code != payload.shipper.country_code
|
|
83
|
+
|
|
84
|
+
options = lib.to_shipping_options(
|
|
85
|
+
payload.options,
|
|
86
|
+
initializer=provider_units.shipping_options_initializer,
|
|
87
|
+
)
|
|
88
|
+
packages = lib.to_packages(
|
|
89
|
+
payload.parcels,
|
|
90
|
+
options=options,
|
|
91
|
+
shipping_options_initializer=provider_units.shipping_options_initializer,
|
|
92
|
+
)
|
|
93
|
+
customs = lib.to_customs_info(
|
|
94
|
+
payload.customs,
|
|
95
|
+
shipper=payload.shipper,
|
|
96
|
+
recipient=payload.recipient,
|
|
97
|
+
weight_unit=units.WeightUnit.KG.name,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Build request using typed schema classes
|
|
101
|
+
request = [
|
|
102
|
+
teleship_req.RateRequestType(
|
|
103
|
+
customerReference=payload.reference,
|
|
104
|
+
description=package.parcel.description,
|
|
105
|
+
shipDate=options.shipping_date.state,
|
|
106
|
+
orderTrackingReference=options.teleship_order_tracking_reference.state,
|
|
107
|
+
commercialInvoiceReference=customs.invoice,
|
|
108
|
+
packageType=provider_units.PackagingType.map(
|
|
109
|
+
package.packaging_type or "your_packaging"
|
|
110
|
+
).value_or_key,
|
|
111
|
+
shipTo=teleship_req.BillToType(
|
|
112
|
+
name=recipient.contact or "N/A",
|
|
113
|
+
company=recipient.company_name,
|
|
114
|
+
email=recipient.email,
|
|
115
|
+
phone=recipient.phone_number,
|
|
116
|
+
address=teleship_req.AddressType(
|
|
117
|
+
line1=recipient.address_line1,
|
|
118
|
+
line2=recipient.address_line2,
|
|
119
|
+
city=recipient.city,
|
|
120
|
+
state=recipient.state_code,
|
|
121
|
+
postcode=recipient.postal_code,
|
|
122
|
+
country=recipient.country_code,
|
|
123
|
+
),
|
|
124
|
+
),
|
|
125
|
+
shipFrom=teleship_req.BillToType(
|
|
126
|
+
name=shipper.contact or "N/A",
|
|
127
|
+
company=shipper.company_name,
|
|
128
|
+
email=shipper.email,
|
|
129
|
+
phone=shipper.phone_number,
|
|
130
|
+
address=teleship_req.AddressType(
|
|
131
|
+
line1=shipper.address_line1,
|
|
132
|
+
line2=shipper.address_line2,
|
|
133
|
+
city=shipper.city,
|
|
134
|
+
state=shipper.state_code,
|
|
135
|
+
postcode=shipper.postal_code,
|
|
136
|
+
country=shipper.country_code,
|
|
137
|
+
),
|
|
138
|
+
),
|
|
139
|
+
returnTo=lib.identity(
|
|
140
|
+
teleship_req.BillToType(
|
|
141
|
+
name=return_address.contact or "N/A",
|
|
142
|
+
company=return_address.company_name,
|
|
143
|
+
email=return_address.email,
|
|
144
|
+
phone=return_address.phone_number,
|
|
145
|
+
address=teleship_req.AddressType(
|
|
146
|
+
line1=return_address.address_line1,
|
|
147
|
+
line2=return_address.address_line2,
|
|
148
|
+
city=return_address.city,
|
|
149
|
+
state=return_address.state_code,
|
|
150
|
+
postcode=return_address.postal_code,
|
|
151
|
+
country=return_address.country_code,
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
if payload.return_address
|
|
155
|
+
else None
|
|
156
|
+
),
|
|
157
|
+
billTo=lib.identity(
|
|
158
|
+
teleship_req.BillToType(
|
|
159
|
+
name=billing_address.contact or "N/A",
|
|
160
|
+
company=billing_address.company_name,
|
|
161
|
+
email=billing_address.email,
|
|
162
|
+
phone=billing_address.phone_number,
|
|
163
|
+
address=teleship_req.AddressType(
|
|
164
|
+
line1=billing_address.address_line1,
|
|
165
|
+
line2=billing_address.address_line2,
|
|
166
|
+
city=billing_address.city,
|
|
167
|
+
state=billing_address.state_code,
|
|
168
|
+
postcode=billing_address.postal_code,
|
|
169
|
+
country=billing_address.country_code,
|
|
170
|
+
),
|
|
171
|
+
stateTaxId=billing_address.state_tax_id,
|
|
172
|
+
countryTaxId=billing_address.federal_tax_id,
|
|
173
|
+
)
|
|
174
|
+
if payload.billing_address
|
|
175
|
+
else None
|
|
176
|
+
),
|
|
177
|
+
weight=teleship_req.WeightType(
|
|
178
|
+
value=package.weight.value,
|
|
179
|
+
unit=package.weight.unit.lower(),
|
|
180
|
+
),
|
|
181
|
+
dimensions=lib.identity(
|
|
182
|
+
teleship_req.DimensionsType(
|
|
183
|
+
unit=package.dimension_unit.lower(),
|
|
184
|
+
length=package.length.value,
|
|
185
|
+
width=package.width.value,
|
|
186
|
+
height=package.height.value,
|
|
187
|
+
)
|
|
188
|
+
if all(
|
|
189
|
+
[
|
|
190
|
+
package.length.value,
|
|
191
|
+
package.width.value,
|
|
192
|
+
package.height.value,
|
|
193
|
+
]
|
|
194
|
+
)
|
|
195
|
+
else None
|
|
196
|
+
),
|
|
197
|
+
additionalServices=lib.identity(
|
|
198
|
+
teleship_req.AdditionalServicesType(
|
|
199
|
+
signatureRequired=options.teleship_signature_required.state,
|
|
200
|
+
deliveryWarranty=options.teleship_delivery_warranty.state,
|
|
201
|
+
deliveryPUDO=options.teleship_delivery_pudo.state,
|
|
202
|
+
lowCarbon=options.teleship_low_carbon.state,
|
|
203
|
+
dutyTaxCalculation=options.teleship_duty_tax_calculation.state,
|
|
204
|
+
)
|
|
205
|
+
if any(
|
|
206
|
+
[
|
|
207
|
+
options.teleship_signature_required.state,
|
|
208
|
+
options.teleship_delivery_warranty.state,
|
|
209
|
+
options.teleship_delivery_pudo.state,
|
|
210
|
+
options.teleship_low_carbon.state,
|
|
211
|
+
options.teleship_duty_tax_calculation.state,
|
|
212
|
+
]
|
|
213
|
+
)
|
|
214
|
+
else None
|
|
215
|
+
),
|
|
216
|
+
commodities=[
|
|
217
|
+
teleship_req.CommodityType(
|
|
218
|
+
sku=commodity.sku,
|
|
219
|
+
hsCode=commodity.hs_code,
|
|
220
|
+
title=lib.text(commodity.title or commodity.description, max=200),
|
|
221
|
+
description=lib.text(
|
|
222
|
+
commodity.description if commodity.title else None, max=200
|
|
223
|
+
),
|
|
224
|
+
category=commodity.category,
|
|
225
|
+
value=teleship_req.ValueType(
|
|
226
|
+
amount=commodity.value_amount,
|
|
227
|
+
currency=commodity.value_currency,
|
|
228
|
+
),
|
|
229
|
+
quantity=commodity.quantity,
|
|
230
|
+
unitWeight=teleship_req.WeightType(
|
|
231
|
+
value=commodity.weight,
|
|
232
|
+
unit=commodity.weight_unit.lower(),
|
|
233
|
+
),
|
|
234
|
+
countryOfOrigin=commodity.origin_country,
|
|
235
|
+
imageUrl=commodity.image_url,
|
|
236
|
+
productUrl=commodity.product_url,
|
|
237
|
+
compliance=None,
|
|
238
|
+
)
|
|
239
|
+
for commodity in (
|
|
240
|
+
package.items if any(package.items) else customs.commodities or []
|
|
241
|
+
)
|
|
242
|
+
],
|
|
243
|
+
customs=lib.identity(
|
|
244
|
+
teleship_req.CustomsType(
|
|
245
|
+
EORI=customs.options.eori_number.state,
|
|
246
|
+
IOSS=customs.options.ioss.state,
|
|
247
|
+
VAT=customs.options.vat.state,
|
|
248
|
+
EIN=customs.options.ein.state,
|
|
249
|
+
VOECNUMBER=customs.options.voec_number.state,
|
|
250
|
+
importerGST=customs.options.importer_gst.state,
|
|
251
|
+
exporterGST=customs.options.exporter_gst.state,
|
|
252
|
+
consigneeGST=customs.options.consignee_gst.state,
|
|
253
|
+
contentType=provider_units.CustomsContentType.map(
|
|
254
|
+
customs.content_type or "other"
|
|
255
|
+
).value,
|
|
256
|
+
invoiceDate=customs.invoice_date,
|
|
257
|
+
invoiceNumber=customs.invoice,
|
|
258
|
+
GPSRContactInfo=options.teleship_gpsr_contact_info.state,
|
|
259
|
+
importerOfRecord=lib.identity(
|
|
260
|
+
teleship_req.BillToType(
|
|
261
|
+
name=customs.duty_billing_address.contact or "N/A",
|
|
262
|
+
company=customs.duty_billing_address.company_name,
|
|
263
|
+
email=customs.duty_billing_address.email,
|
|
264
|
+
phone=customs.duty_billing_address.phone_number,
|
|
265
|
+
address=teleship_req.AddressType(
|
|
266
|
+
line1=customs.duty_billing_address.address_line1,
|
|
267
|
+
line2=customs.duty_billing_address.address_line2,
|
|
268
|
+
city=customs.duty_billing_address.city,
|
|
269
|
+
state=customs.duty_billing_address.state_code,
|
|
270
|
+
country=customs.duty_billing_address.country_code,
|
|
271
|
+
postcode=customs.duty_billing_address.postal_code,
|
|
272
|
+
),
|
|
273
|
+
stateTaxId=customs.duty_billing_address.state_tax_id,
|
|
274
|
+
countryTaxId=customs.duty_billing_address.federal_tax_id,
|
|
275
|
+
)
|
|
276
|
+
if payload.customs.duty_billing_address
|
|
277
|
+
else None
|
|
278
|
+
),
|
|
279
|
+
)
|
|
280
|
+
if payload.customs and is_intl
|
|
281
|
+
else None
|
|
282
|
+
),
|
|
283
|
+
)
|
|
284
|
+
for package in packages
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
return lib.Serializable(request, lib.to_dict)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Karrio Teleship shipment cancellation API implementation."""
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
import karrio.schemas.teleship.shipment_cancel_request as teleship_req
|
|
5
|
+
import karrio.schemas.teleship.shipment_cancel_response as teleship_res
|
|
6
|
+
import karrio.lib as lib
|
|
7
|
+
import karrio.core.models as models
|
|
8
|
+
import karrio.providers.teleship.error as error
|
|
9
|
+
import karrio.providers.teleship.utils as provider_utils
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parse_shipment_cancel_response(
|
|
13
|
+
_response: lib.Deserializable[dict],
|
|
14
|
+
settings: provider_utils.Settings,
|
|
15
|
+
) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
|
|
16
|
+
"""Parse shipment cancellation response from carrier API"""
|
|
17
|
+
response = _response.deserialize()
|
|
18
|
+
messages = error.parse_error_response(response, settings)
|
|
19
|
+
details = lib.to_object(teleship_res.ShipmentCancelResponseType, response)
|
|
20
|
+
|
|
21
|
+
# Check if cancellation was successful based on status
|
|
22
|
+
success = details.status in ["cancelled", "voided"] if details else False
|
|
23
|
+
|
|
24
|
+
confirmation = lib.identity(
|
|
25
|
+
models.ConfirmationDetails(
|
|
26
|
+
carrier_id=settings.carrier_id,
|
|
27
|
+
carrier_name=settings.carrier_name,
|
|
28
|
+
operation="Cancel Shipment",
|
|
29
|
+
success=success,
|
|
30
|
+
)
|
|
31
|
+
if details
|
|
32
|
+
else None
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
return confirmation, messages
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def shipment_cancel_request(
|
|
39
|
+
payload: models.ShipmentCancelRequest,
|
|
40
|
+
settings: provider_utils.Settings,
|
|
41
|
+
) -> lib.Serializable:
|
|
42
|
+
"""Create a shipment cancellation request for the carrier API"""
|
|
43
|
+
|
|
44
|
+
request = teleship_req.ShipmentCancelRequestType(
|
|
45
|
+
shipmentId=payload.shipment_identifier,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return lib.Serializable(request, lib.to_dict)
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"""Karrio Teleship shipment API implementation."""
|
|
2
|
+
|
|
3
|
+
import karrio.schemas.teleship.shipment_request as teleship_req
|
|
4
|
+
import karrio.schemas.teleship.shipment_response as teleship_res
|
|
5
|
+
|
|
6
|
+
import typing
|
|
7
|
+
import karrio.lib as lib
|
|
8
|
+
import karrio.core.units as units
|
|
9
|
+
import karrio.core.models as models
|
|
10
|
+
import karrio.providers.teleship.error as error
|
|
11
|
+
import karrio.providers.teleship.utils as provider_utils
|
|
12
|
+
import karrio.providers.teleship.units as provider_units
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_shipment_response(
|
|
16
|
+
_responses: lib.Deserializable[typing.List[dict]],
|
|
17
|
+
settings: provider_utils.Settings,
|
|
18
|
+
) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
|
|
19
|
+
responses = _responses.deserialize()
|
|
20
|
+
|
|
21
|
+
shipment = lib.to_multi_piece_shipment(
|
|
22
|
+
[
|
|
23
|
+
(
|
|
24
|
+
f"{_}",
|
|
25
|
+
(
|
|
26
|
+
_extract_details(response.get("shipment"), settings)
|
|
27
|
+
if response.get("shipment")
|
|
28
|
+
else None
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
for _, response in enumerate(responses, start=1)
|
|
32
|
+
]
|
|
33
|
+
)
|
|
34
|
+
messages: typing.List[models.Message] = sum(
|
|
35
|
+
[error.parse_error_response(response, settings) for response in responses],
|
|
36
|
+
start=[],
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
return shipment, messages
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _extract_details(
|
|
43
|
+
data: dict,
|
|
44
|
+
settings: provider_utils.Settings,
|
|
45
|
+
) -> models.ShipmentDetails:
|
|
46
|
+
"""Extract shipment details from carrier response data"""
|
|
47
|
+
shipment = lib.to_object(teleship_res.ShipmentType, data)
|
|
48
|
+
service = provider_units.ShippingService.map(shipment.rate.service.code)
|
|
49
|
+
|
|
50
|
+
# Extract label document from documents array
|
|
51
|
+
label = lib.identity(
|
|
52
|
+
next(
|
|
53
|
+
(doc for doc in (shipment.documents or []) if doc.type == "LABEL"),
|
|
54
|
+
None,
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
invoice = lib.identity(
|
|
58
|
+
next(
|
|
59
|
+
(doc for doc in (shipment.documents or []) if doc.type == "INVOICE"),
|
|
60
|
+
None,
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return models.ShipmentDetails(
|
|
65
|
+
carrier_id=settings.carrier_id,
|
|
66
|
+
carrier_name=settings.carrier_name,
|
|
67
|
+
tracking_number=shipment.trackingNumber,
|
|
68
|
+
shipment_identifier=shipment.shipmentId,
|
|
69
|
+
label_type=label.format or "PDF",
|
|
70
|
+
docs=models.Documents(
|
|
71
|
+
label=getattr(label, "base64String", None),
|
|
72
|
+
invoice=getattr(invoice, "base64String", None),
|
|
73
|
+
),
|
|
74
|
+
selected_rate=models.RateDetails(
|
|
75
|
+
carrier_id=settings.carrier_id,
|
|
76
|
+
carrier_name=settings.carrier_name,
|
|
77
|
+
service=service.name_or_key,
|
|
78
|
+
total_charge=lib.to_money(shipment.rate.price),
|
|
79
|
+
currency=shipment.rate.currency,
|
|
80
|
+
transit_days=shipment.rate.transit,
|
|
81
|
+
estimated_delivery=lib.fdate(
|
|
82
|
+
shipment.rate.estimatedDelivery,
|
|
83
|
+
try_formats=["%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%SZ"],
|
|
84
|
+
),
|
|
85
|
+
extra_charges=[
|
|
86
|
+
models.ChargeDetails(
|
|
87
|
+
name=charge.name,
|
|
88
|
+
amount=lib.to_money(charge.amount),
|
|
89
|
+
currency=charge.currency,
|
|
90
|
+
)
|
|
91
|
+
for charge in shipment.rate.charges
|
|
92
|
+
],
|
|
93
|
+
meta=dict(
|
|
94
|
+
service_name=service.name_or_key,
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
meta=dict(
|
|
98
|
+
customer_reference=shipment.customerReference,
|
|
99
|
+
service_name=service.name_or_key,
|
|
100
|
+
ship_date=shipment.shipDate,
|
|
101
|
+
),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def shipment_request(
|
|
106
|
+
payload: models.ShipmentRequest,
|
|
107
|
+
settings: provider_utils.Settings,
|
|
108
|
+
) -> lib.Serializable:
|
|
109
|
+
"""Create a shipment request for the carrier API"""
|
|
110
|
+
# Convert karrio models using functional lib utilities
|
|
111
|
+
shipper = lib.to_address(payload.shipper)
|
|
112
|
+
recipient = lib.to_address(payload.recipient)
|
|
113
|
+
billing_address = lib.to_address(payload.billing_address)
|
|
114
|
+
return_address = lib.to_address(payload.return_address)
|
|
115
|
+
is_intl = payload.recipient.country_code != payload.shipper.country_code
|
|
116
|
+
|
|
117
|
+
service = provider_units.ShippingService.map(payload.service).value_or_key
|
|
118
|
+
options = lib.to_shipping_options(
|
|
119
|
+
payload.options,
|
|
120
|
+
initializer=provider_units.shipping_options_initializer,
|
|
121
|
+
)
|
|
122
|
+
packages = lib.to_packages(
|
|
123
|
+
payload.parcels,
|
|
124
|
+
options=options,
|
|
125
|
+
shipping_options_initializer=provider_units.shipping_options_initializer,
|
|
126
|
+
)
|
|
127
|
+
customs = lib.to_customs_info(
|
|
128
|
+
payload.customs,
|
|
129
|
+
shipper=payload.shipper,
|
|
130
|
+
recipient=payload.recipient,
|
|
131
|
+
weight_unit=units.WeightUnit.KG.name,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Build request using typed schema classes
|
|
135
|
+
request = [
|
|
136
|
+
teleship_req.ShipmentRequestType(
|
|
137
|
+
serviceCode=service,
|
|
138
|
+
customerReference=payload.reference,
|
|
139
|
+
description=package.parcel.description,
|
|
140
|
+
shipDate=options.shipping_date.state,
|
|
141
|
+
orderTrackingReference=options.teleship_order_tracking_reference.state,
|
|
142
|
+
commercialInvoiceReference=customs.invoice,
|
|
143
|
+
packageType=provider_units.PackagingType.map(
|
|
144
|
+
package.packaging_type or "your_packaging"
|
|
145
|
+
).value_or_key,
|
|
146
|
+
shipTo=teleship_req.BillToType(
|
|
147
|
+
name=recipient.contact or "N/A",
|
|
148
|
+
company=recipient.company_name,
|
|
149
|
+
email=recipient.email,
|
|
150
|
+
phone=recipient.phone_number,
|
|
151
|
+
address=teleship_req.AddressType(
|
|
152
|
+
line1=recipient.address_line1,
|
|
153
|
+
line2=recipient.address_line2,
|
|
154
|
+
city=recipient.city,
|
|
155
|
+
state=recipient.state_code,
|
|
156
|
+
postcode=recipient.postal_code,
|
|
157
|
+
country=recipient.country_code,
|
|
158
|
+
),
|
|
159
|
+
),
|
|
160
|
+
shipFrom=teleship_req.BillToType(
|
|
161
|
+
name=shipper.contact or "N/A",
|
|
162
|
+
company=shipper.company_name,
|
|
163
|
+
email=shipper.email,
|
|
164
|
+
phone=shipper.phone_number,
|
|
165
|
+
address=teleship_req.AddressType(
|
|
166
|
+
line1=shipper.address_line1,
|
|
167
|
+
line2=shipper.address_line2,
|
|
168
|
+
city=shipper.city,
|
|
169
|
+
state=shipper.state_code,
|
|
170
|
+
postcode=shipper.postal_code,
|
|
171
|
+
country=shipper.country_code,
|
|
172
|
+
),
|
|
173
|
+
),
|
|
174
|
+
returnTo=lib.identity(
|
|
175
|
+
teleship_req.BillToType(
|
|
176
|
+
name=return_address.contact or "N/A",
|
|
177
|
+
company=return_address.company_name,
|
|
178
|
+
email=return_address.email,
|
|
179
|
+
phone=return_address.phone_number,
|
|
180
|
+
address=teleship_req.AddressType(
|
|
181
|
+
line1=return_address.address_line1,
|
|
182
|
+
line2=return_address.address_line2,
|
|
183
|
+
city=return_address.city,
|
|
184
|
+
state=return_address.state_code,
|
|
185
|
+
postcode=return_address.postal_code,
|
|
186
|
+
country=return_address.country_code,
|
|
187
|
+
),
|
|
188
|
+
)
|
|
189
|
+
if payload.return_address
|
|
190
|
+
else None
|
|
191
|
+
),
|
|
192
|
+
billTo=lib.identity(
|
|
193
|
+
teleship_req.BillToType(
|
|
194
|
+
name=billing_address.contact or "N/A",
|
|
195
|
+
company=billing_address.company_name,
|
|
196
|
+
email=billing_address.email,
|
|
197
|
+
phone=billing_address.phone_number,
|
|
198
|
+
address=teleship_req.AddressType(
|
|
199
|
+
line1=billing_address.address_line1,
|
|
200
|
+
line2=billing_address.address_line2,
|
|
201
|
+
city=billing_address.city,
|
|
202
|
+
state=billing_address.state_code,
|
|
203
|
+
postcode=billing_address.postal_code,
|
|
204
|
+
country=billing_address.country_code,
|
|
205
|
+
),
|
|
206
|
+
stateTaxId=billing_address.state_tax_id,
|
|
207
|
+
countryTaxId=billing_address.federal_tax_id,
|
|
208
|
+
)
|
|
209
|
+
if payload.billing_address
|
|
210
|
+
else None
|
|
211
|
+
),
|
|
212
|
+
weight=teleship_req.WeightType(
|
|
213
|
+
value=package.weight.value,
|
|
214
|
+
unit=package.weight.unit.lower(),
|
|
215
|
+
),
|
|
216
|
+
dimensions=lib.identity(
|
|
217
|
+
teleship_req.DimensionsType(
|
|
218
|
+
unit=package.dimension_unit.lower(),
|
|
219
|
+
length=package.length.value,
|
|
220
|
+
width=package.width.value,
|
|
221
|
+
height=package.height.value,
|
|
222
|
+
)
|
|
223
|
+
if all(
|
|
224
|
+
[
|
|
225
|
+
package.length.value,
|
|
226
|
+
package.width.value,
|
|
227
|
+
package.height.value,
|
|
228
|
+
]
|
|
229
|
+
)
|
|
230
|
+
else None
|
|
231
|
+
),
|
|
232
|
+
additionalServices=lib.identity(
|
|
233
|
+
teleship_req.AdditionalServicesType(
|
|
234
|
+
signatureRequired=options.teleship_signature_required.state,
|
|
235
|
+
deliveryWarranty=options.teleship_delivery_warranty.state,
|
|
236
|
+
deliveryPUDO=options.teleship_delivery_pudo.state,
|
|
237
|
+
lowCarbon=options.teleship_low_carbon.state,
|
|
238
|
+
dutyTaxCalculation=options.teleship_duty_tax_calculation.state,
|
|
239
|
+
)
|
|
240
|
+
if any(
|
|
241
|
+
[
|
|
242
|
+
options.teleship_signature_required.state,
|
|
243
|
+
options.teleship_delivery_warranty.state,
|
|
244
|
+
options.teleship_delivery_pudo.state,
|
|
245
|
+
options.teleship_low_carbon.state,
|
|
246
|
+
options.teleship_duty_tax_calculation.state,
|
|
247
|
+
]
|
|
248
|
+
)
|
|
249
|
+
else None
|
|
250
|
+
),
|
|
251
|
+
commodities=[
|
|
252
|
+
teleship_req.CommodityType(
|
|
253
|
+
sku=commodity.sku,
|
|
254
|
+
hsCode=commodity.hs_code,
|
|
255
|
+
title=lib.text(commodity.title or commodity.description, max=200),
|
|
256
|
+
description=lib.text(
|
|
257
|
+
commodity.description if commodity.title else None, max=200
|
|
258
|
+
),
|
|
259
|
+
category=commodity.category,
|
|
260
|
+
value=teleship_req.ValueType(
|
|
261
|
+
amount=commodity.value_amount,
|
|
262
|
+
currency=commodity.value_currency,
|
|
263
|
+
),
|
|
264
|
+
quantity=commodity.quantity,
|
|
265
|
+
unitWeight=teleship_req.WeightType(
|
|
266
|
+
value=commodity.weight,
|
|
267
|
+
unit=commodity.weight_unit.lower(),
|
|
268
|
+
),
|
|
269
|
+
countryOfOrigin=commodity.origin_country,
|
|
270
|
+
imageUrl=commodity.image_url,
|
|
271
|
+
productUrl=commodity.product_url,
|
|
272
|
+
compliance=None,
|
|
273
|
+
)
|
|
274
|
+
for commodity in (
|
|
275
|
+
package.items if any(package.items) else customs.commodities or []
|
|
276
|
+
)
|
|
277
|
+
],
|
|
278
|
+
customs=lib.identity(
|
|
279
|
+
teleship_req.CustomsType(
|
|
280
|
+
EORI=customs.options.eori_number.state,
|
|
281
|
+
IOSS=customs.options.ioss.state,
|
|
282
|
+
VAT=customs.options.vat.state,
|
|
283
|
+
EIN=customs.options.ein.state,
|
|
284
|
+
VOECNUMBER=customs.options.voec_number.state,
|
|
285
|
+
importerGST=customs.options.importer_gst.state,
|
|
286
|
+
exporterGST=customs.options.exporter_gst.state,
|
|
287
|
+
consigneeGST=customs.options.consignee_gst.state,
|
|
288
|
+
contentType=provider_units.CustomsContentType.map(
|
|
289
|
+
customs.content_type or "other"
|
|
290
|
+
).value,
|
|
291
|
+
invoiceDate=customs.invoice_date,
|
|
292
|
+
invoiceNumber=customs.invoice,
|
|
293
|
+
GPSRContactInfo=options.teleship_gpsr_contact_info.state,
|
|
294
|
+
importerOfRecord=lib.identity(
|
|
295
|
+
teleship_req.BillToType(
|
|
296
|
+
name=customs.duty_billing_address.contact or "N/A",
|
|
297
|
+
company=customs.duty_billing_address.company_name,
|
|
298
|
+
email=customs.duty_billing_address.email,
|
|
299
|
+
phone=customs.duty_billing_address.phone_number,
|
|
300
|
+
address=teleship_req.AddressType(
|
|
301
|
+
line1=customs.duty_billing_address.address_line1,
|
|
302
|
+
line2=customs.duty_billing_address.address_line2,
|
|
303
|
+
city=customs.duty_billing_address.city,
|
|
304
|
+
state=customs.duty_billing_address.state_code,
|
|
305
|
+
country=customs.duty_billing_address.country_code,
|
|
306
|
+
postcode=customs.duty_billing_address.postal_code,
|
|
307
|
+
),
|
|
308
|
+
stateTaxId=customs.duty_billing_address.state_tax_id,
|
|
309
|
+
countryTaxId=customs.duty_billing_address.federal_tax_id,
|
|
310
|
+
)
|
|
311
|
+
if payload.customs.duty_billing_address
|
|
312
|
+
else None
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
if payload.customs and is_intl
|
|
316
|
+
else None
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
for package in packages
|
|
320
|
+
]
|
|
321
|
+
|
|
322
|
+
return lib.Serializable(request, lib.to_dict)
|