karrio-usps 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/usps/__init__.py +3 -0
- karrio/mappers/usps/mapper.py +94 -0
- karrio/mappers/usps/proxy.py +155 -0
- karrio/mappers/usps/settings.py +26 -0
- karrio/plugins/usps/__init__.py +24 -0
- karrio/providers/usps/__init__.py +26 -0
- karrio/providers/usps/error.py +56 -0
- karrio/providers/usps/manifest.py +100 -0
- karrio/providers/usps/pickup/__init__.py +4 -0
- karrio/providers/usps/pickup/cancel.py +40 -0
- karrio/providers/usps/pickup/create.py +102 -0
- karrio/providers/usps/pickup/update.py +109 -0
- karrio/providers/usps/rate.py +204 -0
- karrio/providers/usps/shipment/__init__.py +9 -0
- karrio/providers/usps/shipment/cancel.py +53 -0
- karrio/providers/usps/shipment/create.py +279 -0
- karrio/providers/usps/tracking.py +112 -0
- karrio/providers/usps/units.py +303 -0
- karrio/providers/usps/utils.py +320 -0
- karrio/schemas/usps/__init__.py +0 -0
- karrio/schemas/usps/error_response.py +31 -0
- karrio/schemas/usps/label_request.py +142 -0
- karrio/schemas/usps/label_response.py +84 -0
- karrio/schemas/usps/pickup_request.py +49 -0
- karrio/schemas/usps/pickup_response.py +58 -0
- karrio/schemas/usps/pickup_update_request.py +55 -0
- karrio/schemas/usps/pickup_update_response.py +58 -0
- karrio/schemas/usps/rate_request.py +38 -0
- karrio/schemas/usps/rate_response.py +89 -0
- karrio/schemas/usps/scan_form_request.py +36 -0
- karrio/schemas/usps/scan_form_response.py +46 -0
- karrio/schemas/usps/tracking_response.py +113 -0
- karrio_usps-2025.5rc1.dist-info/METADATA +45 -0
- karrio_usps-2025.5rc1.dist-info/RECORD +37 -0
- karrio_usps-2025.5rc1.dist-info/WHEEL +5 -0
- karrio_usps-2025.5rc1.dist-info/entry_points.txt +2 -0
- karrio_usps-2025.5rc1.dist-info/top_level.txt +3 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
"""Karrio USPS update pickup implementation."""
|
2
|
+
|
3
|
+
import karrio.schemas.usps.pickup_update_request as usps
|
4
|
+
import karrio.schemas.usps.pickup_update_response as pickup
|
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.usps.error as error
|
11
|
+
import karrio.providers.usps.utils as provider_utils
|
12
|
+
import karrio.providers.usps.units as provider_units
|
13
|
+
|
14
|
+
|
15
|
+
def parse_pickup_update_response(
|
16
|
+
_response: lib.Deserializable[dict],
|
17
|
+
settings: provider_utils.Settings,
|
18
|
+
) -> typing.Tuple[typing.List[models.PickupDetails], typing.List[models.Message]]:
|
19
|
+
response = _response.deserialize()
|
20
|
+
|
21
|
+
messages = error.parse_error_response(response, settings)
|
22
|
+
pickup = (
|
23
|
+
_extract_details(response, settings)
|
24
|
+
if "confirmationNumber" in response
|
25
|
+
else None
|
26
|
+
)
|
27
|
+
|
28
|
+
return pickup, messages
|
29
|
+
|
30
|
+
|
31
|
+
def _extract_details(
|
32
|
+
data: dict,
|
33
|
+
settings: provider_utils.Settings,
|
34
|
+
) -> models.PickupDetails:
|
35
|
+
details = lib.to_object(pickup.PickupUpdateResponseType, data)
|
36
|
+
|
37
|
+
return models.PickupDetails(
|
38
|
+
carrier_id=settings.carrier_id,
|
39
|
+
carrier_name=settings.carrier_name,
|
40
|
+
confirmation_number=details.confirmationNumber,
|
41
|
+
pickup_date=lib.fdate(details.pickupDate),
|
42
|
+
)
|
43
|
+
|
44
|
+
|
45
|
+
def pickup_update_request(
|
46
|
+
payload: models.PickupUpdateRequest,
|
47
|
+
settings: provider_utils.Settings,
|
48
|
+
) -> lib.Serializable:
|
49
|
+
address = lib.to_address(payload.address)
|
50
|
+
packages = lib.to_packages(payload.parcels)
|
51
|
+
options = lib.units.Options(
|
52
|
+
payload.options,
|
53
|
+
option_type=lib.units.create_enum(
|
54
|
+
"PickupOptions",
|
55
|
+
# fmt: off
|
56
|
+
{
|
57
|
+
"usps_package_type": lib.OptionEnum("usps_package_type"),
|
58
|
+
},
|
59
|
+
# fmt: on
|
60
|
+
),
|
61
|
+
)
|
62
|
+
|
63
|
+
# map data to convert karrio model to usps specific type
|
64
|
+
request = usps.PickupUpdateRequestType(
|
65
|
+
pickupDate=lib.fdate(payload.pickup_date),
|
66
|
+
carrierPickupRequest=usps.CarrierPickupRequestType(
|
67
|
+
pickupDate=lib.fdate(payload.pickup_date),
|
68
|
+
pickupAddress=usps.PickupAddressType(
|
69
|
+
firstName=address.person_name,
|
70
|
+
lastName=None,
|
71
|
+
firm=address.company_name,
|
72
|
+
address=usps.AddressType(
|
73
|
+
streetAddress=address.address_line1,
|
74
|
+
secondaryAddress=address.address_line2,
|
75
|
+
city=address.city,
|
76
|
+
state=address.state,
|
77
|
+
ZIPCode=lib.to_zip5(address.postal_code),
|
78
|
+
ZIPPlus4=lib.to_zip4(address.postal_code) or "",
|
79
|
+
urbanization=None,
|
80
|
+
),
|
81
|
+
contact=[
|
82
|
+
usps.ContactType(email=address.email)
|
83
|
+
for _ in [address.email]
|
84
|
+
if _ is not None
|
85
|
+
],
|
86
|
+
),
|
87
|
+
packages=[
|
88
|
+
usps.PackageType(
|
89
|
+
packageType=options.usps_package_type.state or "OTHER",
|
90
|
+
packageCount=len(packages),
|
91
|
+
)
|
92
|
+
],
|
93
|
+
estimatedWeight=packages.weight.LB,
|
94
|
+
pickupLocation=lib.identity(
|
95
|
+
usps.PickupLocationType(
|
96
|
+
packageLocation=payload.package_location,
|
97
|
+
specialInstructions=payload.instruction,
|
98
|
+
)
|
99
|
+
if any([payload.package_location, payload.instruction])
|
100
|
+
else None
|
101
|
+
),
|
102
|
+
),
|
103
|
+
)
|
104
|
+
|
105
|
+
return lib.Serializable(
|
106
|
+
request,
|
107
|
+
lib.to_dict,
|
108
|
+
dict(confirmationNumber=payload.confirmation_number),
|
109
|
+
)
|
@@ -0,0 +1,204 @@
|
|
1
|
+
"""Karrio USPS rating API implementation."""
|
2
|
+
|
3
|
+
import karrio.schemas.usps.rate_request as usps
|
4
|
+
import karrio.schemas.usps.rate_response as rating
|
5
|
+
|
6
|
+
import time
|
7
|
+
import typing
|
8
|
+
import karrio.lib as lib
|
9
|
+
import karrio.core.units as units
|
10
|
+
import karrio.core.models as models
|
11
|
+
import karrio.core.errors as errors
|
12
|
+
import karrio.providers.usps.error as error
|
13
|
+
import karrio.providers.usps.utils as provider_utils
|
14
|
+
import karrio.providers.usps.units as provider_units
|
15
|
+
|
16
|
+
|
17
|
+
def parse_rate_response(
|
18
|
+
_response: lib.Deserializable[dict],
|
19
|
+
settings: provider_utils.Settings,
|
20
|
+
) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
|
21
|
+
responses = _response.deserialize()
|
22
|
+
|
23
|
+
messages = error.parse_error_response(responses, settings)
|
24
|
+
rates = lib.to_multi_piece_rates(
|
25
|
+
[
|
26
|
+
(
|
27
|
+
f"{_}",
|
28
|
+
[
|
29
|
+
_ for _ in [
|
30
|
+
_extract_details(dict(rate=rate, rateOption=rateOption), settings, _response.ctx)
|
31
|
+
for pricingOption in response.get("pricingOptions", [])
|
32
|
+
for shippingOption in pricingOption.get("shippingOptions", [])
|
33
|
+
for rateOption in shippingOption.get("rateOptions", [])
|
34
|
+
for rate in rateOption.get("rates", [])
|
35
|
+
]
|
36
|
+
if _ is not None
|
37
|
+
],
|
38
|
+
)
|
39
|
+
for _, response in enumerate(responses, start=1)
|
40
|
+
]
|
41
|
+
)
|
42
|
+
|
43
|
+
return rates, messages
|
44
|
+
|
45
|
+
|
46
|
+
def _extract_details(
|
47
|
+
data: dict,
|
48
|
+
settings: provider_utils.Settings,
|
49
|
+
ctx: dict = dict(),
|
50
|
+
) -> typing.Optional[models.RateDetails]:
|
51
|
+
currency = "USD"
|
52
|
+
machinable_piece = data.get("machinable_piece")
|
53
|
+
rate = lib.to_object(rating.RateType, data['rate'])
|
54
|
+
rateOption = lib.to_object(rating.RateOptionType, data['rateOption'])
|
55
|
+
product_name = rate.productName or rate.description or rate.mailClass
|
56
|
+
service_code = provider_units.ShippingService.to_product_code(product_name)
|
57
|
+
service_name = provider_units.ShippingService.to_product_name(service_code)
|
58
|
+
|
59
|
+
if machinable_piece is True and "machinable" not in service_code:
|
60
|
+
return None
|
61
|
+
if machinable_piece is False and "machinable" in service_code:
|
62
|
+
return None
|
63
|
+
|
64
|
+
transit_days = lib.to_int(next(iter(rateOption.commitment.name.split(" "))))
|
65
|
+
estimated_delivery = rateOption.commitment.scheduleDeliveryDate
|
66
|
+
charges = [
|
67
|
+
("Base Price", lib.to_money(rateOption.totalBasePrice)),
|
68
|
+
*[(extra.name, lib.to_money(extra.price)) for extra in rateOption.extraServices],
|
69
|
+
]
|
70
|
+
|
71
|
+
return models.RateDetails(
|
72
|
+
carrier_id=settings.carrier_id,
|
73
|
+
carrier_name=settings.carrier_name,
|
74
|
+
service=service_code,
|
75
|
+
total_charge=lib.to_money(rateOption.totalPrice),
|
76
|
+
currency=currency,
|
77
|
+
extra_charges=[
|
78
|
+
models.ChargeDetails(
|
79
|
+
currency=currency,
|
80
|
+
amount=amount,
|
81
|
+
name=name,
|
82
|
+
)
|
83
|
+
for name, amount in charges
|
84
|
+
],
|
85
|
+
estimated_delivery=estimated_delivery,
|
86
|
+
transit_days=transit_days,
|
87
|
+
meta=dict(
|
88
|
+
service_name=service_name,
|
89
|
+
usps_mail_class=rate.mailClass,
|
90
|
+
usps_guaranteed_delivery=lib.failsafe(lambda: rateOption.commitment.guaranteedDelivery),
|
91
|
+
usps_processing_category=lib.failsafe(lambda: rate.processingCategory),
|
92
|
+
usps_dimensional_weight=lib.failsafe(lambda: rate.dimensionalWeight),
|
93
|
+
usps_rate_indicator=lib.failsafe(lambda: rate.rateIndicator),
|
94
|
+
usps_price_type=lib.failsafe(lambda: rate.priceType),
|
95
|
+
usps_rate_sku=lib.failsafe(lambda: rate.SKU),
|
96
|
+
usps_zone=lib.failsafe(lambda: rate.zone),
|
97
|
+
rate_zone=lib.failsafe(lambda: rate.zone),
|
98
|
+
usps_extra_services=lib.failsafe(
|
99
|
+
lambda: [lib.to_int(_.extraService) for _ in rateOption.extraServices]
|
100
|
+
),
|
101
|
+
),
|
102
|
+
)
|
103
|
+
|
104
|
+
|
105
|
+
def rate_request(
|
106
|
+
payload: models.RateRequest,
|
107
|
+
settings: provider_utils.Settings,
|
108
|
+
) -> lib.Serializable:
|
109
|
+
shipper = lib.to_address(payload.shipper)
|
110
|
+
recipient = lib.to_address(payload.recipient)
|
111
|
+
|
112
|
+
if (
|
113
|
+
shipper.country_code is not None
|
114
|
+
and shipper.country_code != units.Country.US.name
|
115
|
+
):
|
116
|
+
raise errors.OriginNotServicedError(shipper.country_code)
|
117
|
+
|
118
|
+
if (
|
119
|
+
recipient.country_code is not None
|
120
|
+
and recipient.country_code != units.Country.US.name
|
121
|
+
):
|
122
|
+
raise errors.DestinationNotServicedError(recipient.country_code)
|
123
|
+
|
124
|
+
services = lib.to_services(
|
125
|
+
[provider_units.ShippingService.to_mail_class(_).name_or_key for _ in payload.services],
|
126
|
+
provider_units.ShippingService
|
127
|
+
)
|
128
|
+
options = lib.to_shipping_options(
|
129
|
+
payload.options,
|
130
|
+
initializer=provider_units.shipping_options_initializer,
|
131
|
+
)
|
132
|
+
packages = lib.to_packages(
|
133
|
+
payload.parcels,
|
134
|
+
options=options,
|
135
|
+
package_option_type=provider_units.ShippingOption,
|
136
|
+
shipping_options_initializer=provider_units.shipping_options_initializer,
|
137
|
+
)
|
138
|
+
price_type = lib.identity(
|
139
|
+
options.usps_price_type.state
|
140
|
+
or settings.connection_config.price_type.state
|
141
|
+
or "RETAIL"
|
142
|
+
)
|
143
|
+
|
144
|
+
package_mail_class = lambda package: lib.identity(
|
145
|
+
provider_units.ShippingService.to_mail_class(package.options.usps_mail_class.state).value
|
146
|
+
if package.options.usps_mail_class.state
|
147
|
+
else getattr(services.first, "value", "ALL")
|
148
|
+
)
|
149
|
+
package_options = lambda package: lib.identity(
|
150
|
+
package.options
|
151
|
+
if package_mail_class(package) not in provider_units.INCOMPATIBLE_SERVICES
|
152
|
+
else {}
|
153
|
+
)
|
154
|
+
|
155
|
+
# map data to convert karrio model to usps specific type
|
156
|
+
request = [
|
157
|
+
usps.RateRequestType(
|
158
|
+
pricingOptions=[
|
159
|
+
usps.PricingOptionType(
|
160
|
+
priceType=price_type,
|
161
|
+
paymentAccount=usps.PaymentAccountType(
|
162
|
+
accountType=settings.account_type,
|
163
|
+
accountNumber=settings.account_number,
|
164
|
+
),
|
165
|
+
)
|
166
|
+
],
|
167
|
+
originZIPCode=shipper.postal_code,
|
168
|
+
destinationZIPCode=recipient.postal_code,
|
169
|
+
destinationEntryFacilityType=lib.identity(
|
170
|
+
options.usps_destination_entry_facility_type.state
|
171
|
+
or "NONE"
|
172
|
+
),
|
173
|
+
packageDescription=usps.PackageDescriptionType(
|
174
|
+
weight=package.weight.LB,
|
175
|
+
length=package.length.IN,
|
176
|
+
height=package.height.IN,
|
177
|
+
width=package.width.IN,
|
178
|
+
girth=lib.identity(
|
179
|
+
package.girth.value if package.packaging_type == "tube" else None
|
180
|
+
),
|
181
|
+
mailClass=package_mail_class(package),
|
182
|
+
extraServices=[
|
183
|
+
lib.to_int(_.code)
|
184
|
+
for __, _ in package_options(package).items()
|
185
|
+
if __ not in provider_units.CUSTOM_OPTIONS
|
186
|
+
],
|
187
|
+
packageValue=package.options.package_value.state,
|
188
|
+
mailingDate=lib.fdate(
|
189
|
+
package.options.shipment_date.state or time.strftime("%Y-%m-%d")
|
190
|
+
),
|
191
|
+
),
|
192
|
+
shippingFilter=package.options.usps_shipping_filter.state,
|
193
|
+
)
|
194
|
+
for package in packages
|
195
|
+
]
|
196
|
+
|
197
|
+
return lib.Serializable(
|
198
|
+
request,
|
199
|
+
lib.to_dict,
|
200
|
+
dict(
|
201
|
+
price_type=price_type,
|
202
|
+
machinable_piece=options.usps_machinable_piece.state,
|
203
|
+
),
|
204
|
+
)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import typing
|
2
|
+
import karrio.lib as lib
|
3
|
+
import karrio.core.models as models
|
4
|
+
import karrio.providers.usps.error as error
|
5
|
+
import karrio.providers.usps.utils as provider_utils
|
6
|
+
import karrio.providers.usps.units as provider_units
|
7
|
+
|
8
|
+
|
9
|
+
def parse_shipment_cancel_response(
|
10
|
+
_response: lib.Deserializable[typing.List[typing.Tuple[str, dict]]],
|
11
|
+
settings: provider_utils.Settings,
|
12
|
+
) -> typing.Tuple[models.ConfirmationDetails, typing.List[models.Message]]:
|
13
|
+
responses = _response.deserialize()
|
14
|
+
messages: typing.List[models.Message] = sum(
|
15
|
+
[
|
16
|
+
error.parse_error_response(response, settings, tracking_number=_)
|
17
|
+
for _, response in responses
|
18
|
+
],
|
19
|
+
start=[],
|
20
|
+
)
|
21
|
+
success = all([_.get("status") == "CANCELED" for __, _ in responses])
|
22
|
+
|
23
|
+
confirmation = (
|
24
|
+
models.ConfirmationDetails(
|
25
|
+
carrier_id=settings.carrier_id,
|
26
|
+
carrier_name=settings.carrier_name,
|
27
|
+
operation="Cancel Shipment",
|
28
|
+
success=success,
|
29
|
+
)
|
30
|
+
if success
|
31
|
+
else None
|
32
|
+
)
|
33
|
+
|
34
|
+
return confirmation, messages
|
35
|
+
|
36
|
+
|
37
|
+
def shipment_cancel_request(
|
38
|
+
payload: models.ShipmentCancelRequest,
|
39
|
+
settings: provider_utils.Settings,
|
40
|
+
) -> lib.Serializable:
|
41
|
+
|
42
|
+
# map data to convert karrio model to usps specific type
|
43
|
+
request = [
|
44
|
+
dict(trackingNumber=_)
|
45
|
+
for _ in set(
|
46
|
+
[
|
47
|
+
payload.shipment_identifier,
|
48
|
+
*((payload.options or {}).get("shipment_identifiers") or []),
|
49
|
+
]
|
50
|
+
)
|
51
|
+
]
|
52
|
+
|
53
|
+
return lib.Serializable(request, lib.to_dict)
|
@@ -0,0 +1,279 @@
|
|
1
|
+
"""Karrio USPS create label implementation."""
|
2
|
+
|
3
|
+
import karrio.schemas.usps.label_request as usps
|
4
|
+
import karrio.schemas.usps.label_response as shipping
|
5
|
+
|
6
|
+
import time
|
7
|
+
import typing
|
8
|
+
import karrio.lib as lib
|
9
|
+
import karrio.core.units as units
|
10
|
+
import karrio.core.models as models
|
11
|
+
import karrio.core.errors as errors
|
12
|
+
import karrio.providers.usps.error as error
|
13
|
+
import karrio.providers.usps.utils as provider_utils
|
14
|
+
import karrio.providers.usps.units as provider_units
|
15
|
+
|
16
|
+
|
17
|
+
def parse_shipment_response(
|
18
|
+
_response: lib.Deserializable[typing.List[dict]],
|
19
|
+
settings: provider_utils.Settings,
|
20
|
+
) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
|
21
|
+
responses = _response.deserialize()
|
22
|
+
shipment = lib.to_multi_piece_shipment(
|
23
|
+
[
|
24
|
+
(
|
25
|
+
f"{_}",
|
26
|
+
_extract_details(response, settings, _response.ctx),
|
27
|
+
)
|
28
|
+
for _, response in enumerate(responses, start=1)
|
29
|
+
if response.get("error") is None
|
30
|
+
and response.get("labelMetadata") is not None
|
31
|
+
]
|
32
|
+
)
|
33
|
+
messages: typing.List[models.Message] = sum(
|
34
|
+
[error.parse_error_response(response, settings) for response in responses],
|
35
|
+
start=[],
|
36
|
+
)
|
37
|
+
|
38
|
+
return shipment, messages
|
39
|
+
|
40
|
+
|
41
|
+
def _extract_details(
|
42
|
+
data: dict,
|
43
|
+
settings: provider_utils.Settings,
|
44
|
+
ctx: dict = None,
|
45
|
+
) -> models.ShipmentDetails:
|
46
|
+
details = lib.to_object(shipping.LabelResponseType, data)
|
47
|
+
label = details.labelImage
|
48
|
+
invoice = details.receiptImage
|
49
|
+
label_type = ctx.get("label_type", "PDF")
|
50
|
+
|
51
|
+
return models.ShipmentDetails(
|
52
|
+
carrier_id=settings.carrier_id,
|
53
|
+
carrier_name=settings.carrier_name,
|
54
|
+
tracking_number=details.labelMetadata.trackingNumber,
|
55
|
+
shipment_identifier=details.labelMetadata.trackingNumber,
|
56
|
+
label_type=label_type,
|
57
|
+
docs=models.Documents(label=label, invoice=invoice),
|
58
|
+
meta=dict(
|
59
|
+
SKU=details.labelMetadata.SKU,
|
60
|
+
postage=details.labelMetadata.postage,
|
61
|
+
routingInformation=details.labelMetadata.routingInformation,
|
62
|
+
labelBrokerID=details.labelMetadata.labelBrokerID,
|
63
|
+
),
|
64
|
+
)
|
65
|
+
|
66
|
+
|
67
|
+
def shipment_request(
|
68
|
+
payload: models.ShipmentRequest,
|
69
|
+
settings: provider_utils.Settings,
|
70
|
+
) -> lib.Serializable:
|
71
|
+
shipper = lib.to_address(payload.shipper)
|
72
|
+
recipient = lib.to_address(payload.recipient)
|
73
|
+
|
74
|
+
if (
|
75
|
+
shipper.country_code is not None
|
76
|
+
and shipper.country_code != units.Country.US.name
|
77
|
+
):
|
78
|
+
raise errors.OriginNotServicedError(shipper.country_code)
|
79
|
+
|
80
|
+
if (
|
81
|
+
recipient.country_code is not None
|
82
|
+
and recipient.country_code != units.Country.US.name
|
83
|
+
):
|
84
|
+
raise errors.DestinationNotServicedError(recipient.country_code)
|
85
|
+
|
86
|
+
return_address = lib.to_address(payload.return_address)
|
87
|
+
mail_class = lib.identity(
|
88
|
+
provider_units.ShippingService.to_mail_class(payload.service).value
|
89
|
+
or payload.service
|
90
|
+
)
|
91
|
+
options = lib.to_shipping_options(
|
92
|
+
payload.options,
|
93
|
+
initializer=provider_units.shipping_options_initializer,
|
94
|
+
)
|
95
|
+
packages = lib.to_packages(
|
96
|
+
payload.parcels,
|
97
|
+
options=options,
|
98
|
+
package_option_type=provider_units.ShippingOption,
|
99
|
+
shipping_options_initializer=provider_units.shipping_options_initializer,
|
100
|
+
)
|
101
|
+
pickup_location = lib.to_address(options.hold_for_pickup_address.state)
|
102
|
+
label_type = provider_units.LabelType.map(payload.label_type).value or "PDF"
|
103
|
+
|
104
|
+
package_options = lambda package: lib.identity(
|
105
|
+
package.options
|
106
|
+
if mail_class not in provider_units.INCOMPATIBLE_SERVICES
|
107
|
+
else {}
|
108
|
+
)
|
109
|
+
|
110
|
+
# map data to convert karrio model to usps specific type
|
111
|
+
request = [
|
112
|
+
usps.LabelRequestType(
|
113
|
+
imageInfo=usps.ImageInfoType(
|
114
|
+
imageType=label_type,
|
115
|
+
labelType="4X6LABEL",
|
116
|
+
# shipInfo=None,
|
117
|
+
receiptOption="NONE",
|
118
|
+
suppressPostage=None,
|
119
|
+
suppressMailDate=None,
|
120
|
+
returnLabel=None,
|
121
|
+
),
|
122
|
+
toAddress=usps.AddressType(
|
123
|
+
streetAddress=recipient.address_line1,
|
124
|
+
secondaryAddress=recipient.address_line2,
|
125
|
+
city=recipient.city,
|
126
|
+
state=recipient.state_code,
|
127
|
+
ZIPCode=lib.to_zip5(recipient.postal_code) or "",
|
128
|
+
ZIPPlus4=lib.to_zip4(recipient.postal_code) or "",
|
129
|
+
urbanization=None,
|
130
|
+
firstName=recipient.first_name,
|
131
|
+
lastName=recipient.last_name,
|
132
|
+
firm=recipient.company_name,
|
133
|
+
phone=provider_utils.parse_phone_number(recipient.phone_number),
|
134
|
+
email=recipient.email,
|
135
|
+
ignoreBadAddress=True,
|
136
|
+
platformUserId=None,
|
137
|
+
parcelLockerDelivery=None,
|
138
|
+
holdForPickup=package.options.usps_hold_for_pickup.state,
|
139
|
+
facilityId=package.options.usps_facility_id.state,
|
140
|
+
),
|
141
|
+
fromAddress=usps.AddressType(
|
142
|
+
streetAddress=shipper.address_line1,
|
143
|
+
secondaryAddress=shipper.address_line2,
|
144
|
+
city=shipper.city,
|
145
|
+
state=shipper.state_code,
|
146
|
+
ZIPCode=lib.to_zip5(shipper.postal_code) or "",
|
147
|
+
ZIPPlus4=lib.to_zip4(shipper.postal_code) or "",
|
148
|
+
urbanization=None,
|
149
|
+
firstName=shipper.first_name,
|
150
|
+
lastName=shipper.last_name,
|
151
|
+
firm=shipper.company_name,
|
152
|
+
phone=provider_utils.parse_phone_number(shipper.phone_number),
|
153
|
+
email=shipper.email,
|
154
|
+
ignoreBadAddress=True,
|
155
|
+
platformUserId=None,
|
156
|
+
parcelLockerDelivery=None,
|
157
|
+
holdForPickup=None,
|
158
|
+
facilityId=None,
|
159
|
+
),
|
160
|
+
senderAddress=usps.AddressType(
|
161
|
+
streetAddress=shipper.address_line1,
|
162
|
+
secondaryAddress=shipper.address_line2r,
|
163
|
+
city=shipper.city,
|
164
|
+
state=shipper.state_code,
|
165
|
+
ZIPCode=lib.to_zip5(shipper.postal_code) or "",
|
166
|
+
ZIPPlus4=lib.to_zip4(shipper.postal_code) or "",
|
167
|
+
urbanization=None,
|
168
|
+
firstName=shipper.first_name,
|
169
|
+
lastName=shipper.last_name,
|
170
|
+
firm=shipper.company_name,
|
171
|
+
phone=provider_utils.parse_phone_number(shipper.phone_number),
|
172
|
+
email=shipper.email,
|
173
|
+
ignoreBadAddress=True,
|
174
|
+
platformUserId=None,
|
175
|
+
parcelLockerDelivery=None,
|
176
|
+
holdForPickup=None,
|
177
|
+
facilityId=None,
|
178
|
+
),
|
179
|
+
returnAddress=lib.identity(
|
180
|
+
usps.AddressType(
|
181
|
+
streetAddress=return_address.address_line1,
|
182
|
+
secondaryAddress=return_address.address_line2r,
|
183
|
+
city=return_address.city,
|
184
|
+
state=return_address.state_code,
|
185
|
+
ZIPCode=lib.to_zip5(return_address.postal_code) or "",
|
186
|
+
ZIPPlus4=lib.to_zip4(return_address.postal_code) or "",
|
187
|
+
urbanization=None,
|
188
|
+
firstName=return_address.first_name,
|
189
|
+
lastName=return_address.last_name,
|
190
|
+
firm=return_address.company_name,
|
191
|
+
phone=provider_utils.parse_phone_number(return_address.phone_number),
|
192
|
+
email=return_address.email,
|
193
|
+
ignoreBadAddress=True,
|
194
|
+
platformUserId=None,
|
195
|
+
parcelLockerDelivery=None,
|
196
|
+
holdForPickup=None,
|
197
|
+
facilityId=None,
|
198
|
+
)
|
199
|
+
if payload.return_address is not None
|
200
|
+
else None
|
201
|
+
),
|
202
|
+
packageDescription=usps.PackageDescriptionType(
|
203
|
+
weightUOM="lb",
|
204
|
+
weight=package.weight.LB,
|
205
|
+
dimensionsUOM="in",
|
206
|
+
length=package.length.IN,
|
207
|
+
height=package.height.IN,
|
208
|
+
width=package.width.IN,
|
209
|
+
girth=package.girth.value,
|
210
|
+
mailClass=mail_class,
|
211
|
+
rateIndicator=package.options.usps_rate_indicator.state or "DR",
|
212
|
+
processingCategory=lib.identity(
|
213
|
+
package.options.usps_processing_category.state or "NON_MACHINABLE"
|
214
|
+
),
|
215
|
+
destinationEntryFacilityType=lib.identity(
|
216
|
+
package.options.usps_destination_facility_type.state or "NONE"
|
217
|
+
),
|
218
|
+
destinationEntryFacilityAddress=lib.identity(
|
219
|
+
usps.DestinationEntryFacilityAddressType(
|
220
|
+
streetAddress=pickup_location.address_line1,
|
221
|
+
secondaryAddress=pickup_location.address_line2r,
|
222
|
+
city=pickup_location.city,
|
223
|
+
state=pickup_location.state_code,
|
224
|
+
ZIPCode=lib.to_zip5(pickup_location.postal_code) or "",
|
225
|
+
ZIPPlus4=lib.to_zip4(pickup_location.postal_code) or "",
|
226
|
+
urbanization=None,
|
227
|
+
)
|
228
|
+
if package.options.hold_for_pickup_address.state is not None
|
229
|
+
else None
|
230
|
+
),
|
231
|
+
packageOptions=lib.identity(
|
232
|
+
usps.PackageOptionsType(
|
233
|
+
packageValue=lib.identity(
|
234
|
+
package.total_value
|
235
|
+
or package.options.declared_value.state
|
236
|
+
or 1.0
|
237
|
+
),
|
238
|
+
nonDeliveryOption=None,
|
239
|
+
redirectAddress=None,
|
240
|
+
contentType=None,
|
241
|
+
generateGXEvent=None,
|
242
|
+
containers=[],
|
243
|
+
ancillaryServiceEndorsements=None,
|
244
|
+
originalPackage=None,
|
245
|
+
)
|
246
|
+
if (package.total_value or package.options.declared_value.state)
|
247
|
+
else None
|
248
|
+
),
|
249
|
+
customerReference=[
|
250
|
+
usps.CustomerReferenceType(
|
251
|
+
referenceNumber=reference,
|
252
|
+
printReferenceNumber=True,
|
253
|
+
)
|
254
|
+
for reference in [payload.reference]
|
255
|
+
if reference is not None
|
256
|
+
],
|
257
|
+
extraServices=lib.identity(
|
258
|
+
package.options.usps_extra_services.state
|
259
|
+
or [
|
260
|
+
lib.to_int(_.code)
|
261
|
+
for __, _ in package_options(package).items()
|
262
|
+
if _.name not in provider_units.CUSTOM_OPTIONS
|
263
|
+
]
|
264
|
+
),
|
265
|
+
mailingDate=lib.fdate(
|
266
|
+
package.options.shipment_date.state or time.strftime("%Y-%m-%d")
|
267
|
+
),
|
268
|
+
carrierRelease=package.options.usps_carrier_release.state,
|
269
|
+
physicalSignatureRequired=package.options.usps_physical_signature_required.state,
|
270
|
+
inductionZIPCode=lib.identity(
|
271
|
+
return_address.postal_code or shipper.postal_code
|
272
|
+
),
|
273
|
+
),
|
274
|
+
customsForm=None,
|
275
|
+
)
|
276
|
+
for package in packages
|
277
|
+
]
|
278
|
+
|
279
|
+
return lib.Serializable(request, lib.to_dict, dict(label_type=label_type))
|