karrio 2023.3.4__py3-none-any.whl → 2023.4.4__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/api/interface.py +44 -1
- karrio/core/metadata.py +2 -1
- karrio/core/models.py +5 -11
- karrio/core/settings.py +19 -10
- karrio/core/units.py +106 -27
- karrio/core/utils/helpers.py +32 -6
- karrio/core/utils/serializable.py +10 -10
- karrio/lib.py +27 -2
- karrio/references.py +6 -0
- karrio/universal/mappers/rating_proxy.py +3 -5
- karrio/universal/mappers/shipping_proxy.py +1 -1
- karrio/universal/providers/rating/rate.py +7 -6
- karrio/universal/providers/shipping/shipment.py +4 -3
- {karrio-2023.3.4.dist-info → karrio-2023.4.4.dist-info}/METADATA +1 -1
- {karrio-2023.3.4.dist-info → karrio-2023.4.4.dist-info}/RECORD +17 -17
- {karrio-2023.3.4.dist-info → karrio-2023.4.4.dist-info}/WHEEL +0 -0
- {karrio-2023.3.4.dist-info → karrio-2023.4.4.dist-info}/top_level.txt +0 -0
karrio/api/interface.py
CHANGED
@@ -81,6 +81,27 @@ def check_operation(gateway: gateway.Gateway, request: str, **kwargs):
|
|
81
81
|
return True, None
|
82
82
|
|
83
83
|
|
84
|
+
def filter_rates(rates: typing.List[models.RateDetails], gateway: gateway.Gateway):
|
85
|
+
"""Filter rates by gateway
|
86
|
+
|
87
|
+
Args:
|
88
|
+
rates (List[models.Rate]): the rates to filter
|
89
|
+
gateways (List[gateway.Gateway]): the gateways to filter by
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
List[models.Rate]: the filtered rates
|
93
|
+
"""
|
94
|
+
restricted_services = (
|
95
|
+
gateway.settings.connection_config.shipping_services.state or []
|
96
|
+
)
|
97
|
+
|
98
|
+
return [
|
99
|
+
rate
|
100
|
+
for rate in rates
|
101
|
+
if (not any(restricted_services) or rate.service in restricted_services)
|
102
|
+
]
|
103
|
+
|
104
|
+
|
84
105
|
@attr.s(auto_attribs=True)
|
85
106
|
class IDeserialize:
|
86
107
|
"""A lazy deserializer type class"""
|
@@ -290,7 +311,29 @@ class Rating:
|
|
290
311
|
|
291
312
|
def flatten(*args):
|
292
313
|
responses = [p.parse() for p in deserializable_collection]
|
293
|
-
flattened_rates = sum(
|
314
|
+
flattened_rates = sum(
|
315
|
+
(
|
316
|
+
(
|
317
|
+
(lambda gateway: filter_rates(rates, gateway))(
|
318
|
+
# find the gateway that matches the carrier_id of the rates
|
319
|
+
next(
|
320
|
+
(
|
321
|
+
g
|
322
|
+
for g in gateways
|
323
|
+
if (
|
324
|
+
g.settings.carrier_id == rates[0].carrier_id
|
325
|
+
)
|
326
|
+
)
|
327
|
+
)
|
328
|
+
)
|
329
|
+
if len(rates) > 0
|
330
|
+
else rates
|
331
|
+
)
|
332
|
+
for rates, _ in responses
|
333
|
+
if rates is not None
|
334
|
+
),
|
335
|
+
[],
|
336
|
+
)
|
294
337
|
messages = sum((m for _, m in responses), [])
|
295
338
|
return flattened_rates, messages
|
296
339
|
|
karrio/core/metadata.py
CHANGED
@@ -23,10 +23,11 @@ class Metadata:
|
|
23
23
|
Settings: Type[Settings]
|
24
24
|
|
25
25
|
# Data Units
|
26
|
-
services: Optional[Type[Enum]] = None
|
27
26
|
options: Optional[Type[Enum]] = None
|
27
|
+
services: Optional[Type[Enum]] = None
|
28
28
|
package_presets: Optional[Type[Enum]] = None
|
29
29
|
packaging_types: Optional[Type[Enum]] = None
|
30
|
+
connection_configs: Optional[Type[Enum]] = None
|
30
31
|
service_levels: Optional[List[ServiceLevel]] = None
|
31
32
|
|
32
33
|
id: Optional[str] = None
|
karrio/core/models.py
CHANGED
@@ -4,14 +4,6 @@ from typing import List, Dict, Any, Union
|
|
4
4
|
from jstruct import JList, JStruct, REQUIRED
|
5
5
|
|
6
6
|
|
7
|
-
@attr.s(auto_attribs=True)
|
8
|
-
class AddressExtra:
|
9
|
-
street_name: str = None
|
10
|
-
street_type: str = None
|
11
|
-
suburb: str = None
|
12
|
-
suite: str = None
|
13
|
-
|
14
|
-
|
15
7
|
@attr.s(auto_attribs=True)
|
16
8
|
class Address:
|
17
9
|
"""shipping party (contact and address) data type."""
|
@@ -35,8 +27,6 @@ class Address:
|
|
35
27
|
federal_tax_id: str = None
|
36
28
|
state_tax_id: str = None
|
37
29
|
|
38
|
-
extra: AddressExtra = JStruct[AddressExtra]
|
39
|
-
|
40
30
|
|
41
31
|
@attr.s(auto_attribs=True)
|
42
32
|
class Commodity:
|
@@ -304,12 +294,13 @@ class TrackingInfo:
|
|
304
294
|
shipment_service: str = None
|
305
295
|
shipment_origin_country: str = None
|
306
296
|
shipment_origin_postal_code: str = None
|
307
|
-
|
297
|
+
shipment_destination_country: str = None
|
308
298
|
shipment_destination_postal_code: str = None
|
309
299
|
shipping_date: str = None
|
310
300
|
signed_by: str = None
|
311
301
|
source: str = None
|
312
302
|
|
303
|
+
|
313
304
|
@attr.s(auto_attribs=True)
|
314
305
|
class TrackingDetails:
|
315
306
|
"""Karrio unified tracking details data type."""
|
@@ -330,6 +321,9 @@ class Documents:
|
|
330
321
|
"""Karrio unified shipment details data type."""
|
331
322
|
|
332
323
|
label: str
|
324
|
+
zpl_label: str = None
|
325
|
+
pdf_label: str = None
|
326
|
+
|
333
327
|
invoice: str = None
|
334
328
|
|
335
329
|
|
karrio/core/settings.py
CHANGED
@@ -1,26 +1,35 @@
|
|
1
1
|
"""Karrio Settings abstract class definition"""
|
2
2
|
|
3
|
+
import abc
|
3
4
|
import attr
|
4
|
-
|
5
|
-
from abc import ABC
|
5
|
+
import typing
|
6
6
|
|
7
7
|
|
8
8
|
@attr.s(auto_attribs=True)
|
9
|
-
class Settings(ABC):
|
10
|
-
"""
|
11
|
-
Unified API carrier Connection settings (Interface)
|
12
|
-
"""
|
9
|
+
class Settings(abc.ABC):
|
10
|
+
"""Unified API carrier Connection settings (Interface)"""
|
13
11
|
|
14
12
|
carrier_id: str
|
15
|
-
id: str = None
|
16
|
-
test_mode: bool = False
|
17
13
|
account_country_code: str = None
|
14
|
+
test_mode: bool = False
|
18
15
|
metadata: dict = {}
|
16
|
+
config: dict = {}
|
17
|
+
id: str = None
|
18
|
+
|
19
|
+
@property
|
20
|
+
def carrier_name(self) -> typing.Optional[str]:
|
21
|
+
return None
|
19
22
|
|
20
23
|
@property
|
21
|
-
def server_url(self) -> Optional[str]:
|
24
|
+
def server_url(self) -> typing.Optional[str]:
|
22
25
|
return None
|
23
26
|
|
24
27
|
@property
|
25
|
-
def
|
28
|
+
def tracking_url(self) -> typing.Optional[str]:
|
26
29
|
return None
|
30
|
+
|
31
|
+
@property
|
32
|
+
def connection_config(self):
|
33
|
+
import karrio.lib as lib
|
34
|
+
|
35
|
+
return lib.to_connection_config(self.config or {})
|
karrio/core/units.py
CHANGED
@@ -139,6 +139,11 @@ class MeasurementOptionsType(typing.NamedTuple):
|
|
139
139
|
min_lb: typing.Optional[float] = None
|
140
140
|
min_kg: typing.Optional[float] = None
|
141
141
|
min_oz: typing.Optional[float] = None
|
142
|
+
max_in: typing.Optional[float] = None
|
143
|
+
max_cm: typing.Optional[float] = None
|
144
|
+
max_lb: typing.Optional[float] = None
|
145
|
+
max_kg: typing.Optional[float] = None
|
146
|
+
max_oz: typing.Optional[float] = None
|
142
147
|
quant: typing.Optional[float] = None
|
143
148
|
|
144
149
|
|
@@ -428,6 +433,10 @@ class Products(typing.Iterable[Product]):
|
|
428
433
|
def quantity(self):
|
429
434
|
return sum((item.quantity for item in self._items), 0)
|
430
435
|
|
436
|
+
@property
|
437
|
+
def value_amount(self):
|
438
|
+
return sum((item.value_amount or 0.0 for item in self._items), 0.0)
|
439
|
+
|
431
440
|
|
432
441
|
class Package:
|
433
442
|
"""The parcel common processing helper"""
|
@@ -830,11 +839,13 @@ class ShippingOption(utils.Enum):
|
|
830
839
|
currency = utils.OptionEnum("currency")
|
831
840
|
insurance = utils.OptionEnum("insurance", float)
|
832
841
|
cash_on_delivery = utils.OptionEnum("COD", float)
|
842
|
+
shipment_note = utils.OptionEnum("shipment_note")
|
833
843
|
shipment_date = utils.OptionEnum("shipment_date")
|
834
844
|
dangerous_good = utils.OptionEnum("dangerous_good", bool)
|
835
845
|
declared_value = utils.OptionEnum("declared_value", float)
|
836
846
|
paperless_trade = utils.OptionEnum("paperless_trade", bool)
|
837
847
|
hold_at_location = utils.OptionEnum("hold_at_location", bool)
|
848
|
+
sms_notification = utils.OptionEnum("email_notification", bool)
|
838
849
|
email_notification = utils.OptionEnum("email_notification", bool)
|
839
850
|
email_notification_to = utils.OptionEnum("email_notification_to")
|
840
851
|
signature_confirmation = utils.OptionEnum("signature_confirmation", bool)
|
@@ -875,6 +886,10 @@ class ShippingOptions(Options):
|
|
875
886
|
|
876
887
|
return ShippingOption.email_notification.value(True)
|
877
888
|
|
889
|
+
@property
|
890
|
+
def sms_notification(self) -> utils.OptionEnum:
|
891
|
+
return self[ShippingOption.sms_notification.name]
|
892
|
+
|
878
893
|
@property
|
879
894
|
def email_notification_to(self) -> utils.OptionEnum:
|
880
895
|
return self[ShippingOption.email_notification_to.name]
|
@@ -903,6 +918,10 @@ class ShippingOptions(Options):
|
|
903
918
|
def doc_references(self) -> utils.OptionEnum:
|
904
919
|
return self[ShippingOption.doc_references.name]
|
905
920
|
|
921
|
+
@property
|
922
|
+
def shipment_note(self) -> utils.OptionEnum:
|
923
|
+
return self[ShippingOption.shipment_note.name]
|
924
|
+
|
906
925
|
|
907
926
|
class CustomsOption(utils.Enum):
|
908
927
|
"""common shipment customs identifiers"""
|
@@ -994,6 +1013,43 @@ class DocumentUploadOption(utils.Enum):
|
|
994
1013
|
destination_country_code = utils.OptionEnum("destination_country_code")
|
995
1014
|
|
996
1015
|
|
1016
|
+
class ConnectionConfigOption(utils.Enum):
|
1017
|
+
"""common shipment document upload options"""
|
1018
|
+
|
1019
|
+
label_type = utils.OptionEnum("label_type")
|
1020
|
+
language_code = utils.OptionEnum("language_code")
|
1021
|
+
default_currency = utils.OptionEnum("default_currency")
|
1022
|
+
shipping_options = utils.OptionEnum("shipping_options", list)
|
1023
|
+
shipping_services = utils.OptionEnum("shipping_services", list)
|
1024
|
+
|
1025
|
+
|
1026
|
+
class ConnectionConfigOptions(Options):
|
1027
|
+
"""The options common processing helper"""
|
1028
|
+
|
1029
|
+
def __init__(self, *args, **kwargs):
|
1030
|
+
super().__init__(*args, **kwargs, base_option_type=ConnectionConfigOption)
|
1031
|
+
|
1032
|
+
@property
|
1033
|
+
def label_type(self) -> utils.OptionEnum:
|
1034
|
+
return self[ConnectionConfigOption.label_type.name]
|
1035
|
+
|
1036
|
+
@property
|
1037
|
+
def language_code(self) -> utils.OptionEnum:
|
1038
|
+
return self[ConnectionConfigOption.language_code.name]
|
1039
|
+
|
1040
|
+
@property
|
1041
|
+
def default_currency(self) -> utils.OptionEnum:
|
1042
|
+
return self[ConnectionConfigOption.default_currency.name]
|
1043
|
+
|
1044
|
+
@property
|
1045
|
+
def shipping_options(self) -> utils.OptionEnum:
|
1046
|
+
return self[ConnectionConfigOption.shipping_options.name]
|
1047
|
+
|
1048
|
+
@property
|
1049
|
+
def shipping_services(self) -> utils.OptionEnum:
|
1050
|
+
return self[ConnectionConfigOption.shipping_services.name]
|
1051
|
+
|
1052
|
+
|
997
1053
|
class Services:
|
998
1054
|
"""The services common processing helper"""
|
999
1055
|
|
@@ -1050,6 +1106,9 @@ class ComputedAddress(models.Address):
|
|
1050
1106
|
self.address = address
|
1051
1107
|
|
1052
1108
|
def __getattr__(self, item):
|
1109
|
+
if item == "street_number":
|
1110
|
+
return self._compute_street_number()
|
1111
|
+
|
1053
1112
|
if hasattr(self.address, item):
|
1054
1113
|
return getattr(self.address, item)
|
1055
1114
|
|
@@ -1067,6 +1126,33 @@ class ComputedAddress(models.Address):
|
|
1067
1126
|
def address_lines(self) -> str:
|
1068
1127
|
return self._compute_address_line(join=False)
|
1069
1128
|
|
1129
|
+
@property
|
1130
|
+
def street(self) -> typing.Optional[str]:
|
1131
|
+
return typing.cast(
|
1132
|
+
str,
|
1133
|
+
utils.SF.concat_str(
|
1134
|
+
self.street_number,
|
1135
|
+
self.street_name,
|
1136
|
+
join=True,
|
1137
|
+
),
|
1138
|
+
)
|
1139
|
+
|
1140
|
+
@property
|
1141
|
+
def street_name(self) -> typing.Optional[str]:
|
1142
|
+
"""The address line 1 without the street number"""
|
1143
|
+
return typing.cast(
|
1144
|
+
str,
|
1145
|
+
utils.SF.concat_str(
|
1146
|
+
*[
|
1147
|
+
_
|
1148
|
+
for _ in self.address.address_line1.split(" ")
|
1149
|
+
if _ != self.street_number
|
1150
|
+
],
|
1151
|
+
join=True,
|
1152
|
+
),
|
1153
|
+
)
|
1154
|
+
return self.address.address_line1.replace(self.street_number, "").strip()
|
1155
|
+
|
1070
1156
|
@property
|
1071
1157
|
def tax_id(self) -> typing.Optional[str]:
|
1072
1158
|
return self.address.federal_tax_id or self.address.state_tax_id
|
@@ -1092,50 +1178,43 @@ class ComputedAddress(models.Address):
|
|
1092
1178
|
def has_tax_info(self) -> bool:
|
1093
1179
|
return any([self.address.federal_tax_id, self.address.state_tax_id])
|
1094
1180
|
|
1095
|
-
@property
|
1096
|
-
def suite(self) -> typing.Optional[str]:
|
1097
|
-
return getattr(self.address.extra, "suite", None)
|
1098
|
-
|
1099
1181
|
@property
|
1100
1182
|
def contact(self) -> typing.Optional[str]:
|
1101
1183
|
return getattr(self.address, "person_name", None) or getattr(
|
1102
1184
|
self.address, "company_name", None
|
1103
1185
|
)
|
1104
1186
|
|
1105
|
-
@property
|
1106
|
-
def street_name(self) -> typing.Optional[str]:
|
1107
|
-
return getattr(self.address.extra, "street_name", None)
|
1108
|
-
|
1109
|
-
@property
|
1110
|
-
def street_type(self) -> typing.Optional[str]:
|
1111
|
-
return getattr(self.address.extra, "street_type", None)
|
1112
|
-
|
1113
1187
|
def _compute_address_line(self, join: bool = True) -> typing.Optional[str]:
|
1114
1188
|
if any(
|
1115
1189
|
[
|
1116
|
-
self.
|
1117
|
-
self.
|
1118
|
-
self.
|
1190
|
+
self.street_number,
|
1191
|
+
self.street_name,
|
1192
|
+
self.address_line2,
|
1119
1193
|
]
|
1120
1194
|
):
|
1121
1195
|
return utils.SF.concat_str(
|
1122
|
-
self.
|
1123
|
-
self.
|
1124
|
-
self.
|
1196
|
+
self.street_number,
|
1197
|
+
self.street_name,
|
1198
|
+
self.address_line2,
|
1125
1199
|
join=join,
|
1126
1200
|
) # type:ignore
|
1127
1201
|
|
1128
|
-
if self.address.extra is not None:
|
1129
|
-
return utils.SF.concat_str(
|
1130
|
-
self.address.extra.suite,
|
1131
|
-
self.address.street_number,
|
1132
|
-
self.address.extra.street_name,
|
1133
|
-
self.address.extra.street_type,
|
1134
|
-
join=True,
|
1135
|
-
) # type:ignore
|
1136
|
-
|
1137
1202
|
return None
|
1138
1203
|
|
1204
|
+
def _compute_street_number(self):
|
1205
|
+
_value = getattr(self.address, "street_number", None)
|
1206
|
+
|
1207
|
+
if _value is None:
|
1208
|
+
words = self.address.address_line1.split(" ")
|
1209
|
+
|
1210
|
+
if any(_.isdigit() for _ in words[0]):
|
1211
|
+
return words[0]
|
1212
|
+
|
1213
|
+
if any(_.isdigit() for _ in words[-1]):
|
1214
|
+
return words[-1]
|
1215
|
+
|
1216
|
+
return _value
|
1217
|
+
|
1139
1218
|
|
1140
1219
|
class ComputedDocumentFile(models.DocumentFile):
|
1141
1220
|
def __init__(self, document: typing.Optional[models.DocumentFile]):
|
karrio/core/utils/helpers.py
CHANGED
@@ -44,17 +44,28 @@ def to_buffer(encoded_file: str, **kwargs) -> io.BytesIO:
|
|
44
44
|
return buffer
|
45
45
|
|
46
46
|
|
47
|
-
def image_to_pdf(image_str: str, rotate: int = None) -> str:
|
47
|
+
def image_to_pdf(image_str: str, rotate: int = None, resize: dict = None) -> str:
|
48
48
|
buffer = to_buffer(image_str)
|
49
49
|
_image = Image.open(buffer)
|
50
|
+
|
50
51
|
image = (
|
51
|
-
_image.rotate(rotate, Image.NEAREST, expand
|
52
|
+
_image.rotate(rotate, Image.NEAREST, expand=True)
|
52
53
|
if rotate is not None
|
53
54
|
else _image
|
54
55
|
)
|
55
56
|
|
57
|
+
if resize is not None:
|
58
|
+
img = image.copy()
|
59
|
+
wpercent = resize["width"] / float(img.size[0])
|
60
|
+
hsize = int((float(img.size[1]) * float(wpercent)))
|
61
|
+
image = img.resize((resize["width"], hsize), Image.Resampling.LANCZOS)
|
62
|
+
|
63
|
+
if resize is not None:
|
64
|
+
img = image.copy()
|
65
|
+
image = img.resize((resize["width"], resize["height"]), Image.ANTIALIAS)
|
66
|
+
|
56
67
|
new_buffer = io.BytesIO()
|
57
|
-
image.save(new_buffer, format="PDF")
|
68
|
+
image.save(new_buffer, format="PDF", dpi=(300, 300))
|
58
69
|
|
59
70
|
return base64.b64encode(new_buffer.getvalue()).decode("utf-8")
|
60
71
|
|
@@ -116,11 +127,26 @@ def bundle_base64(base64_strings: List[str], format: str = "PDF") -> str:
|
|
116
127
|
return base64.b64encode(result.getvalue()).decode("utf-8")
|
117
128
|
|
118
129
|
|
130
|
+
def zpl_to_pdf(zpl_str: str, width: int, height: int, dpmm: int = 12) -> str:
|
131
|
+
"""Return a PDF base64 string from a ZPL string."""
|
132
|
+
import karrio.lib as lib
|
133
|
+
|
134
|
+
data = lib.to_json(dict(file=base64.b64decode(zpl_str).decode("utf-8")))
|
135
|
+
doc = request(
|
136
|
+
url=f"http://api.labelary.com/v1/printers/{dpmm}dpmm/labels/{width}x{height}/",
|
137
|
+
data=data,
|
138
|
+
headers={"Accept": "application/pdf"},
|
139
|
+
decoder=lambda b: base64.encodebytes(b).decode("utf-8"),
|
140
|
+
)
|
141
|
+
|
142
|
+
return doc
|
143
|
+
|
144
|
+
|
119
145
|
def decode_bytes(byte):
|
120
146
|
return (
|
121
|
-
failsafe(lambda: byte.decode("utf-8"))
|
122
|
-
failsafe(lambda: byte.decode("ISO-8859-1"))
|
123
|
-
byte.decode("utf-8")
|
147
|
+
failsafe(lambda: byte.decode("utf-8"))
|
148
|
+
or failsafe(lambda: byte.decode("ISO-8859-1"))
|
149
|
+
or byte.decode("utf-8")
|
124
150
|
)
|
125
151
|
|
126
152
|
|
@@ -1,22 +1,22 @@
|
|
1
1
|
import attr
|
2
|
+
import typing
|
2
3
|
import logging
|
3
|
-
from typing import Any, Callable, Generic, TypeVar
|
4
4
|
|
5
5
|
from karrio.core.utils.helpers import identity
|
6
6
|
|
7
7
|
logger = logging.getLogger(__name__)
|
8
8
|
|
9
9
|
XML_str = str
|
10
|
-
T = TypeVar("T")
|
10
|
+
T = typing.TypeVar("T")
|
11
11
|
|
12
12
|
|
13
13
|
@attr.s(auto_attribs=True)
|
14
|
-
class Serializable(Generic[T]):
|
15
|
-
value:
|
16
|
-
_serializer: Callable[[
|
14
|
+
class Serializable(typing.Generic[T]):
|
15
|
+
value: typing.Any
|
16
|
+
_serializer: typing.Callable[[typing.Any], T] = identity
|
17
17
|
_ctx: dict = {}
|
18
18
|
|
19
|
-
def serialize(self) ->
|
19
|
+
def serialize(self) -> T:
|
20
20
|
serialized_value = self._serializer(self.value)
|
21
21
|
logger.debug(serialized_value)
|
22
22
|
return serialized_value
|
@@ -27,12 +27,12 @@ class Serializable(Generic[T]):
|
|
27
27
|
|
28
28
|
|
29
29
|
@attr.s(auto_attribs=True)
|
30
|
-
class Deserializable(Generic[T]):
|
31
|
-
value:
|
32
|
-
_deserializer: Callable[[
|
30
|
+
class Deserializable(typing.Generic[T]):
|
31
|
+
value: typing.Any
|
32
|
+
_deserializer: typing.Callable[[typing.Any], T] = identity
|
33
33
|
_ctx: dict = {}
|
34
34
|
|
35
|
-
def deserialize(self) ->
|
35
|
+
def deserialize(self) -> T:
|
36
36
|
logger.debug(self.value)
|
37
37
|
return self._deserializer(self.value)
|
38
38
|
|
karrio/lib.py
CHANGED
@@ -368,7 +368,11 @@ def to_shipping_options(
|
|
368
368
|
if initializer is not None:
|
369
369
|
return initializer(options, **kwargs)
|
370
370
|
|
371
|
-
return units.ShippingOptions(
|
371
|
+
return units.ShippingOptions(
|
372
|
+
options,
|
373
|
+
option_type=kwargs.get("option_type"),
|
374
|
+
items_filter=kwargs.get("items_filter"),
|
375
|
+
)
|
372
376
|
|
373
377
|
|
374
378
|
def to_services(
|
@@ -422,6 +426,16 @@ def to_upload_options(
|
|
422
426
|
)
|
423
427
|
|
424
428
|
|
429
|
+
def to_connection_config(
|
430
|
+
options: dict,
|
431
|
+
option_type: typing.Optional[typing.Type[utils.Enum]] = None,
|
432
|
+
) -> units.ConnectionConfigOptions:
|
433
|
+
return units.ConnectionConfigOptions(
|
434
|
+
options,
|
435
|
+
option_type=option_type,
|
436
|
+
)
|
437
|
+
|
438
|
+
|
425
439
|
# -----------------------------------------------------------
|
426
440
|
# Address utility functions.
|
427
441
|
# -----------------------------------------------------------
|
@@ -577,8 +591,9 @@ def request(
|
|
577
591
|
def image_to_pdf(
|
578
592
|
image_str: str,
|
579
593
|
rotate: int = None,
|
594
|
+
resize: dict = None,
|
580
595
|
) -> str:
|
581
|
-
return utils.image_to_pdf(image_str, rotate=rotate)
|
596
|
+
return utils.image_to_pdf(image_str, rotate=rotate, resize=resize)
|
582
597
|
|
583
598
|
|
584
599
|
def bundle_pdfs(
|
@@ -599,6 +614,16 @@ def bundle_zpls(
|
|
599
614
|
return utils.bundle_zpls(base64_strings)
|
600
615
|
|
601
616
|
|
617
|
+
def zpl_to_pdf(
|
618
|
+
zpl_str: str,
|
619
|
+
width: int,
|
620
|
+
height: int,
|
621
|
+
dpmm: int = 12,
|
622
|
+
) -> str:
|
623
|
+
"""Return a PDF base64 string from a ZPL string."""
|
624
|
+
return utils.zpl_to_pdf(zpl_str, width, height, dpmm=dpmm)
|
625
|
+
|
626
|
+
|
602
627
|
def bundle_base64(
|
603
628
|
base64_strings: typing.List[str],
|
604
629
|
format: str = "PDF",
|
karrio/references.py
CHANGED
@@ -78,6 +78,11 @@ def collect_references() -> dict:
|
|
78
78
|
for key, mapper in PROVIDERS_DATA.items()
|
79
79
|
if mapper.get("options") is not None
|
80
80
|
}
|
81
|
+
connection_configs = {
|
82
|
+
key: {c.name: dict(code=c.value.code) for c in list(mapper["connection_configs"])} # type: ignore
|
83
|
+
for key, mapper in PROVIDERS_DATA.items()
|
84
|
+
if mapper.get("connection_configs") is not None
|
85
|
+
}
|
81
86
|
|
82
87
|
REFERENCES = {
|
83
88
|
"countries": {c.name: c.value for c in list(units.Country)},
|
@@ -103,6 +108,7 @@ def collect_references() -> dict:
|
|
103
108
|
},
|
104
109
|
"services": services,
|
105
110
|
"options": options,
|
111
|
+
"connection_configs": connection_configs,
|
106
112
|
"carrier_capabilities": {
|
107
113
|
key: detect_capabilities(detect_proxy_methods(mapper["Proxy"]))
|
108
114
|
for key, mapper in PROVIDERS_DATA.items()
|
@@ -21,7 +21,7 @@ class RatingMixinProxy:
|
|
21
21
|
)
|
22
22
|
|
23
23
|
def get_rates(
|
24
|
-
self, request: utils.Serializable
|
24
|
+
self, request: utils.Serializable
|
25
25
|
) -> utils.Deserializable[typing.List[typing.Tuple[str, PackageRates]]]:
|
26
26
|
_request = request.serialize()
|
27
27
|
|
@@ -144,12 +144,10 @@ def get_available_rates(
|
|
144
144
|
for zone in service.zones or []:
|
145
145
|
# Check Location inclusion
|
146
146
|
_cover_supported_cities = (
|
147
|
-
zone.cities is not None
|
148
|
-
and recipient.city in zone.cities
|
147
|
+
zone.cities is not None and recipient.city in zone.cities
|
149
148
|
) or not any(zone.cities or [])
|
150
149
|
_cover_supported_countries = (
|
151
|
-
zone.cities is not None
|
152
|
-
and recipient.country_code in zone.country_codes
|
150
|
+
zone.cities is not None and recipient.country_code in zone.country_codes
|
153
151
|
) or not any(zone.country_codes or [])
|
154
152
|
|
155
153
|
# Check if weight and dimensions fit restrictions
|
@@ -14,7 +14,7 @@ class ShippingMixinProxy:
|
|
14
14
|
settings: ShippingMixinSettings
|
15
15
|
|
16
16
|
def create_shipment(
|
17
|
-
self, request: lib.Serializable
|
17
|
+
self, request: lib.Serializable
|
18
18
|
) -> lib.Deserializable[
|
19
19
|
typing.Tuple[typing.List[typing.Tuple[str, ServiceLabel]], typing.List[Message]]
|
20
20
|
]:
|
@@ -3,15 +3,18 @@ import karrio.lib as lib
|
|
3
3
|
import karrio.core.models as models
|
4
4
|
import karrio.universal.providers.rating.utils as utils
|
5
5
|
|
6
|
+
ResponseType = typing.List[typing.Tuple[str, utils.PackageRates]]
|
7
|
+
|
6
8
|
|
7
9
|
def parse_rate_response(
|
8
|
-
|
10
|
+
_response: lib.Deserializable[ResponseType], _
|
9
11
|
) -> typing.Tuple[typing.List[models.RateDetails], typing.List[models.Message]]:
|
12
|
+
responses = _response.deserialize()
|
10
13
|
package_rates: typing.List[typing.Tuple[str, typing.List[models.RateDetails]]] = []
|
11
14
|
messages: typing.List[models.Message] = []
|
12
15
|
|
13
|
-
for _ref,
|
14
|
-
_rates, _messages =
|
16
|
+
for _ref, _res in responses:
|
17
|
+
_rates, _messages = _res
|
15
18
|
messages += _messages
|
16
19
|
package_rates += [(_ref, _rates)]
|
17
20
|
|
@@ -20,7 +23,5 @@ def parse_rate_response(
|
|
20
23
|
return rates, messages
|
21
24
|
|
22
25
|
|
23
|
-
def rate_request(
|
24
|
-
payload: models.RateRequest, _
|
25
|
-
) -> lib.Serializable[models.RateRequest]:
|
26
|
+
def rate_request(payload: models.RateRequest, _) -> lib.Serializable:
|
26
27
|
return lib.Serializable(payload)
|
@@ -9,13 +9,14 @@ from karrio.core.models import (
|
|
9
9
|
from karrio.universal.providers.shipping.utils import ShippingMixinSettings
|
10
10
|
from karrio.core.models import ServiceLabel
|
11
11
|
from karrio.core.utils.transformer import to_multi_piece_shipment
|
12
|
+
import karrio.lib as lib
|
12
13
|
|
13
14
|
|
14
15
|
def parse_shipment_response(
|
15
|
-
|
16
|
+
_response: lib.Deserializable[Tuple[List[Tuple[str, ServiceLabel]], List[Message]]],
|
16
17
|
settings: ShippingMixinSettings,
|
17
18
|
) -> Tuple[ShipmentDetails, List[Message]]:
|
18
|
-
service_labels, errors =
|
19
|
+
service_labels, errors = _response.deserialize()
|
19
20
|
shipment = to_multi_piece_shipment(
|
20
21
|
[
|
21
22
|
(package_ref, _extract_details(service_label, settings))
|
@@ -40,5 +41,5 @@ def _extract_details(
|
|
40
41
|
)
|
41
42
|
|
42
43
|
|
43
|
-
def shipment_request(payload: ShipmentRequest, _) -> Serializable
|
44
|
+
def shipment_request(payload: ShipmentRequest, _) -> Serializable:
|
44
45
|
return Serializable(payload)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
karrio/__init__.py,sha256=MGaZGiMfGOpYY5gTQaOT-FgpyAmRoBio8dfXl1IcRWA,3149
|
2
|
-
karrio/lib.py,sha256=
|
3
|
-
karrio/references.py,sha256=
|
2
|
+
karrio/lib.py,sha256=jeFbDvSONXTG5cd6Sw-7FyskKzWfrDcYKlIt1L9rFq8,18075
|
3
|
+
karrio/references.py,sha256=Re-PHb3QyhFkqCGTuKyQjIFxpa30b9vaRqA5TVjwr1E,4969
|
4
4
|
karrio/addons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
karrio/addons/label.py,sha256=WwC1o97Ztyj3kRNTlAkHmYh4It7dC7l8bsC3fc-5yMA,10316
|
6
6
|
karrio/addons/renderer.py,sha256=tLO1ZWrYExBOyLVv29v-1FWtASrevZlG2OCgQFf8lqk,7016
|
@@ -8,25 +8,25 @@ karrio/addons/fonts/Oswald-Regular.ttf,sha256=JkY5cy9a34D6weSp7z8OtY5Yta6tB4UAh2
|
|
8
8
|
karrio/addons/fonts/Oswald-SemiBold.ttf,sha256=s4enQAb3fl-rF7yrZAHO8P99AVqUjiJ3DS873v-lidA,91700
|
9
9
|
karrio/api/__init__.py,sha256=fJbOJLRIdrVlUi2BM-JtagKdm05ADc9naRMtx6rZ0V4,127
|
10
10
|
karrio/api/gateway.py,sha256=9E30taInhrN7-VGeZz3NKcbKEwhy7h9grB_nZ8dlkQM,4955
|
11
|
-
karrio/api/interface.py,sha256=
|
11
|
+
karrio/api/interface.py,sha256=9vt5IZO0bZBYpeyFrxHe1XVLbR75gygdPowAY6DoJnE,16054
|
12
12
|
karrio/api/mapper.py,sha256=OjLH2b6_NRcVNnJDb3hZypY6FfHuTHiMlAJgYnWpkzM,13472
|
13
13
|
karrio/api/proxy.py,sha256=Mx5tpcL0L_02lIZ84AvnEfroVu5Qi22iz7AVueX4YjI,6320
|
14
14
|
karrio/core/__init__.py,sha256=BboTt3huAYrsqcTcaq1lFX5O4uKiIi2cpWEXp68ItMo,71
|
15
15
|
karrio/core/errors.py,sha256=iMwiwCwK0eiYzk5KJ9Qu86JMWpymw1zDCvmqY67ghSw,3006
|
16
|
-
karrio/core/metadata.py,sha256=
|
17
|
-
karrio/core/models.py,sha256=
|
18
|
-
karrio/core/settings.py,sha256=
|
19
|
-
karrio/core/units.py,sha256=
|
16
|
+
karrio/core/metadata.py,sha256=vs4doqUjxDSRbDulbdBeTAyFUIZ8MdjsRP74YjtdNEY,1081
|
17
|
+
karrio/core/models.py,sha256=wkqD4M7cCDFJmdpI3shDvxX4M9mFirL6K3yHUl0GIbM,10953
|
18
|
+
karrio/core/settings.py,sha256=1d-w-U5nODMxsbmR0B4CdgggvYCzsgtSipP7GUWmFkI,753
|
19
|
+
karrio/core/units.py,sha256=PyHjHEdge6fY-xZph9_NUQdbExROoyIpUSdRT8MgKIs,58015
|
20
20
|
karrio/core/utils/__init__.py,sha256=NPxAugvQ4lhWOngITOagexXrsTQqlJQ0gyaXc9iBivg,739
|
21
21
|
karrio/core/utils/caching.py,sha256=zx0R1XAWPuA0q2hz5xUw0-OLZhHd7haS41uO_Prg8Ng,1734
|
22
22
|
karrio/core/utils/datetime.py,sha256=aFMqLB_AdRGM0By2TO8mYce-UlqExf_J2s2eLNtDClY,2311
|
23
23
|
karrio/core/utils/dict.py,sha256=fUsyMwRduh3qJ6D6Vf4LUVcljEqDHJVn8Av9x4rUadg,2312
|
24
24
|
karrio/core/utils/enum.py,sha256=qCrqP49wXyypfQ7rw4kFGjJ6rawptOxq_RPwqaz09dk,4420
|
25
|
-
karrio/core/utils/helpers.py,sha256=
|
25
|
+
karrio/core/utils/helpers.py,sha256=I3oMOPl4oeOyR8qQLlt1jVL59-uxnE8dBoWlfuqP658,8518
|
26
26
|
karrio/core/utils/log.py,sha256=G0JqUqNiS7JwkFMurtHtbxa42miAs28dPfNZZdlZid4,434
|
27
27
|
karrio/core/utils/number.py,sha256=z455Zbx5V92Ofo8PEaC_UEfmVEwnb-nq7fIoSeApz4o,1176
|
28
28
|
karrio/core/utils/pipeline.py,sha256=6wXdsUGW7ZVqhpsEzreBnS6dHSCU5XgClOaBgKfJyh8,1253
|
29
|
-
karrio/core/utils/serializable.py,sha256=
|
29
|
+
karrio/core/utils/serializable.py,sha256=iaeiVeiCqnpIhX0danUPfsixVWcYkhb3NkYlfQaFuJA,916
|
30
30
|
karrio/core/utils/soap.py,sha256=g8AzymGypJris0liiK-zwsjeoCPlIJ8r25WSBlSHqqs,5274
|
31
31
|
karrio/core/utils/string.py,sha256=l2CL4rn7Tls26oH_IgAsiQh80grG39Tj4NKY4CtcCsU,762
|
32
32
|
karrio/core/utils/tracing.py,sha256=84dmmpEPs_iBC3JaFv4f9vbC0VgR6KW4HZEYIrdt084,1462
|
@@ -36,16 +36,16 @@ karrio/mappers/__init__.py,sha256=i5qDwqYoTmFscV1rwxIOo19JiRzyfTWJd9Jx0qEvUmo,12
|
|
36
36
|
karrio/providers/__init__.py,sha256=02HsiVGylnZLoB_OE-7kJTvF500-CpOe-WWkOkqRUno,131
|
37
37
|
karrio/universal/__init__.py,sha256=bpT73UG7mZL_JjEqMwbYx6q69jA8J5Jcoul1LcDokhA,81
|
38
38
|
karrio/universal/mappers/__init__.py,sha256=bpT73UG7mZL_JjEqMwbYx6q69jA8J5Jcoul1LcDokhA,81
|
39
|
-
karrio/universal/mappers/rating_proxy.py,sha256=
|
40
|
-
karrio/universal/mappers/shipping_proxy.py,sha256
|
39
|
+
karrio/universal/mappers/rating_proxy.py,sha256=la0cAsbhuXzSFYdzi8tJalC4kT79FvZu_N99VMGTktU,10634
|
40
|
+
karrio/universal/mappers/shipping_proxy.py,sha256=-hEXZ0R3-Ps6MSRAGpE_IlWsa0gKr6xJjIz4NuoeXQ8,1935
|
41
41
|
karrio/universal/providers/__init__.py,sha256=bpT73UG7mZL_JjEqMwbYx6q69jA8J5Jcoul1LcDokhA,81
|
42
42
|
karrio/universal/providers/rating/__init__.py,sha256=3f8u1FS7OF9OZUGauBSt4B1ad0dmqIsmFaG3pWu7Sck,139
|
43
|
-
karrio/universal/providers/rating/rate.py,sha256=
|
43
|
+
karrio/universal/providers/rating/rate.py,sha256=5M79YhIX-XMnm44kezFEoY5vE9d-WWjGAaBnE7MOmJI,861
|
44
44
|
karrio/universal/providers/rating/utils.py,sha256=WVyJWdxCdKM1YlhTHVFxEMyac0FKIGHEkYXWEgJUzYA,558
|
45
45
|
karrio/universal/providers/shipping/__init__.py,sha256=JRcfJWSeDSjO2g2fRnLgBurBXn01nVpdi21ShxLpG34,188
|
46
|
-
karrio/universal/providers/shipping/shipment.py,sha256=
|
46
|
+
karrio/universal/providers/shipping/shipment.py,sha256=t7PO4uSzD1ZL3q3UZWHAPD3UUZUKXReQvED8mVKUe1A,1512
|
47
47
|
karrio/universal/providers/shipping/utils.py,sha256=1LuO31RMhpUls6-h5xhWkfky4G7tdWmGKmRhLkj-e98,593
|
48
|
-
karrio-2023.
|
49
|
-
karrio-2023.
|
50
|
-
karrio-2023.
|
51
|
-
karrio-2023.
|
48
|
+
karrio-2023.4.4.dist-info/METADATA,sha256=dRozbMtKfDyrdjkZtVUAHMOyE4vbgM3M-dzUyicgKJo,4705
|
49
|
+
karrio-2023.4.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
50
|
+
karrio-2023.4.4.dist-info/top_level.txt,sha256=mfkVZXzNuVRmA7NRlck_Ub-C8Zgtqxbx3gX1Rq_W-i0,7
|
51
|
+
karrio-2023.4.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|