karrio-parcelone 2026.1__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/parcelone/__init__.py +3 -0
- karrio/mappers/parcelone/mapper.py +50 -0
- karrio/mappers/parcelone/proxy.py +84 -0
- karrio/mappers/parcelone/settings.py +36 -0
- karrio/plugins/parcelone/__init__.py +28 -0
- karrio/providers/parcelone/__init__.py +17 -0
- karrio/providers/parcelone/error.py +76 -0
- karrio/providers/parcelone/rate.py +162 -0
- karrio/providers/parcelone/shipment/__init__.py +17 -0
- karrio/providers/parcelone/shipment/cancel.py +60 -0
- karrio/providers/parcelone/shipment/create.py +250 -0
- karrio/providers/parcelone/tracking.py +141 -0
- karrio/providers/parcelone/units.py +326 -0
- karrio/providers/parcelone/utils.py +63 -0
- karrio/schemas/parcelone/__init__.py +6 -0
- karrio/schemas/parcelone/error.py +27 -0
- karrio/schemas/parcelone/shipping_request.py +202 -0
- karrio/schemas/parcelone/shipping_response.py +171 -0
- karrio/schemas/parcelone/tracking_response.py +45 -0
- karrio_parcelone-2026.1.dist-info/METADATA +47 -0
- karrio_parcelone-2026.1.dist-info/RECORD +26 -0
- karrio_parcelone-2026.1.dist-info/WHEEL +5 -0
- karrio_parcelone-2026.1.dist-info/entry_points.txt +2 -0
- karrio_parcelone-2026.1.dist-info/top_level.txt +5 -0
- modules/connectors/parcelone/karrio/schemas/__init__.py +0 -0
- modules/connectors/parcelone/karrio/schemas/parcelone/__init__.py +0 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"""ParcelOne units and enums."""
|
|
2
|
+
|
|
3
|
+
import csv
|
|
4
|
+
import pathlib
|
|
5
|
+
import typing
|
|
6
|
+
import karrio.lib as lib
|
|
7
|
+
import karrio.core.units as units
|
|
8
|
+
import karrio.core.models as models
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LabelFormat(lib.StrEnum):
|
|
12
|
+
"""Supported label formats."""
|
|
13
|
+
|
|
14
|
+
PDF = "PDF"
|
|
15
|
+
ZPL = "ZPL"
|
|
16
|
+
PNG = "PNG"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LabelSize(lib.StrEnum):
|
|
20
|
+
"""Supported label sizes."""
|
|
21
|
+
|
|
22
|
+
A6 = "A6"
|
|
23
|
+
A4 = "A4"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class WeightUnit(lib.StrEnum):
|
|
27
|
+
"""Supported weight units."""
|
|
28
|
+
|
|
29
|
+
kg = "kg"
|
|
30
|
+
g = "g"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class CEP(lib.StrEnum):
|
|
34
|
+
"""Available carriers through ParcelOne (CEP = Courier, Express, Parcel)."""
|
|
35
|
+
|
|
36
|
+
PA1 = "PA1" # Parcel.One
|
|
37
|
+
DHL = "DHL"
|
|
38
|
+
UPS = "UPS"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class PackagingType(lib.StrEnum):
|
|
42
|
+
"""Carrier specific packaging type."""
|
|
43
|
+
|
|
44
|
+
PACKAGE = "PACKAGE"
|
|
45
|
+
PALLET = "PALLET"
|
|
46
|
+
|
|
47
|
+
# Unified Packaging type mapping
|
|
48
|
+
envelope = PACKAGE
|
|
49
|
+
pak = PACKAGE
|
|
50
|
+
tube = PACKAGE
|
|
51
|
+
pallet = PALLET
|
|
52
|
+
small_box = PACKAGE
|
|
53
|
+
medium_box = PACKAGE
|
|
54
|
+
your_packaging = PACKAGE
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ConnectionConfig(lib.Enum):
|
|
58
|
+
"""ParcelOne connection configuration options."""
|
|
59
|
+
|
|
60
|
+
cep_id = lib.OptionEnum("cep_id", str, "PA1") # Default carrier (PA1, DHL, UPS)
|
|
61
|
+
product_id = lib.OptionEnum("product_id", str, "eco") # Default product code
|
|
62
|
+
label_format = lib.OptionEnum("label_format", LabelFormat)
|
|
63
|
+
label_size = lib.OptionEnum("label_size", LabelSize)
|
|
64
|
+
shipping_services = lib.OptionEnum("shipping_services", list)
|
|
65
|
+
shipping_options = lib.OptionEnum("shipping_options", list)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ShippingService(lib.StrEnum):
|
|
69
|
+
"""ParcelOne shipping services.
|
|
70
|
+
|
|
71
|
+
Format: parcelone_{cep}_{product}
|
|
72
|
+
The service code maps to CEPID and ProductID internally.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
# Parcel.One (PA1) services
|
|
76
|
+
parcelone_pa1_basic = "PA1_basic"
|
|
77
|
+
parcelone_pa1_eco = "PA1_eco"
|
|
78
|
+
parcelone_pa1_premium = "PA1_premium"
|
|
79
|
+
parcelone_pa1_express = "PA1_express"
|
|
80
|
+
|
|
81
|
+
# DHL services (via ParcelOne)
|
|
82
|
+
parcelone_dhl_paket = "DHL_PAKET"
|
|
83
|
+
parcelone_dhl_paket_international = "DHL_PAKETINT"
|
|
84
|
+
parcelone_dhl_express = "DHL_EXPRESS"
|
|
85
|
+
parcelone_dhl_retoure = "DHL_RETOURE"
|
|
86
|
+
|
|
87
|
+
# UPS services (via ParcelOne)
|
|
88
|
+
parcelone_ups_standard = "UPS_STANDARD"
|
|
89
|
+
parcelone_ups_express = "UPS_EXPRESS"
|
|
90
|
+
parcelone_ups_express_saver = "UPS_EXPSAVER"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def parse_service_code(service_code: str) -> typing.Tuple[str, str]:
|
|
94
|
+
"""Parse a service code to extract CEP ID and Product ID.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
service_code: Service code in format "CEPID_PRODUCTID"
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Tuple of (cep_id, product_id)
|
|
101
|
+
"""
|
|
102
|
+
if "_" in service_code:
|
|
103
|
+
parts = service_code.split("_", 1)
|
|
104
|
+
return parts[0], parts[1] if len(parts) > 1 else ""
|
|
105
|
+
return service_code, ""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ShippingOption(lib.Enum):
|
|
109
|
+
"""Carrier specific shipping options.
|
|
110
|
+
|
|
111
|
+
ParcelOne ServiceID values that can be added to shipments or packages.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
# Delivery options
|
|
115
|
+
parcelone_saturday_delivery = lib.OptionEnum("SDO", bool) # Saturday delivery only
|
|
116
|
+
parcelone_return_label = lib.OptionEnum("SRL", bool) # Return label
|
|
117
|
+
|
|
118
|
+
# Payment services
|
|
119
|
+
parcelone_cod = lib.OptionEnum("COD", float) # Cash on delivery
|
|
120
|
+
parcelone_cod_currency = lib.OptionEnum("COD_CURRENCY")
|
|
121
|
+
parcelone_insurance = lib.OptionEnum("INS", float) # Insurance
|
|
122
|
+
parcelone_insurance_currency = lib.OptionEnum("INS_CURRENCY")
|
|
123
|
+
|
|
124
|
+
# Notification services
|
|
125
|
+
parcelone_notification_email = lib.OptionEnum("MAIL") # Email notification
|
|
126
|
+
parcelone_notification_sms = lib.OptionEnum("SMS") # SMS notification
|
|
127
|
+
|
|
128
|
+
# Delivery confirmation
|
|
129
|
+
parcelone_signature = lib.OptionEnum("SIG", bool) # Signature required
|
|
130
|
+
parcelone_ident_check = lib.OptionEnum("IDENT", bool) # Identity check
|
|
131
|
+
parcelone_age_check = lib.OptionEnum("AGE", int) # Age verification (16, 18)
|
|
132
|
+
parcelone_personally = lib.OptionEnum("PERS", bool) # Personal delivery only
|
|
133
|
+
|
|
134
|
+
# Delivery location options
|
|
135
|
+
parcelone_neighbor_delivery = lib.OptionEnum("NEIGHBOR", bool)
|
|
136
|
+
parcelone_no_neighbor = lib.OptionEnum("NONEIGHBOR", bool)
|
|
137
|
+
parcelone_drop_off_point = lib.OptionEnum("DROP") # Parcel shop delivery (PUDO ID)
|
|
138
|
+
|
|
139
|
+
# Premium services
|
|
140
|
+
parcelone_premium = lib.OptionEnum("PREMIUM", bool)
|
|
141
|
+
parcelone_bulky_goods = lib.OptionEnum("BULKY", bool)
|
|
142
|
+
|
|
143
|
+
# Unified option mappings
|
|
144
|
+
cash_on_delivery = parcelone_cod
|
|
145
|
+
insurance = parcelone_insurance
|
|
146
|
+
signature_required = parcelone_signature
|
|
147
|
+
saturday_delivery = parcelone_saturday_delivery
|
|
148
|
+
email_notification = parcelone_notification_email
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def shipping_options_initializer(
|
|
152
|
+
options: dict,
|
|
153
|
+
package_options: units.ShippingOptions = None,
|
|
154
|
+
) -> units.ShippingOptions:
|
|
155
|
+
"""Apply default values to the given options."""
|
|
156
|
+
if package_options is not None:
|
|
157
|
+
options.update(package_options.content)
|
|
158
|
+
|
|
159
|
+
def items_filter(key: str) -> bool:
|
|
160
|
+
return key in ShippingOption # type: ignore
|
|
161
|
+
|
|
162
|
+
return units.ShippingOptions(options, ShippingOption, items_filter=items_filter)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class TrackingStatus(lib.Enum):
|
|
166
|
+
"""Carrier tracking status mapping.
|
|
167
|
+
|
|
168
|
+
Maps ParcelOne/last-mile-carrier tracking status codes to Karrio unified status.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
pending = [
|
|
172
|
+
"CREATED",
|
|
173
|
+
"REGISTERED",
|
|
174
|
+
"DATA_RECEIVED",
|
|
175
|
+
"LABEL_PRINTED",
|
|
176
|
+
"0",
|
|
177
|
+
"1",
|
|
178
|
+
]
|
|
179
|
+
delivered = [
|
|
180
|
+
"DELIVERED",
|
|
181
|
+
"POD",
|
|
182
|
+
"DELIVERED_NEIGHBOR",
|
|
183
|
+
"DELIVERED_SAFE_PLACE",
|
|
184
|
+
"DELIVERED_PARCELSHOP",
|
|
185
|
+
"90",
|
|
186
|
+
]
|
|
187
|
+
in_transit = [
|
|
188
|
+
"IN_TRANSIT",
|
|
189
|
+
"DEPARTED",
|
|
190
|
+
"ARRIVED",
|
|
191
|
+
"PROCESSED",
|
|
192
|
+
"SORTING",
|
|
193
|
+
"IN_DELIVERY_VEHICLE",
|
|
194
|
+
"EXPORTED",
|
|
195
|
+
"IMPORTED",
|
|
196
|
+
"SHIPPED",
|
|
197
|
+
"10",
|
|
198
|
+
"20",
|
|
199
|
+
"30",
|
|
200
|
+
]
|
|
201
|
+
out_for_delivery = [
|
|
202
|
+
"OUT_FOR_DELIVERY",
|
|
203
|
+
"ON_DELIVERY_VEHICLE",
|
|
204
|
+
"DELIVERY_IN_PROGRESS",
|
|
205
|
+
"80",
|
|
206
|
+
]
|
|
207
|
+
on_hold = [
|
|
208
|
+
"HELD",
|
|
209
|
+
"CUSTOMS",
|
|
210
|
+
"CUSTOMS_CLEARANCE",
|
|
211
|
+
"PAYMENT_REQUIRED",
|
|
212
|
+
"AWAITING_PICKUP",
|
|
213
|
+
"40",
|
|
214
|
+
]
|
|
215
|
+
delivery_failed = [
|
|
216
|
+
"FAILED",
|
|
217
|
+
"EXCEPTION",
|
|
218
|
+
"NOT_DELIVERED",
|
|
219
|
+
"REFUSED",
|
|
220
|
+
"ADDRESSEE_NOT_FOUND",
|
|
221
|
+
"WRONG_ADDRESS",
|
|
222
|
+
"99",
|
|
223
|
+
]
|
|
224
|
+
delivery_delayed = [
|
|
225
|
+
"DELAYED",
|
|
226
|
+
"RESCHEDULED",
|
|
227
|
+
"REDIRECTED",
|
|
228
|
+
]
|
|
229
|
+
ready_for_pickup = [
|
|
230
|
+
"READY_FOR_PICKUP",
|
|
231
|
+
"AT_PARCELSHOP",
|
|
232
|
+
"AVAILABLE_FOR_COLLECTION",
|
|
233
|
+
"70",
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def load_services_from_csv() -> list:
|
|
238
|
+
"""
|
|
239
|
+
Load service definitions from CSV file.
|
|
240
|
+
CSV format: service_code,service_name,zone_label,country_codes,min_weight,max_weight,max_length,max_width,max_height,rate,currency,transit_days,domicile,international
|
|
241
|
+
"""
|
|
242
|
+
csv_path = pathlib.Path(__file__).resolve().parent / "services.csv"
|
|
243
|
+
|
|
244
|
+
if not csv_path.exists():
|
|
245
|
+
# Fallback to simple default if CSV doesn't exist
|
|
246
|
+
return [
|
|
247
|
+
models.ServiceLevel(
|
|
248
|
+
service_name="Parcel.One Eco",
|
|
249
|
+
service_code="parcelone_pa1_eco",
|
|
250
|
+
currency="EUR",
|
|
251
|
+
domicile=True,
|
|
252
|
+
zones=[models.ServiceZone(rate=0.0)],
|
|
253
|
+
)
|
|
254
|
+
]
|
|
255
|
+
|
|
256
|
+
# Group zones by service
|
|
257
|
+
services_dict: dict[str, dict] = {}
|
|
258
|
+
|
|
259
|
+
with open(csv_path, "r", encoding="utf-8") as f:
|
|
260
|
+
reader = csv.DictReader(f)
|
|
261
|
+
for row in reader:
|
|
262
|
+
service_code = row["service_code"]
|
|
263
|
+
service_name = row["service_name"]
|
|
264
|
+
|
|
265
|
+
# Map carrier service code to karrio service code
|
|
266
|
+
karrio_service_code = ShippingService.map(service_code).name_or_key
|
|
267
|
+
|
|
268
|
+
# Initialize service if not exists
|
|
269
|
+
if karrio_service_code not in services_dict:
|
|
270
|
+
services_dict[karrio_service_code] = {
|
|
271
|
+
"service_name": service_name,
|
|
272
|
+
"service_code": karrio_service_code,
|
|
273
|
+
"currency": row.get("currency", "EUR"),
|
|
274
|
+
"min_weight": (
|
|
275
|
+
float(row["min_weight"]) if row.get("min_weight") else None
|
|
276
|
+
),
|
|
277
|
+
"max_weight": (
|
|
278
|
+
float(row["max_weight"]) if row.get("max_weight") else None
|
|
279
|
+
),
|
|
280
|
+
"max_length": (
|
|
281
|
+
float(row["max_length"]) if row.get("max_length") else None
|
|
282
|
+
),
|
|
283
|
+
"max_width": (
|
|
284
|
+
float(row["max_width"]) if row.get("max_width") else None
|
|
285
|
+
),
|
|
286
|
+
"max_height": (
|
|
287
|
+
float(row["max_height"]) if row.get("max_height") else None
|
|
288
|
+
),
|
|
289
|
+
"weight_unit": "KG",
|
|
290
|
+
"dimension_unit": "CM",
|
|
291
|
+
"domicile": row.get("domicile", "").lower() == "true",
|
|
292
|
+
"international": (
|
|
293
|
+
True if row.get("international", "").lower() == "true" else None
|
|
294
|
+
),
|
|
295
|
+
"zones": [],
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
# Parse country codes
|
|
299
|
+
country_codes = [
|
|
300
|
+
c.strip() for c in row.get("country_codes", "").split(",") if c.strip()
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
# Parse transit days (handle "1-3" format)
|
|
304
|
+
transit_days = None
|
|
305
|
+
if row.get("transit_days"):
|
|
306
|
+
transit_str = row["transit_days"].split("-")[0]
|
|
307
|
+
if transit_str.isdigit():
|
|
308
|
+
transit_days = int(transit_str)
|
|
309
|
+
|
|
310
|
+
# Create zone
|
|
311
|
+
zone = models.ServiceZone(
|
|
312
|
+
label=row.get("zone_label", "Default Zone"),
|
|
313
|
+
rate=float(row.get("rate", 0.0)),
|
|
314
|
+
transit_days=transit_days,
|
|
315
|
+
country_codes=country_codes if country_codes else None,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
services_dict[karrio_service_code]["zones"].append(zone)
|
|
319
|
+
|
|
320
|
+
# Convert to ServiceLevel objects
|
|
321
|
+
return [
|
|
322
|
+
models.ServiceLevel(**service_data) for service_data in services_dict.values()
|
|
323
|
+
]
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
DEFAULT_SERVICES = load_services_from_csv()
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""ParcelOne REST API connection utilities and settings."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import karrio.lib as lib
|
|
5
|
+
import karrio.core as core
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Settings(core.Settings):
|
|
9
|
+
"""ParcelOne REST API connection settings."""
|
|
10
|
+
|
|
11
|
+
# Required credentials
|
|
12
|
+
username: str
|
|
13
|
+
password: str
|
|
14
|
+
mandator_id: str
|
|
15
|
+
consigner_id: str
|
|
16
|
+
|
|
17
|
+
# Generic properties
|
|
18
|
+
id: str = None
|
|
19
|
+
test_mode: bool = False
|
|
20
|
+
carrier_id: str = "parcelone"
|
|
21
|
+
account_country_code: str = "DE"
|
|
22
|
+
metadata: dict = {}
|
|
23
|
+
config: dict = {}
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def carrier_name(self):
|
|
27
|
+
return "parcelone"
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def server_url(self):
|
|
31
|
+
return (
|
|
32
|
+
"https://sandboxapi.parcel.one/v1"
|
|
33
|
+
if self.test_mode
|
|
34
|
+
else "https://api.parcel.one/v1"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def tracking_url(self):
|
|
39
|
+
return (
|
|
40
|
+
"https://sandboxapi.parcel.one/v1/tracklmc"
|
|
41
|
+
if self.test_mode
|
|
42
|
+
else "https://api.parcel.one/v1/tracklmc"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def tracking_link(self):
|
|
47
|
+
return "https://tracking.parcel.one/?trackingNumber={}"
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def authorization(self):
|
|
51
|
+
"""HTTP Basic Auth header value."""
|
|
52
|
+
credentials = f"{self.username}:{self.password}"
|
|
53
|
+
encoded = base64.b64encode(credentials.encode()).decode()
|
|
54
|
+
return f"Basic {encoded}"
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def connection_config(self) -> lib.units.Options:
|
|
58
|
+
from karrio.providers.parcelone.units import ConnectionConfig
|
|
59
|
+
|
|
60
|
+
return lib.to_connection_config(
|
|
61
|
+
self.config or {},
|
|
62
|
+
option_type=ConnectionConfig,
|
|
63
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""ParcelOne REST API v1 - Error Types."""
|
|
2
|
+
|
|
3
|
+
import attr
|
|
4
|
+
import jstruct
|
|
5
|
+
import typing
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@attr.s(auto_attribs=True)
|
|
9
|
+
class ErrorDetailType:
|
|
10
|
+
"""Error detail information."""
|
|
11
|
+
|
|
12
|
+
ErrorNo: typing.Optional[str] = None
|
|
13
|
+
Message: typing.Optional[str] = None
|
|
14
|
+
StatusCode: typing.Optional[str] = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@attr.s(auto_attribs=True)
|
|
18
|
+
class ErrorResponseType:
|
|
19
|
+
"""API error response."""
|
|
20
|
+
|
|
21
|
+
status: typing.Optional[int] = None
|
|
22
|
+
success: typing.Optional[int] = None
|
|
23
|
+
message: typing.Optional[str] = None
|
|
24
|
+
type: typing.Optional[str] = None
|
|
25
|
+
instance: typing.Optional[str] = None
|
|
26
|
+
errors: typing.Optional[typing.List[ErrorDetailType]] = jstruct.JList[ErrorDetailType]
|
|
27
|
+
UniqId: typing.Optional[str] = None
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""ParcelOne Shipping REST API v1 - Request Types."""
|
|
2
|
+
|
|
3
|
+
import attr
|
|
4
|
+
import jstruct
|
|
5
|
+
import typing
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@attr.s(auto_attribs=True)
|
|
9
|
+
class AddressType:
|
|
10
|
+
"""Address data format."""
|
|
11
|
+
|
|
12
|
+
Street: typing.Optional[str] = None
|
|
13
|
+
Streetno: typing.Optional[str] = None
|
|
14
|
+
PostalCode: typing.Optional[str] = None
|
|
15
|
+
City: typing.Optional[str] = None
|
|
16
|
+
District: typing.Optional[str] = None
|
|
17
|
+
State: typing.Optional[str] = None
|
|
18
|
+
Country: typing.Optional[str] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@attr.s(auto_attribs=True)
|
|
22
|
+
class ContactType:
|
|
23
|
+
"""Contact information."""
|
|
24
|
+
|
|
25
|
+
Email: typing.Optional[str] = None
|
|
26
|
+
Phone: typing.Optional[str] = None
|
|
27
|
+
Mobile: typing.Optional[str] = None
|
|
28
|
+
Fax: typing.Optional[str] = None
|
|
29
|
+
AttentionName: typing.Optional[str] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@attr.s(auto_attribs=True)
|
|
33
|
+
class ShipToType:
|
|
34
|
+
"""Recipient/consignee address data."""
|
|
35
|
+
|
|
36
|
+
Name1: typing.Optional[str] = None
|
|
37
|
+
Name2: typing.Optional[str] = None
|
|
38
|
+
Name3: typing.Optional[str] = None
|
|
39
|
+
Reference: typing.Optional[str] = None
|
|
40
|
+
ShipmentAddress: typing.Optional[AddressType] = jstruct.JStruct[AddressType]
|
|
41
|
+
ShipmentContact: typing.Optional[ContactType] = jstruct.JStruct[ContactType]
|
|
42
|
+
PrivateAddressIndicator: typing.Optional[int] = None
|
|
43
|
+
SalesTaxID: typing.Optional[str] = None
|
|
44
|
+
CustomsID: typing.Optional[str] = None
|
|
45
|
+
BranchID: typing.Optional[str] = None
|
|
46
|
+
CEPCustID: typing.Optional[str] = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@attr.s(auto_attribs=True)
|
|
50
|
+
class ShipFromType:
|
|
51
|
+
"""Consigner/sender address data."""
|
|
52
|
+
|
|
53
|
+
Name1: typing.Optional[str] = None
|
|
54
|
+
Name2: typing.Optional[str] = None
|
|
55
|
+
Name3: typing.Optional[str] = None
|
|
56
|
+
Reference: typing.Optional[str] = None
|
|
57
|
+
ShipmentAddress: typing.Optional[AddressType] = jstruct.JStruct[AddressType]
|
|
58
|
+
ShipmentContact: typing.Optional[ContactType] = jstruct.JStruct[ContactType]
|
|
59
|
+
SalesTaxID: typing.Optional[str] = None
|
|
60
|
+
CustomsID: typing.Optional[str] = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@attr.s(auto_attribs=True)
|
|
64
|
+
class FormatType:
|
|
65
|
+
"""Document format specification."""
|
|
66
|
+
|
|
67
|
+
Type: typing.Optional[str] = None
|
|
68
|
+
Size: typing.Optional[str] = None
|
|
69
|
+
Unit: typing.Optional[str] = None
|
|
70
|
+
Orientation: typing.Optional[int] = None
|
|
71
|
+
Height: typing.Optional[str] = None
|
|
72
|
+
Width: typing.Optional[str] = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@attr.s(auto_attribs=True)
|
|
76
|
+
class MeasurementType:
|
|
77
|
+
"""Weight or volume measurement."""
|
|
78
|
+
|
|
79
|
+
Unit: typing.Optional[str] = None
|
|
80
|
+
Value: typing.Optional[str] = None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@attr.s(auto_attribs=True)
|
|
84
|
+
class DimensionsType:
|
|
85
|
+
"""Package dimensions."""
|
|
86
|
+
|
|
87
|
+
Length: typing.Optional[str] = None
|
|
88
|
+
Width: typing.Optional[str] = None
|
|
89
|
+
Height: typing.Optional[str] = None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@attr.s(auto_attribs=True)
|
|
93
|
+
class AmountType:
|
|
94
|
+
"""Monetary amount."""
|
|
95
|
+
|
|
96
|
+
Currency: typing.Optional[str] = None
|
|
97
|
+
Value: typing.Optional[str] = None
|
|
98
|
+
Description: typing.Optional[str] = None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@attr.s(auto_attribs=True)
|
|
102
|
+
class ShipmentServiceType:
|
|
103
|
+
"""Service for shipment or package."""
|
|
104
|
+
|
|
105
|
+
ServiceID: typing.Optional[str] = None
|
|
106
|
+
Value: typing.Optional[AmountType] = jstruct.JStruct[AmountType]
|
|
107
|
+
Parameters: typing.Optional[str] = None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@attr.s(auto_attribs=True)
|
|
111
|
+
class CustomDetailType:
|
|
112
|
+
"""Customs detail line item."""
|
|
113
|
+
|
|
114
|
+
Contents: typing.Optional[str] = None
|
|
115
|
+
ItemValue: typing.Optional[float] = None
|
|
116
|
+
ItemValuePerItem: typing.Optional[float] = None
|
|
117
|
+
NetWeight: typing.Optional[float] = None
|
|
118
|
+
NetWeightPerItem: typing.Optional[float] = None
|
|
119
|
+
Origin: typing.Optional[str] = None
|
|
120
|
+
Quantity: typing.Optional[int] = None
|
|
121
|
+
TariffNumber: typing.Optional[str] = None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@attr.s(auto_attribs=True)
|
|
125
|
+
class InternationalDocFormatType:
|
|
126
|
+
"""International document format."""
|
|
127
|
+
|
|
128
|
+
Type: typing.Optional[str] = None
|
|
129
|
+
Size: typing.Optional[str] = None
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@attr.s(auto_attribs=True)
|
|
133
|
+
class IntDocDataType:
|
|
134
|
+
"""International/customs documentation data."""
|
|
135
|
+
|
|
136
|
+
ConsignerCustomsID: typing.Optional[str] = None
|
|
137
|
+
Invoice: typing.Optional[int] = None
|
|
138
|
+
InvoiceNo: typing.Optional[str] = None
|
|
139
|
+
PrintInternationalDocuments: typing.Optional[int] = None
|
|
140
|
+
InternationalDocumentFormat: typing.Optional[InternationalDocFormatType] = jstruct.JStruct[InternationalDocFormatType]
|
|
141
|
+
ShipToRef: typing.Optional[str] = None
|
|
142
|
+
TotalWeightkg: typing.Optional[float] = None
|
|
143
|
+
Postage: typing.Optional[float] = None
|
|
144
|
+
ItemCategory: typing.Optional[int] = None
|
|
145
|
+
CustomDetails: typing.Optional[typing.List[CustomDetailType]] = jstruct.JList[CustomDetailType]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@attr.s(auto_attribs=True)
|
|
149
|
+
class ShipmentPackageType:
|
|
150
|
+
"""Package within a shipment."""
|
|
151
|
+
|
|
152
|
+
PackageRef: typing.Optional[str] = None
|
|
153
|
+
PackageType: typing.Optional[str] = None
|
|
154
|
+
PackageWeight: typing.Optional[MeasurementType] = jstruct.JStruct[MeasurementType]
|
|
155
|
+
PackageDimensions: typing.Optional[DimensionsType] = jstruct.JStruct[DimensionsType]
|
|
156
|
+
PackageVolume: typing.Optional[MeasurementType] = jstruct.JStruct[MeasurementType]
|
|
157
|
+
Services: typing.Optional[typing.List[ShipmentServiceType]] = jstruct.JList[ShipmentServiceType]
|
|
158
|
+
IntDocData: typing.Optional[IntDocDataType] = jstruct.JStruct[IntDocDataType]
|
|
159
|
+
Remarks: typing.Optional[str] = None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@attr.s(auto_attribs=True)
|
|
163
|
+
class CEPSpecialType:
|
|
164
|
+
"""CEP-specific special options."""
|
|
165
|
+
|
|
166
|
+
Key: typing.Optional[str] = None
|
|
167
|
+
Value: typing.Optional[str] = None
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@attr.s(auto_attribs=True)
|
|
171
|
+
class ShipmentType:
|
|
172
|
+
"""Complete shipment registration request."""
|
|
173
|
+
|
|
174
|
+
ShipmentRef: typing.Optional[str] = None
|
|
175
|
+
CEPID: typing.Optional[str] = None
|
|
176
|
+
ProductID: typing.Optional[str] = None
|
|
177
|
+
MandatorID: typing.Optional[str] = None
|
|
178
|
+
ConsignerID: typing.Optional[str] = None
|
|
179
|
+
ShipToData: typing.Optional[ShipToType] = jstruct.JStruct[ShipToType]
|
|
180
|
+
ShipFromData: typing.Optional[ShipFromType] = jstruct.JStruct[ShipFromType]
|
|
181
|
+
ReturnShipmentIndicator: typing.Optional[int] = None
|
|
182
|
+
PrintLabel: typing.Optional[int] = None
|
|
183
|
+
LabelFormat: typing.Optional[FormatType] = jstruct.JStruct[FormatType]
|
|
184
|
+
PrintDocuments: typing.Optional[int] = None
|
|
185
|
+
DocumentFormat: typing.Optional[FormatType] = jstruct.JStruct[FormatType]
|
|
186
|
+
ReturnCharges: typing.Optional[int] = None
|
|
187
|
+
MaxCharges: typing.Optional[AmountType] = jstruct.JStruct[AmountType]
|
|
188
|
+
Software: typing.Optional[str] = None
|
|
189
|
+
Packages: typing.Optional[typing.List[ShipmentPackageType]] = jstruct.JList[ShipmentPackageType]
|
|
190
|
+
Services: typing.Optional[typing.List[ShipmentServiceType]] = jstruct.JList[ShipmentServiceType]
|
|
191
|
+
CEPSpecials: typing.Optional[typing.List[CEPSpecialType]] = jstruct.JList[CEPSpecialType]
|
|
192
|
+
CostCenter: typing.Optional[str] = None
|
|
193
|
+
Other1: typing.Optional[str] = None
|
|
194
|
+
Other2: typing.Optional[str] = None
|
|
195
|
+
Other3: typing.Optional[str] = None
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@attr.s(auto_attribs=True)
|
|
199
|
+
class ShippingDataRequestType:
|
|
200
|
+
"""Root shipping data request wrapper."""
|
|
201
|
+
|
|
202
|
+
ShippingData: typing.Optional[ShipmentType] = jstruct.JStruct[ShipmentType]
|