karrio-dicom 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/dicom/__init__.py +3 -0
- karrio/mappers/dicom/mapper.py +107 -0
- karrio/mappers/dicom/proxy.py +31 -0
- karrio/mappers/dicom/settings.py +22 -0
- karrio/plugins/dicom/__init__.py +16 -0
- karrio/providers/dicom/__init__.py +20 -0
- karrio/providers/dicom/error.py +19 -0
- karrio/providers/dicom/pickup/__init__.py +3 -0
- karrio/providers/dicom/pickup/cancel.py +33 -0
- karrio/providers/dicom/pickup/create.py +102 -0
- karrio/providers/dicom/pickup/update.py +57 -0
- karrio/providers/dicom/rate.py +127 -0
- karrio/providers/dicom/shipment/__init__.py +2 -0
- karrio/providers/dicom/shipment/cancel.py +32 -0
- karrio/providers/dicom/shipment/create.py +192 -0
- karrio/providers/dicom/tracking.py +47 -0
- karrio/providers/dicom/units.py +167 -0
- karrio/providers/dicom/utils.py +34 -0
- karrio/schemas/dicom/__init__.py +0 -0
- karrio/schemas/dicom/pickups.py +83 -0
- karrio/schemas/dicom/rates.py +126 -0
- karrio/schemas/dicom/shipments.py +140 -0
- karrio/schemas/dicom/tracking.py +58 -0
- karrio_dicom-2025.5rc1.dist-info/METADATA +44 -0
- karrio_dicom-2025.5rc1.dist-info/RECORD +28 -0
- karrio_dicom-2025.5rc1.dist-info/WHEEL +5 -0
- karrio_dicom-2025.5rc1.dist-info/entry_points.txt +2 -0
- karrio_dicom-2025.5rc1.dist-info/top_level.txt +3 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
from typing import Tuple, List
|
2
|
+
from karrio.schemas.dicom.shipments import (
|
3
|
+
ShipmentRequest as DicomShipmentRequest,
|
4
|
+
Address as DicomAddress,
|
5
|
+
Parcel,
|
6
|
+
Surcharge,
|
7
|
+
Contact,
|
8
|
+
InternationalDetails,
|
9
|
+
Product,
|
10
|
+
Broker,
|
11
|
+
ShipmentResponse,
|
12
|
+
)
|
13
|
+
import karrio.lib as lib
|
14
|
+
from karrio.core.units import Packages
|
15
|
+
from karrio.core.utils import Serializable, DP
|
16
|
+
from karrio.core.models import (
|
17
|
+
Documents,
|
18
|
+
ShipmentRequest,
|
19
|
+
ShipmentDetails,
|
20
|
+
Message,
|
21
|
+
Address,
|
22
|
+
Payment,
|
23
|
+
)
|
24
|
+
|
25
|
+
from karrio.providers.dicom.units import (
|
26
|
+
UnitOfMeasurement,
|
27
|
+
ParcelType,
|
28
|
+
Service,
|
29
|
+
ShippingOption,
|
30
|
+
PaymentType,
|
31
|
+
Purpose,
|
32
|
+
)
|
33
|
+
from karrio.providers.dicom.error import parse_error_response
|
34
|
+
from karrio.providers.dicom.utils import Settings
|
35
|
+
|
36
|
+
|
37
|
+
def parse_shipment_response(
|
38
|
+
_response: lib.Deserializable[dict],
|
39
|
+
settings: Settings,
|
40
|
+
) -> Tuple[ShipmentDetails, List[Message]]:
|
41
|
+
response = _response.deserialize()
|
42
|
+
errors = parse_error_response(response, settings)
|
43
|
+
details = (
|
44
|
+
_extract_details(response, settings)
|
45
|
+
if all(key in response for key in ["label", "shipment"])
|
46
|
+
else None
|
47
|
+
)
|
48
|
+
|
49
|
+
return details, errors
|
50
|
+
|
51
|
+
|
52
|
+
def _extract_details(response: dict, settings: Settings) -> ShipmentDetails:
|
53
|
+
label: str = response["label"]
|
54
|
+
shipment = DP.to_object(ShipmentResponse, response["shipment"])
|
55
|
+
|
56
|
+
return ShipmentDetails(
|
57
|
+
carrier_name=settings.carrier_name,
|
58
|
+
carrier_id=settings.carrier_id,
|
59
|
+
tracking_number=shipment.trackingNumber,
|
60
|
+
shipment_identifier=shipment.ID,
|
61
|
+
docs=Documents(label=label),
|
62
|
+
)
|
63
|
+
|
64
|
+
|
65
|
+
def shipment_request(payload: ShipmentRequest, settings: Settings) -> Serializable:
|
66
|
+
packages = Packages(payload.parcels)
|
67
|
+
shipper = lib.to_address(payload.shipper)
|
68
|
+
recipient = lib.to_address(payload.recipient)
|
69
|
+
is_international = shipper.country_code != recipient.country_code
|
70
|
+
broker_info = payload.options.get("dicom_broker_info", {})
|
71
|
+
importer_info = (
|
72
|
+
Address(**payload.options.get("importer_info"))
|
73
|
+
if "importer_info" in payload.options
|
74
|
+
else None
|
75
|
+
)
|
76
|
+
payment = payload.payment or Payment("prepaid")
|
77
|
+
delivery_type = Service[payload.service].value
|
78
|
+
options = {
|
79
|
+
key: (value if ShippingOption[key].value in ["DCV", "COD"] else None)
|
80
|
+
for key, value in payload.options
|
81
|
+
if key in ShippingOption.__members__
|
82
|
+
}
|
83
|
+
|
84
|
+
request = DicomShipmentRequest(
|
85
|
+
paymentType=PaymentType[payment.paid_by or "prepaid"].value,
|
86
|
+
billingAccount=settings.billing_account,
|
87
|
+
sender=DicomAddress(
|
88
|
+
city=shipper.city,
|
89
|
+
provinceCode=shipper.state_code,
|
90
|
+
postalCode=shipper.postal_code,
|
91
|
+
countryCode=shipper.country_code,
|
92
|
+
customerName=shipper.company_name,
|
93
|
+
addressLine1=shipper.street,
|
94
|
+
addressLine2=shipper.address_line2,
|
95
|
+
contact=Contact(
|
96
|
+
fullName=shipper.person_name,
|
97
|
+
email=shipper.email,
|
98
|
+
telephone=shipper.phone_number,
|
99
|
+
),
|
100
|
+
),
|
101
|
+
consignee=DicomAddress(
|
102
|
+
city=recipient.city,
|
103
|
+
provinceCode=recipient.state_code,
|
104
|
+
postalCode=recipient.postal_code,
|
105
|
+
countryCode=recipient.country_code,
|
106
|
+
customerName=recipient.company_name,
|
107
|
+
addressLine1=recipient.street,
|
108
|
+
addressLine2=recipient.address_line2,
|
109
|
+
contact=Contact(
|
110
|
+
fullName=recipient.person_name,
|
111
|
+
email=recipient.email,
|
112
|
+
telephone=recipient.phone_number,
|
113
|
+
),
|
114
|
+
),
|
115
|
+
parcels=[
|
116
|
+
Parcel(
|
117
|
+
quantity=1,
|
118
|
+
parcelType=ParcelType[package.packaging_type or "dicom_box"].value,
|
119
|
+
weight=package.weight.KG,
|
120
|
+
length=package.height.CM,
|
121
|
+
depth=package.length.CM,
|
122
|
+
width=package.width.CM,
|
123
|
+
note=None,
|
124
|
+
status=None,
|
125
|
+
FCAClass=None,
|
126
|
+
hazmat=None,
|
127
|
+
requestReturnLabel=None,
|
128
|
+
returnWaybill=None,
|
129
|
+
)
|
130
|
+
for package in packages
|
131
|
+
],
|
132
|
+
note=None,
|
133
|
+
category="Parcel",
|
134
|
+
pickupDate=None,
|
135
|
+
deliveryType=delivery_type,
|
136
|
+
trackingNumber=None,
|
137
|
+
unitOfMeasurement=UnitOfMeasurement.KC.value,
|
138
|
+
surcharges=[Surcharge(type=key, value=value) for key, value in options.items()],
|
139
|
+
promoCodes=None,
|
140
|
+
references=None,
|
141
|
+
returnAddress=None,
|
142
|
+
appointment=None,
|
143
|
+
internationalDetails=(
|
144
|
+
InternationalDetails(
|
145
|
+
isDicomBroker=(broker_info is not None),
|
146
|
+
descriptionOfGoods=payload.customs.content_description,
|
147
|
+
dutyBilling=payload.customs.duty.paid_by,
|
148
|
+
importerOfRecord=(
|
149
|
+
DicomAddress(
|
150
|
+
city=importer_info.city,
|
151
|
+
provinceCode=importer_info.state_code,
|
152
|
+
postalCode=importer_info.postal_code,
|
153
|
+
countryCode=importer_info.country_code,
|
154
|
+
customerName=importer_info.company_name,
|
155
|
+
addressLine1=lib.text(
|
156
|
+
importer_info.street_number, importer_info.address_line1
|
157
|
+
),
|
158
|
+
addressLine2=importer_info.address_line2,
|
159
|
+
contact=Contact(
|
160
|
+
fullName=importer_info.person_name,
|
161
|
+
email=importer_info.email,
|
162
|
+
telephone=importer_info.phone_number,
|
163
|
+
),
|
164
|
+
)
|
165
|
+
if importer_info is not None
|
166
|
+
else None
|
167
|
+
),
|
168
|
+
broker=(
|
169
|
+
Broker(
|
170
|
+
id=broker_info.get("id"),
|
171
|
+
CSA_BusinessNumber=broker_info.get("CSA_BusinessNumber"),
|
172
|
+
otherBroker=broker_info.get("otherBroker"),
|
173
|
+
)
|
174
|
+
if broker_info is not None
|
175
|
+
else None
|
176
|
+
),
|
177
|
+
purpose=(
|
178
|
+
Purpose[payload.customs.content_type].value
|
179
|
+
if payload.customs.content_type is not None
|
180
|
+
else None
|
181
|
+
),
|
182
|
+
products=[
|
183
|
+
Product(id=index, Quantity=product.quantity)
|
184
|
+
for index, product in enumerate(payload.customs.commodities, 1)
|
185
|
+
],
|
186
|
+
)
|
187
|
+
if is_international and payload.customs is not None
|
188
|
+
else None
|
189
|
+
),
|
190
|
+
)
|
191
|
+
|
192
|
+
return Serializable(request)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
from typing import Tuple, List
|
2
|
+
from karrio.schemas.dicom.tracking import Tracking
|
3
|
+
from karrio.core.utils import Serializable, DF, DP
|
4
|
+
from karrio.core.models import TrackingRequest, TrackingDetails, TrackingEvent, Message
|
5
|
+
|
6
|
+
from karrio.providers.dicom.error import parse_error_response
|
7
|
+
from karrio.providers.dicom.utils import Settings
|
8
|
+
import karrio.lib as lib
|
9
|
+
|
10
|
+
|
11
|
+
def parse_tracking_response(
|
12
|
+
_response: lib.Deserializable[dict],
|
13
|
+
settings: Settings,
|
14
|
+
) -> Tuple[List[TrackingDetails], List[Message]]:
|
15
|
+
response = _response.deserialize()
|
16
|
+
errors = [e for e in response if "activities" not in e]
|
17
|
+
details = [
|
18
|
+
_extract_detail(DP.to_object(Tracking, d), settings)
|
19
|
+
for d in response
|
20
|
+
if "activities" in d
|
21
|
+
]
|
22
|
+
|
23
|
+
return details, parse_error_response(errors, settings)
|
24
|
+
|
25
|
+
|
26
|
+
def _extract_detail(detail: Tracking, settings: Settings) -> TrackingDetails:
|
27
|
+
return TrackingDetails(
|
28
|
+
carrier_name=settings.carrier_name,
|
29
|
+
carrier_id=settings.carrier_id,
|
30
|
+
tracking_number=detail.trackingNumber,
|
31
|
+
events=[
|
32
|
+
TrackingEvent(
|
33
|
+
date=DF.fdate(event.activityDate, "%Y-%m-%dT%H:%M:%SZ"),
|
34
|
+
description=event.statusDetail,
|
35
|
+
location=event.terminal,
|
36
|
+
code=event.status,
|
37
|
+
time=DF.ftime(event.activityDate, "%Y-%m-%dT%H:%M:%SZ"),
|
38
|
+
)
|
39
|
+
for event in detail.activities
|
40
|
+
],
|
41
|
+
)
|
42
|
+
|
43
|
+
|
44
|
+
def tracking_request(payload: TrackingRequest, _) -> Serializable:
|
45
|
+
request = payload.tracking_numbers
|
46
|
+
|
47
|
+
return Serializable(request)
|
@@ -0,0 +1,167 @@
|
|
1
|
+
import karrio.lib as lib
|
2
|
+
import karrio.core.units as units
|
3
|
+
|
4
|
+
|
5
|
+
class UnitOfMeasurement(lib.StrEnum):
|
6
|
+
K = "K"
|
7
|
+
L = "L"
|
8
|
+
KC = "KC"
|
9
|
+
KM = "KM"
|
10
|
+
LI = "LI"
|
11
|
+
LF = "LF"
|
12
|
+
|
13
|
+
|
14
|
+
class Category(lib.StrEnum):
|
15
|
+
parcel = "Parcel"
|
16
|
+
freight = "Freight"
|
17
|
+
distribution = "Distribution"
|
18
|
+
logistics = "Logistics"
|
19
|
+
|
20
|
+
|
21
|
+
class Purpose(lib.StrEnum):
|
22
|
+
com = "COM"
|
23
|
+
per = "PER"
|
24
|
+
doc = "DOC"
|
25
|
+
ret = "RET"
|
26
|
+
|
27
|
+
""" Unified Customs Content Type mapping """
|
28
|
+
|
29
|
+
documents = doc
|
30
|
+
gift = per
|
31
|
+
sample = per
|
32
|
+
merchandise = com
|
33
|
+
return_merchandise = ret
|
34
|
+
other = per
|
35
|
+
|
36
|
+
|
37
|
+
class PaymentType(lib.StrEnum):
|
38
|
+
prepaid = "Prepaid"
|
39
|
+
third_party = "ThirdParty"
|
40
|
+
collect = "Collect"
|
41
|
+
|
42
|
+
""" Unified Payment Type mapping """
|
43
|
+
|
44
|
+
sender = prepaid
|
45
|
+
recipient = collect
|
46
|
+
|
47
|
+
|
48
|
+
class ParcelType(lib.StrEnum):
|
49
|
+
dicom_barrel = "Barrel"
|
50
|
+
dicom_bundle = "Bundle"
|
51
|
+
dicom_box = "Box"
|
52
|
+
dicom_crate = "Crate"
|
53
|
+
dicom_full_load = "FullLoad"
|
54
|
+
dicom_mixed = "Mixed"
|
55
|
+
dicom_other = "Other"
|
56
|
+
dicom_piece = "Piece"
|
57
|
+
dicom_skid = "Skid"
|
58
|
+
dicom_tube = "Tube"
|
59
|
+
dicom_envelope = "Envelope"
|
60
|
+
dicom_maxpak = "Maxpak"
|
61
|
+
dicom_pallet = "Pallet"
|
62
|
+
|
63
|
+
""" Unified Packaging type mapping """
|
64
|
+
|
65
|
+
envelope = dicom_envelope
|
66
|
+
pak = dicom_maxpak
|
67
|
+
tube = dicom_tube
|
68
|
+
pallet = dicom_pallet
|
69
|
+
small_box = dicom_box
|
70
|
+
medium_box = dicom_box
|
71
|
+
your_packaging = dicom_other
|
72
|
+
|
73
|
+
|
74
|
+
class Service(lib.StrEnum): # DeliveryType
|
75
|
+
dicom_air_delivery = "AIR"
|
76
|
+
dicom_ground_delivery = "GRD"
|
77
|
+
|
78
|
+
|
79
|
+
class ShippingOption(lib.Enum):
|
80
|
+
dicom_common_declared_value = lib.OptionEnum("DCV")
|
81
|
+
dicom_common_dangerous_goods = lib.OptionEnum("DGG")
|
82
|
+
dicom_common_residential_delivery = lib.OptionEnum("PHD")
|
83
|
+
dicom_common_tradeshow_delivery = lib.OptionEnum("TRD")
|
84
|
+
dicom_common_signature_not_required = lib.OptionEnum("SNR")
|
85
|
+
dicom_parcel_ca_hold_for_pickup = lib.OptionEnum("HFP")
|
86
|
+
dicom_parcel_ca_non_conveyable = lib.OptionEnum("NCV")
|
87
|
+
dicom_parcel_ca_residential_delivery_signature = lib.OptionEnum("PHDS")
|
88
|
+
dicom_parcel_ca_weekend_delivery = lib.OptionEnum("WKD")
|
89
|
+
dicom_freight_construction_site_delivery = lib.OptionEnum("CNSTD")
|
90
|
+
dicom_freight_collect_on_delivery = lib.OptionEnum("COD")
|
91
|
+
dicom_freight_heating = lib.OptionEnum("HEAT")
|
92
|
+
dicom_freight_inside_delivery = lib.OptionEnum("IDEL")
|
93
|
+
dicom_freight_residential_delivery_signature = lib.OptionEnum("PHDS")
|
94
|
+
dicom_freight_residential_pickup = lib.OptionEnum("PHPU")
|
95
|
+
dicom_freight_tailgate_delivery = lib.OptionEnum("TGT")
|
96
|
+
dicom_freight_tailgate_pickup = lib.OptionEnum("TGTPU")
|
97
|
+
dicom_parcel_us_adult_signature = lib.OptionEnum("ADLSIG")
|
98
|
+
dicom_parcel_us_direct_signature = lib.OptionEnum("DIRSIG")
|
99
|
+
dicom_parcel_us_saturday_delivery = lib.OptionEnum("SAT")
|
100
|
+
dicom_parcel_us_sunday_delivery = lib.OptionEnum("SUN")
|
101
|
+
dicom_parcel_us_residential_delivery_signature = lib.OptionEnum("PHDS")
|
102
|
+
dicom_parcel_us_earliest_possible = lib.OptionEnum("EP")
|
103
|
+
dicom_parcel_us_priority_service = lib.OptionEnum("PR")
|
104
|
+
dicom_parcel_us_pouch_service = lib.OptionEnum("PO")
|
105
|
+
dicom_parcel_us_pallet_service_pa = lib.OptionEnum("PA")
|
106
|
+
dicom_parcel_us_pallet_service_rap = lib.OptionEnum("RAP")
|
107
|
+
dicom_parcel_us_pallet_service_nd = lib.OptionEnum("ND")
|
108
|
+
|
109
|
+
""" Unified Option type mapping """
|
110
|
+
saturday_delivery = dicom_parcel_us_saturday_delivery
|
111
|
+
|
112
|
+
|
113
|
+
def shipping_options_initializer(
|
114
|
+
options: dict,
|
115
|
+
package_options: units.Options = None,
|
116
|
+
) -> units.Options:
|
117
|
+
"""
|
118
|
+
Apply default values to the given options.
|
119
|
+
"""
|
120
|
+
_options = options.copy()
|
121
|
+
|
122
|
+
if package_options is not None:
|
123
|
+
_options.update(package_options.content)
|
124
|
+
|
125
|
+
return units.ShippingOptions(_options, ShippingOption)
|
126
|
+
|
127
|
+
|
128
|
+
class Surcharge(lib.StrEnum):
|
129
|
+
dicom_common_base = "BAS"
|
130
|
+
dicom_common_declared_value = "DCV"
|
131
|
+
dicom_common_dangerous_goods = "DGG"
|
132
|
+
dicom_common_other_charge = "OTH"
|
133
|
+
dicom_common_residential_delivery = "PHD"
|
134
|
+
dicom_common_tradeshow_delivery = "TRD"
|
135
|
+
dicom_parcel_ca_collect_on_delivery = "COD"
|
136
|
+
dicom_parcel_ca_collect = "COL"
|
137
|
+
dicom_parcel_ca_chain_of_signature = "COS"
|
138
|
+
dicom_parcel_ca_dangerous_goods = "DGA"
|
139
|
+
dicom_parcel_ca_hold_for_pickup = "HFP"
|
140
|
+
dicom_parcel_ca_multi_pieces = "MPC"
|
141
|
+
dicom_parcel_ca_non_conveyable = "NCV"
|
142
|
+
dicom_parcel_ca_residential_delivery_signature = "PHS"
|
143
|
+
dicom_parcel_ca_over_36_inches = "O36"
|
144
|
+
dicom_parcel_ca_over_44_inches = "O44"
|
145
|
+
dicom_parcel_ca_over_96_inches = "O96"
|
146
|
+
dicom_parcel_ca_overweight = "OVW"
|
147
|
+
dicom_parcel_ca_signature_not_required = "SNR"
|
148
|
+
dicom_parcel_ca_trade_show = "TRD"
|
149
|
+
dicom_parcel_ca_weekend_delivery = "WKD"
|
150
|
+
dicom_parcel_ca_weekend_kilometers = "WKK"
|
151
|
+
dicom_parcel_ca_zone = "ZON"
|
152
|
+
dicom_parcel_ca_ontario_minimum_wage = "SMO"
|
153
|
+
dicom_parcel_ca_overweight_shipment = "OWS"
|
154
|
+
dicom_freight_construction_site_delivery = "CNSTD"
|
155
|
+
dicom_freight_collect_on_delivery = "COD"
|
156
|
+
dicom_freight_congestion_pickup = "CPU"
|
157
|
+
dicom_freight_heating = "HEAT"
|
158
|
+
dicom_freight_inside_delivery = "IDEL"
|
159
|
+
dicom_freight_pan_am_games_delivery = "PADL"
|
160
|
+
dicom_freight_pan_am_games_pickup = "PAPU"
|
161
|
+
dicom_freight_residential_delivery_signature = "PHDS"
|
162
|
+
dicom_freight_residential_pickup = "PHPU"
|
163
|
+
dicom_freight_promo_cash = "PRC"
|
164
|
+
dicom_freight_promo_pourcent = "PRP"
|
165
|
+
dicom_freight_single_pickup = "SPU"
|
166
|
+
dicom_freight_tailgate_delivery = "TGT"
|
167
|
+
dicom_freight_tailgate_pickup = "TGTPU"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
"""Karrio Dicom client settings."""
|
2
|
+
|
3
|
+
from base64 import b64encode
|
4
|
+
from karrio.core.settings import Settings as BaseSettings
|
5
|
+
|
6
|
+
|
7
|
+
class Settings(BaseSettings):
|
8
|
+
"""Dicom connection settings."""
|
9
|
+
|
10
|
+
# Carrier specific properties
|
11
|
+
username: str
|
12
|
+
password: str
|
13
|
+
billing_account: str = None
|
14
|
+
|
15
|
+
id: str = None
|
16
|
+
account_country_code: str = None
|
17
|
+
metadata: dict = {}
|
18
|
+
|
19
|
+
@property
|
20
|
+
def carrier_name(self):
|
21
|
+
return "dicom"
|
22
|
+
|
23
|
+
@property
|
24
|
+
def server_url(self):
|
25
|
+
return (
|
26
|
+
"https://sandbox-smart4i.dicom.com"
|
27
|
+
if self.test_mode
|
28
|
+
else "https://smart4i.dicom.com"
|
29
|
+
)
|
30
|
+
|
31
|
+
@property
|
32
|
+
def authorization(self):
|
33
|
+
pair = "%s:%s" % (self.username, self.password)
|
34
|
+
return b64encode(pair.encode("utf-8")).decode("ascii")
|
File without changes
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import attr
|
2
|
+
from jstruct import JStruct, JList, REQUIRED
|
3
|
+
from typing import Optional, List
|
4
|
+
|
5
|
+
|
6
|
+
@attr.s(auto_attribs=True)
|
7
|
+
class Contact:
|
8
|
+
fullName: str
|
9
|
+
extension: Optional[int] = None
|
10
|
+
language: Optional[str] = None
|
11
|
+
email: Optional[str] = None
|
12
|
+
department: Optional[str] = None
|
13
|
+
telephone: Optional[str] = None
|
14
|
+
|
15
|
+
|
16
|
+
@attr.s(auto_attribs=True)
|
17
|
+
class Shipment:
|
18
|
+
id: int
|
19
|
+
status: Optional[int] = None
|
20
|
+
|
21
|
+
|
22
|
+
@attr.s(auto_attribs=True)
|
23
|
+
class Sender:
|
24
|
+
city: str
|
25
|
+
provinceCode: str
|
26
|
+
postalCode: str
|
27
|
+
countryCode: str
|
28
|
+
customerName: str
|
29
|
+
|
30
|
+
streetNumber: Optional[int] = None
|
31
|
+
suite: Optional[int] = None
|
32
|
+
addressLine1: Optional[str] = None
|
33
|
+
addressLine2: Optional[str] = None
|
34
|
+
streetType: Optional[str] = None
|
35
|
+
streetName: Optional[str] = None
|
36
|
+
streetDirection: Optional[str] = None
|
37
|
+
customerNickName: Optional[str] = None
|
38
|
+
contact: Optional[Contact] = JStruct[Contact]
|
39
|
+
|
40
|
+
|
41
|
+
@attr.s(auto_attribs=True)
|
42
|
+
class Shipment:
|
43
|
+
id: Optional[int] = None
|
44
|
+
status: Optional[int] = None
|
45
|
+
|
46
|
+
|
47
|
+
@attr.s(auto_attribs=True)
|
48
|
+
class Pickup:
|
49
|
+
shipments: Optional[List[Shipment]] = JStruct[Shipment]
|
50
|
+
id: Optional[int] = None
|
51
|
+
officeClose: Optional[str] = None
|
52
|
+
date: Optional[str] = None
|
53
|
+
ready: Optional[str] = None
|
54
|
+
location: Optional[str] = None
|
55
|
+
otherLocation: Optional[str] = None
|
56
|
+
category: Optional[str] = None
|
57
|
+
sender: Optional[Sender] = JStruct[Sender]
|
58
|
+
contact: Optional[Contact] = JStruct[Contact]
|
59
|
+
|
60
|
+
|
61
|
+
@attr.s(auto_attribs=True)
|
62
|
+
class ShipmentPickupRequest:
|
63
|
+
date: str
|
64
|
+
ready: str
|
65
|
+
category: str
|
66
|
+
officeClose: str
|
67
|
+
contact: Contact = JStruct[Contact, REQUIRED]
|
68
|
+
shipments: List[Shipment] = JList[Shipment, REQUIRED]
|
69
|
+
|
70
|
+
location: Optional[str] = None
|
71
|
+
otherLocation: Optional[str] = None
|
72
|
+
|
73
|
+
|
74
|
+
@attr.s(auto_attribs=True)
|
75
|
+
class PickupRequest:
|
76
|
+
date: str
|
77
|
+
ready: str
|
78
|
+
category: str
|
79
|
+
officeClose: str
|
80
|
+
sender: Sender = JStruct[Sender, REQUIRED]
|
81
|
+
|
82
|
+
location: Optional[str] = None
|
83
|
+
otherLocation: Optional[str] = None
|
@@ -0,0 +1,126 @@
|
|
1
|
+
import attr
|
2
|
+
from jstruct import JStruct, JList, REQUIRED
|
3
|
+
from typing import Optional, List
|
4
|
+
|
5
|
+
|
6
|
+
@attr.s(auto_attribs=True)
|
7
|
+
class Appointment:
|
8
|
+
type: str
|
9
|
+
date: Optional[str] = None
|
10
|
+
time: Optional[str] = None
|
11
|
+
phone: Optional[str] = None
|
12
|
+
|
13
|
+
|
14
|
+
@attr.s(auto_attribs=True)
|
15
|
+
class Address:
|
16
|
+
postalCode: str
|
17
|
+
provinceCode: str
|
18
|
+
number: Optional[int] = None
|
19
|
+
countryCode: Optional[str] = None
|
20
|
+
name: Optional[str] = None
|
21
|
+
|
22
|
+
|
23
|
+
@attr.s(auto_attribs=True)
|
24
|
+
class Hazmat:
|
25
|
+
number: int
|
26
|
+
phone: str
|
27
|
+
|
28
|
+
|
29
|
+
@attr.s(auto_attribs=True)
|
30
|
+
class Parcel:
|
31
|
+
quantity: int
|
32
|
+
parcelType: str
|
33
|
+
|
34
|
+
id: Optional[int] = None
|
35
|
+
weight: Optional[int] = None
|
36
|
+
length: Optional[int] = None
|
37
|
+
depth: Optional[int] = None
|
38
|
+
width: Optional[int] = None
|
39
|
+
note: Optional[str] = None
|
40
|
+
status: Optional[int] = None
|
41
|
+
FCA_Class: Optional[str] = None
|
42
|
+
hazmat: Optional[Hazmat] = JStruct[Hazmat]
|
43
|
+
requestReturnLabel: Optional[bool] = None
|
44
|
+
returnWaybill: Optional[str] = None
|
45
|
+
|
46
|
+
|
47
|
+
@attr.s(auto_attribs=True)
|
48
|
+
class PromoCode:
|
49
|
+
code: Optional[str] = None
|
50
|
+
|
51
|
+
|
52
|
+
@attr.s(auto_attribs=True)
|
53
|
+
class Surcharge:
|
54
|
+
type: str
|
55
|
+
id: Optional[int] = None
|
56
|
+
value: Optional[str] = None
|
57
|
+
name: Optional[str] = None
|
58
|
+
amount: Optional[int] = None
|
59
|
+
|
60
|
+
|
61
|
+
@attr.s(auto_attribs=True)
|
62
|
+
class RateRequest:
|
63
|
+
category: str
|
64
|
+
paymentType: str
|
65
|
+
deliveryType: str
|
66
|
+
unitOfMeasurement: str
|
67
|
+
sender: Address = JStruct[Address, REQUIRED]
|
68
|
+
consignee: Address = JStruct[Address, REQUIRED]
|
69
|
+
parcels: List[Parcel] = JList[Parcel, REQUIRED]
|
70
|
+
|
71
|
+
billing: Optional[int] = None
|
72
|
+
promoCodes: Optional[List[PromoCode]] = JList[PromoCode]
|
73
|
+
surcharges: Optional[List[Surcharge]] = JList[Surcharge]
|
74
|
+
appointment: Optional[Appointment] = JStruct[Appointment]
|
75
|
+
|
76
|
+
|
77
|
+
@attr.s(auto_attribs=True)
|
78
|
+
class TaxesDetail:
|
79
|
+
type: Optional[str] = None
|
80
|
+
amount: Optional[str] = None
|
81
|
+
name: Optional[str] = None
|
82
|
+
|
83
|
+
|
84
|
+
@attr.s(auto_attribs=True)
|
85
|
+
class Rate:
|
86
|
+
grossAmount: Optional[int] = None
|
87
|
+
discountAmount: Optional[int] = None
|
88
|
+
otherCharge: Optional[int] = None
|
89
|
+
fuelChargePercentage: Optional[int] = None
|
90
|
+
accountType: Optional[str] = None
|
91
|
+
rateType: Optional[str] = None
|
92
|
+
cubicWeight: Optional[float] = None
|
93
|
+
basicCharge: Optional[float] = None
|
94
|
+
weightCharge: Optional[float] = None
|
95
|
+
surcharges: List[Surcharge] = JList[Surcharge]
|
96
|
+
subTotal: Optional[float] = None
|
97
|
+
unitOfMeasurement: Optional[str] = None
|
98
|
+
taxesDetails: List[TaxesDetail] = JList[TaxesDetail]
|
99
|
+
taxes: Optional[float] = None
|
100
|
+
fuelCharge: Optional[float] = None
|
101
|
+
zoneCharge: Optional[float] = None
|
102
|
+
total: Optional[float] = None
|
103
|
+
|
104
|
+
|
105
|
+
@attr.s(auto_attribs=True)
|
106
|
+
class Reference:
|
107
|
+
code: Optional[int] = None
|
108
|
+
type: Optional[str] = None
|
109
|
+
|
110
|
+
|
111
|
+
@attr.s(auto_attribs=True)
|
112
|
+
class RateResponse:
|
113
|
+
delay: Optional[int] = None
|
114
|
+
terminalLimit: Optional[int] = None
|
115
|
+
singleShipmentCost: Optional[int] = None
|
116
|
+
quantity: Optional[int] = None
|
117
|
+
rates: List[Rate] = JList[Rate]
|
118
|
+
references: List[Reference] = JList[Reference]
|
119
|
+
unitOfMeasurement: Optional[str] = None
|
120
|
+
parcelType: Optional[str] = None
|
121
|
+
weight: Optional[str] = None
|
122
|
+
postalCodeDelivery: Optional[str] = None
|
123
|
+
postalCodePickup: Optional[str] = None
|
124
|
+
creator: Optional[str] = None
|
125
|
+
date: Optional[str] = None
|
126
|
+
warning: Optional[str] = None
|