karrio 2023.9.2__py3-none-any.whl → 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/core/units.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """Karrio universal data types and units definitions"""
2
2
 
3
+ from ctypes import util
3
4
  import attr
4
5
  import typing
5
6
  import numbers
@@ -24,20 +25,20 @@ class PackagePreset:
24
25
  packaging_type: str = None
25
26
 
26
27
 
27
- class LabelType(utils.Enum):
28
+ class LabelType(utils.StrEnum):
28
29
  PDF = "PDF"
29
30
  ZPL = "ZPL"
30
31
  PNG = "PNG"
31
32
 
32
33
 
33
- class DocFormat(utils.Enum):
34
+ class DocFormat(utils.StrEnum):
34
35
  gif = "GIF"
35
36
  jpg = "JPG"
36
37
  pdf = "PDF"
37
38
  png = "PNG"
38
39
 
39
40
 
40
- class PackagingUnit(utils.Enum):
41
+ class PackagingUnit(utils.StrEnum):
41
42
  envelope = "Small Envelope"
42
43
  pak = "Pak"
43
44
  tube = "Tube"
@@ -47,19 +48,19 @@ class PackagingUnit(utils.Enum):
47
48
  your_packaging = "Your Packaging"
48
49
 
49
50
 
50
- class PaymentType(utils.Enum):
51
+ class PaymentType(utils.StrEnum):
51
52
  sender = "SENDER"
52
53
  recipient = "RECIPIENT"
53
54
  third_party = "THIRD_PARTY"
54
55
 
55
56
 
56
- class CreditCardType(utils.Enum):
57
+ class CreditCardType(utils.StrEnum):
57
58
  visa = "Visa"
58
59
  mastercard = "Mastercard"
59
60
  american_express = "AmericanExpress"
60
61
 
61
62
 
62
- class CustomsContentType(utils.Enum):
63
+ class CustomsContentType(utils.StrEnum):
63
64
  documents = "DOCUMENTS"
64
65
  gift = "GIFT"
65
66
  sample = "SAMPLE"
@@ -68,13 +69,14 @@ class CustomsContentType(utils.Enum):
68
69
  other = "OTHER"
69
70
 
70
71
 
71
- class Incoterm(utils.Enum):
72
+ class Incoterm(utils.StrEnum):
72
73
  """universal international shipment incoterm (term of trades)"""
73
74
 
74
75
  CFR = "Cost and Freight"
75
76
  CIF = "Cost Insurance and Freight"
76
77
  CIP = "Carriage and Insurance Paid"
77
78
  CPT = "Carriage Paid To"
79
+ DAP = "Delivery at Place"
78
80
  DAF = "Delivered at Frontier"
79
81
  DDP = "Delivery Duty Paid"
80
82
  DDU = "Delivery Duty Unpaid"
@@ -86,7 +88,7 @@ class Incoterm(utils.Enum):
86
88
  FOB = "Free On Board"
87
89
 
88
90
 
89
- class WeightUnit(utils.Enum):
91
+ class WeightUnit(utils.StrEnum):
90
92
  """universal weight units"""
91
93
 
92
94
  KG = "KG"
@@ -95,13 +97,27 @@ class WeightUnit(utils.Enum):
95
97
  G = "G"
96
98
 
97
99
 
98
- class DimensionUnit(utils.Enum):
100
+ class DimensionUnit(utils.StrEnum):
99
101
  """universal dimension units"""
100
102
 
101
103
  CM = "CM"
102
104
  IN = "IN"
103
105
 
104
106
 
107
+ class VolumeUnit(utils.StrEnum):
108
+ """universal dimension units"""
109
+
110
+ l = "l"
111
+ m3 = "m3"
112
+ i3 = "i3"
113
+ ft3 = "ft3"
114
+ cm3 = "cm3"
115
+
116
+ """ mapping from dimension units to volume units """
117
+ CM = "cm3"
118
+ IN = "i3"
119
+
120
+
105
121
  class FreightClass(utils.Enum):
106
122
  """universal freight_class units"""
107
123
 
@@ -125,7 +141,7 @@ class FreightClass(utils.Enum):
125
141
  freight_class_400 = 400
126
142
 
127
143
 
128
- class UploadDocumentType(utils.Enum):
144
+ class UploadDocumentType(utils.StrEnum):
129
145
  """universal upload document types"""
130
146
 
131
147
  certificate_of_origin = "certificate_of_origin"
@@ -136,6 +152,8 @@ class UploadDocumentType(utils.Enum):
136
152
 
137
153
 
138
154
  class MeasurementOptionsType(typing.NamedTuple):
155
+ quant: typing.Optional[float] = None
156
+
139
157
  min_in: typing.Optional[float] = None
140
158
  min_cm: typing.Optional[float] = None
141
159
  min_lb: typing.Optional[float] = None
@@ -148,7 +166,9 @@ class MeasurementOptionsType(typing.NamedTuple):
148
166
  max_kg: typing.Optional[float] = None
149
167
  max_oz: typing.Optional[float] = None
150
168
  max_g: typing.Optional[float] = None
151
- quant: typing.Optional[float] = None
169
+
170
+ min_volume: typing.Optional[float] = None
171
+ max_volume: typing.Optional[float] = None
152
172
 
153
173
 
154
174
  class CarrierCapabilities(utils.Enum):
@@ -157,6 +177,7 @@ class CarrierCapabilities(utils.Enum):
157
177
  shipping = "shipping"
158
178
  tracking = "tracking"
159
179
  paperless = "paperless"
180
+ manifest = "manifest"
160
181
 
161
182
  @classmethod
162
183
  def get_capabilities(cls):
@@ -176,6 +197,8 @@ class CarrierCapabilities(utils.Enum):
176
197
  return "shipping"
177
198
  elif "document" in method_name:
178
199
  return "paperless"
200
+ elif "manifest" in method_name:
201
+ return "manifest"
179
202
 
180
203
  return None
181
204
 
@@ -260,24 +283,148 @@ class Volume:
260
283
  """The volume common processing helper"""
261
284
 
262
285
  def __init__(
263
- self, side1: Dimension = None, side2: Dimension = None, side3: Dimension = None
286
+ self,
287
+ side1: Dimension = None,
288
+ side2: Dimension = None,
289
+ side3: Dimension = None,
290
+ value: float = None,
291
+ unit: typing.Union[VolumeUnit, str] = VolumeUnit.cm3,
292
+ options: MeasurementOptionsType = MeasurementOptionsType(),
264
293
  ):
265
294
  self._side1 = side1
266
295
  self._side2 = side2
267
296
  self._side3 = side3
268
297
 
298
+ self._value = value
299
+ self._unit = VolumeUnit[unit] if isinstance(unit, str) else unit
300
+
301
+ self._quant = 0.01
302
+ self._min_volume = options.min_volume
303
+
304
+ def __getitem__(self, item):
305
+ return getattr(self, item)
306
+
307
+ def _compute(self, value: float):
308
+ below_min = self._min_volume is not None and value < self._min_volume
309
+ return utils.NF.decimal(
310
+ value=(self._min_volume if below_min else value),
311
+ quant=self._quant,
312
+ )
313
+
314
+ @property
315
+ def unit(self) -> str:
316
+ if self._unit is None:
317
+ return None
318
+
319
+ return self._unit.value
320
+
269
321
  @property
270
322
  def value(self):
271
- if not all([self._side1.value, self._side2.value, self._side3.value]):
323
+ missing_side_value = not all(
324
+ [
325
+ getattr(self._side1, "value", None),
326
+ getattr(self._side2, "value", None),
327
+ getattr(self._side3, "value", None),
328
+ ]
329
+ )
330
+ missing_value = self._unit is None or self._value is None
331
+
332
+ if missing_side_value and missing_value:
272
333
  return None
273
334
 
274
- return utils.NF.decimal(self._side1.M * self._side2.M * self._side3.M)
335
+ if not missing_value:
336
+ return self._value
337
+
338
+ return self._compute(self._side1.value * self._side2.value * self._side3.value)
275
339
 
276
340
  @property
277
- def cubic_meter(self):
341
+ def l(self):
278
342
  if self.value is None:
279
343
  return None
280
- return utils.NF.decimal(self.value * 250)
344
+ if self._unit == VolumeUnit.m3:
345
+ return self._compute(self.value * 1000)
346
+ elif self._unit == VolumeUnit.i3:
347
+ return self._compute(self.value / 61.024)
348
+ elif self._unit == VolumeUnit.ft3:
349
+ return self._compute(self.value * 28.317)
350
+ if self._unit == VolumeUnit.cm3:
351
+ return self._compute(self.value / 1000)
352
+ else:
353
+ return self.value
354
+
355
+ @property
356
+ def m3(self):
357
+ if self.value is None:
358
+ return None
359
+ if self._unit == VolumeUnit.l:
360
+ return self._compute(self.value / 1000)
361
+ if self._unit == VolumeUnit.cm3:
362
+ return self._compute(self.value / 1e6)
363
+ elif self._unit == VolumeUnit.i3:
364
+ return self._compute(self.value / 61020)
365
+ elif self._unit == VolumeUnit.ft3:
366
+ return self._compute(self.value / 35.315)
367
+ else:
368
+ return self.value
369
+
370
+ @property
371
+ def i3(self):
372
+ if self.value is None:
373
+ return None
374
+ if self._unit == VolumeUnit.l:
375
+ return self._compute(self.value * 61.024)
376
+ if self._unit == VolumeUnit.m3:
377
+ return self._compute(self.value * 1000000)
378
+ elif self._unit == VolumeUnit.cm3:
379
+ return self._compute(self.value / 16.387)
380
+ elif self._unit == VolumeUnit.ft3:
381
+ return self._compute(self.value * 1728)
382
+ else:
383
+ return self.value
384
+
385
+ @property
386
+ def ft3(self):
387
+ if self.value is None:
388
+ return None
389
+ if self._unit == VolumeUnit.l:
390
+ return self._compute(self.value / 28.317)
391
+ if self._unit == VolumeUnit.m3:
392
+ return self._compute(self.value * 35.315)
393
+ elif self._unit == VolumeUnit.i3:
394
+ return self._compute(self.value / 1728)
395
+ elif self._unit == VolumeUnit.cm3:
396
+ return self._compute(self.value / 28320)
397
+ else:
398
+ return self.value
399
+
400
+ @property
401
+ def cm3(self):
402
+ if self.value is None:
403
+ return None
404
+ if self._unit == VolumeUnit.l:
405
+ return self._compute(self.value * 1000)
406
+ if self._unit == VolumeUnit.m3:
407
+ return self._compute(self.value * 1e6)
408
+ elif self._unit == VolumeUnit.i3:
409
+ return self._compute(self.value * 16.387)
410
+ elif self._unit == VolumeUnit.ft3:
411
+ return self._compute(self.value * 28320)
412
+ else:
413
+ return self.value
414
+
415
+ @property
416
+ def cubic_meter(self):
417
+ return self.m3
418
+
419
+ def map(self, options: MeasurementOptionsType):
420
+ return Volume(
421
+ side1=self._side1,
422
+ side2=self._side2,
423
+ side3=self._side3,
424
+ value=self._value,
425
+ unit=self._unit,
426
+ options=options,
427
+ )
281
428
 
282
429
 
283
430
  class Girth:
@@ -458,6 +605,9 @@ class Products(typing.Iterable[Product]):
458
605
  weight_unit: str = None,
459
606
  ):
460
607
  self._items = [Product(item, weight_unit=weight_unit) for item in items]
608
+ self._weight_unit = (
609
+ weight_unit or self._items[0].weight_unit if any(self._items) else None
610
+ )
461
611
 
462
612
  def __len__(self) -> int:
463
613
  return len(self._items)
@@ -474,7 +624,30 @@ class Products(typing.Iterable[Product]):
474
624
 
475
625
  @property
476
626
  def value_amount(self):
477
- return sum((item.value_amount or 0.0 for item in self._items), 0.0)
627
+ return sum(
628
+ (
629
+ item.value_amount * item.quantity
630
+ for item in self._items
631
+ if utils.NF.decimal(item.value_amount) is not None
632
+ ),
633
+ 0.0,
634
+ )
635
+
636
+ @property
637
+ def weight(self) -> Weight:
638
+ return Weight(
639
+ sum([item.weight * item.quantity for item in self._items], 0.0),
640
+ self._weight_unit,
641
+ )
642
+
643
+ @property
644
+ def description(self) -> typing.Optional[str]:
645
+ descriptions = set([item.description for item in self._items])
646
+ description: typing.Optional[str] = utils.SF.concat_str(
647
+ *list(descriptions), join=True
648
+ ) # type:ignore
649
+
650
+ return description
478
651
 
479
652
 
480
653
  class Package:
@@ -565,7 +738,9 @@ class Package:
565
738
 
566
739
  @property
567
740
  def volume(self) -> Volume:
568
- return Volume(self.width, self.length, self.height)
741
+ return Volume(
742
+ self.width, self.length, self.height, unit=self.dimension_unit.value
743
+ )
569
744
 
570
745
  @property
571
746
  def thickness(self) -> Dimension:
@@ -603,6 +778,17 @@ class Package:
603
778
 
604
779
  return Products(_items, self.weight_unit.value)
605
780
 
781
+ @property
782
+ def total_value(self) -> typing.Optional[float]:
783
+ if not any(self.parcel.items or []):
784
+ return None
785
+
786
+ return self.items.value_amount
787
+
788
+ @property
789
+ def reference_number(self) -> typing.Optional[str]:
790
+ return self.parcel.reference_number
791
+
606
792
 
607
793
  class Packages(typing.Iterable[Package]):
608
794
  """The parcel collection common processing helper"""
@@ -695,11 +881,22 @@ class Packages(typing.Iterable[Package]):
695
881
  return Weight(unit=unit, value=value)
696
882
 
697
883
  @property
698
- def volume(self) -> typing.Optional[float]:
884
+ def volume(self) -> Volume:
699
885
  if not any([pkg.volume.value for pkg in self._items]):
700
- return None
886
+ return Volume(value=None)
701
887
 
702
- return sum([pkg.volume.value or 0.0 for pkg in self._items], 0.0)
888
+ _, _dimension_unit = self._compatible_units
889
+ _volume_unit = VolumeUnit[_dimension_unit.name]
890
+ _total_volume = sum(
891
+ [
892
+ pkg.volume[_volume_unit.name]
893
+ for pkg in self._items
894
+ if pkg.volume is not None
895
+ ],
896
+ 0.0,
897
+ )
898
+
899
+ return Volume(value=_total_volume, unit=_volume_unit)
703
900
 
704
901
  @property
705
902
  def package_type(self) -> str:
@@ -722,6 +919,15 @@ class Packages(typing.Iterable[Package]):
722
919
 
723
920
  return description
724
921
 
922
+ @property
923
+ def content(self) -> typing.Optional[str]:
924
+ contents = set([item.parcel.content for item in self._items])
925
+ content: typing.Optional[str] = utils.SF.concat_str(
926
+ *list(contents), join=True
927
+ ) # type:ignore
928
+
929
+ return content
930
+
725
931
  @property
726
932
  def options(self) -> "ShippingOptions":
727
933
  def merge_options(acc, pkg) -> dict:
@@ -776,6 +982,15 @@ class Packages(typing.Iterable[Package]):
776
982
 
777
983
  return Products(_items, _weight_unit.value)
778
984
 
985
+ @property
986
+ def total_value(self) -> typing.Optional[float]:
987
+ if not any([_.total_value for _ in self._items]):
988
+ return None
989
+
990
+ return sum(
991
+ [pkg.total_value for pkg in self._items if pkg.total_value is not None], 0.0
992
+ )
993
+
779
994
  def validate(self, required: typing.List[str] = None, max_weight: Weight = None):
780
995
  required = required or self._required
781
996
  max_weight = max_weight or self._max_weight
@@ -853,6 +1068,7 @@ class Options:
853
1068
  _key = key
854
1069
  option_values[key] = _val
855
1070
 
1071
+ self._raw_options = options
856
1072
  self._options = option_values
857
1073
  self._option_list = self._filter(
858
1074
  option_values, (items_filter or utils.identity)
@@ -894,10 +1110,10 @@ class ShippingOption(utils.Enum):
894
1110
  """universal shipment options (special services)"""
895
1111
 
896
1112
  currency = utils.OptionEnum("currency")
1113
+ is_return = utils.OptionEnum("is_return", bool)
897
1114
  insurance = utils.OptionEnum("insurance", float)
898
1115
  cash_on_delivery = utils.OptionEnum("COD", float)
899
1116
  shipment_note = utils.OptionEnum("shipment_note")
900
- shipment_date = utils.OptionEnum("shipment_date")
901
1117
  dangerous_good = utils.OptionEnum("dangerous_good", bool)
902
1118
  declared_value = utils.OptionEnum("declared_value", float)
903
1119
  paperless_trade = utils.OptionEnum("paperless_trade", bool)
@@ -906,6 +1122,7 @@ class ShippingOption(utils.Enum):
906
1122
  email_notification_to = utils.OptionEnum("email_notification_to")
907
1123
  signature_confirmation = utils.OptionEnum("signature_confirmation", bool)
908
1124
  saturday_delivery = utils.OptionEnum("saturday_delivery", bool)
1125
+ sunday_delivery = utils.OptionEnum("sunday_delivery", bool)
909
1126
  doc_files = utils.OptionEnum("doc_files", utils.DP.to_dict)
910
1127
  doc_references = utils.OptionEnum("doc_references", utils.DP.to_dict)
911
1128
  hold_at_location = utils.OptionEnum("hold_at_location", bool)
@@ -913,6 +1130,14 @@ class ShippingOption(utils.Enum):
913
1130
  "hold_at_location_address",
914
1131
  functools.partial(utils.DP.to_object, models.Address),
915
1132
  )
1133
+ shipper_instructions = utils.OptionEnum("shipper_instructions")
1134
+ recipient_instructions = utils.OptionEnum("recipient_instructions")
1135
+
1136
+ """TODO: dreprecate these"""
1137
+ shipment_date = utils.OptionEnum("shipment_date")
1138
+
1139
+ """TODO: standardize to these"""
1140
+ shipping_date = utils.OptionEnum("shipping_date") # format: %Y-%m-%dT%H:%M
916
1141
 
917
1142
 
918
1143
  class ShippingOptions(Options):
@@ -958,8 +1183,22 @@ class ShippingOptions(Options):
958
1183
 
959
1184
  @property
960
1185
  def shipment_date(self) -> utils.OptionEnum:
1186
+ # Check if shipment_date is not defined and fallback to shipping_date
1187
+ if not self[ShippingOption.shipment_date.name].state:
1188
+ return utils.OptionEnum(
1189
+ "shipment_date",
1190
+ str,
1191
+ utils.DF.fdate(
1192
+ self._raw_options.get("shipping_date"), "%Y-%m-%dT%H:%M"
1193
+ ),
1194
+ )
1195
+
961
1196
  return self[ShippingOption.shipment_date.name]
962
1197
 
1198
+ @property
1199
+ def shipping_date(self) -> utils.OptionEnum:
1200
+ return self[ShippingOption.shipping_date.name]
1201
+
963
1202
  @property
964
1203
  def signature_confirmation(self) -> utils.OptionEnum:
965
1204
  return self[ShippingOption.signature_confirmation.name]
@@ -984,19 +1223,63 @@ class ShippingOptions(Options):
984
1223
  def shipment_note(self) -> utils.OptionEnum:
985
1224
  return self[ShippingOption.shipment_note.name]
986
1225
 
1226
+ @property
1227
+ def shipper_instructions(self) -> utils.OptionEnum:
1228
+ return self[ShippingOption.shipper_instructions.name]
1229
+
1230
+ @property
1231
+ def recipient_instructions(self) -> utils.OptionEnum:
1232
+ return self[ShippingOption.recipient_instructions.name]
1233
+
987
1234
 
988
1235
  class CustomsOption(utils.Enum):
989
1236
  """common shipment customs identifiers"""
990
1237
 
991
1238
  aes = utils.OptionEnum("aes")
1239
+ ioss = utils.OptionEnum("ioss")
992
1240
  eel_pfc = utils.OptionEnum("eel_pfc")
993
- nip_number = utils.OptionEnum("eori_number")
1241
+ nip_number = utils.OptionEnum("nip_number")
994
1242
  eori_number = utils.OptionEnum("eori_number")
995
1243
  license_number = utils.OptionEnum("license_number")
996
1244
  certificate_number = utils.OptionEnum("certificate_number")
997
1245
  vat_registration_number = utils.OptionEnum("vat_registration_number")
998
1246
 
999
1247
 
1248
+ class CustomsOptions(Options):
1249
+ """The options common processing helper"""
1250
+
1251
+ def __init__(self, *args, **kwargs):
1252
+ super().__init__(*args, **kwargs, base_option_type=CustomsOption)
1253
+
1254
+ @property
1255
+ def aes(self) -> utils.OptionEnum:
1256
+ return self[CustomsOption.aes.name]
1257
+
1258
+ @property
1259
+ def eel_pfc(self) -> utils.OptionEnum:
1260
+ return self[CustomsOption.eel_pfc.name]
1261
+
1262
+ @property
1263
+ def nip_number(self) -> utils.OptionEnum:
1264
+ return self[CustomsOption.nip_number.name]
1265
+
1266
+ @property
1267
+ def eori_number(self) -> utils.OptionEnum:
1268
+ return self[CustomsOption.eori_number.name]
1269
+
1270
+ @property
1271
+ def license_number(self) -> utils.OptionEnum:
1272
+ return self[CustomsOption.license_number.name]
1273
+
1274
+ @property
1275
+ def certificate_number(self) -> utils.OptionEnum:
1276
+ return self[CustomsOption.certificate_number.name]
1277
+
1278
+ @property
1279
+ def vat_registration_number(self) -> utils.OptionEnum:
1280
+ return self[CustomsOption.vat_registration_number.name]
1281
+
1282
+
1000
1283
  class CustomsInfo(models.Customs):
1001
1284
  """The customs info processing helper"""
1002
1285
 
@@ -1010,10 +1293,9 @@ class CustomsInfo(models.Customs):
1010
1293
  recipient: typing.Optional[models.Address] = None,
1011
1294
  ):
1012
1295
  _customs = customs or default_to
1013
- options = Options(
1296
+ options = CustomsOptions(
1014
1297
  getattr(_customs, "options", None) or {},
1015
1298
  option_type=option_type,
1016
- base_option_type=CustomsOption,
1017
1299
  )
1018
1300
 
1019
1301
  self._customs = _customs
@@ -1036,7 +1318,7 @@ class CustomsInfo(models.Customs):
1036
1318
  return self._customs is not None
1037
1319
 
1038
1320
  @property
1039
- def duty(self) -> typing.Optional[models.Duty]: # type:ignore
1321
+ def duty(self) -> models.Duty: # type:ignore
1040
1322
  return getattr(self._customs, "duty", None) or models.Duty()
1041
1323
 
1042
1324
  @property
@@ -1213,7 +1495,6 @@ class ComputedAddress(models.Address):
1213
1495
  join=True,
1214
1496
  ),
1215
1497
  )
1216
- return self.address.address_line1.replace(self.street_number, "").strip()
1217
1498
 
1218
1499
  @property
1219
1500
  def tax_id(self) -> typing.Optional[str]:
@@ -1246,6 +1527,20 @@ class ComputedAddress(models.Address):
1246
1527
  self.address, "company_name", None
1247
1528
  )
1248
1529
 
1530
+ @property
1531
+ def first_name(self) -> typing.Optional[str]:
1532
+ if self.address.person_name is None:
1533
+ return None
1534
+
1535
+ return self.address.person_name.split(" ")[0]
1536
+
1537
+ @property
1538
+ def last_name(self) -> typing.Optional[str]:
1539
+ if self.address.person_name is None:
1540
+ return None
1541
+
1542
+ return self.address.person_name.split(" ")[-1]
1543
+
1249
1544
  def _compute_address_line(self, join: bool = True) -> typing.Optional[str]:
1250
1545
  if any(
1251
1546
  [
@@ -1264,7 +1559,7 @@ class ComputedAddress(models.Address):
1264
1559
  def _compute_street_number(self):
1265
1560
  _value = getattr(self.address, "street_number", None)
1266
1561
 
1267
- if _value is None:
1562
+ if _value is None and self.address:
1268
1563
  words = self.address.address_line1.split(" ")
1269
1564
 
1270
1565
  if any(_.isdigit() for _ in words[0]):
@@ -1293,16 +1588,20 @@ class ComputedDocumentFile(models.DocumentFile):
1293
1588
 
1294
1589
 
1295
1590
  class TrackingStatus(utils.Enum):
1591
+ pending = ["pending"]
1296
1592
  on_hold = ["on_hold"]
1593
+ cancelled = ["cancelled"]
1297
1594
  delivered = ["delivered"]
1298
1595
  in_transit = ["in_transit"]
1299
1596
  delivery_failed = ["delivery_failed"]
1300
1597
  delivery_delayed = ["delivery_delayed"]
1301
1598
  out_for_delivery = ["out_for_delivery"]
1302
1599
  ready_for_pickup = ["ready_for_pickup"]
1600
+ return_to_sender = ["return_to_sender"]
1601
+ unknown = ["unknown"]
1303
1602
 
1304
1603
 
1305
- def create_enum(name, values):
1604
+ def create_enum(name, values) -> utils.Enum:
1306
1605
  return utils.Enum(name, values) # type: ignore
1307
1606
 
1308
1607
 
@@ -1455,6 +1754,7 @@ class Currency(utils.Enum):
1455
1754
 
1456
1755
 
1457
1756
  class Country(utils.Enum):
1757
+ AC = "Ascension Island"
1458
1758
  AD = "Andorra"
1459
1759
  AE = "United Arab Emirates"
1460
1760
  AF = "Afghanistan"
@@ -1689,9 +1989,17 @@ class Country(utils.Enum):
1689
1989
  ZA = "South Africa"
1690
1990
  ZM = "Zambia"
1691
1991
  ZW = "Zimbabwe"
1992
+ # Adding missing country codes
1993
+ EH = "Western Sahara"
1994
+ IM = "Isle of Man"
1995
+ BL = "Saint Barthelemy"
1996
+ MF = "Saint Martin"
1997
+ SX = "Sint Maarten"
1998
+ XK = "Kosovo"
1692
1999
 
1693
2000
 
1694
2001
  class CountryCurrency(utils.Enum):
2002
+ AC = "USD"
1695
2003
  AD = "EUR"
1696
2004
  AE = "AED"
1697
2005
  AF = "USD"
@@ -2419,3 +2727,240 @@ class EUCountry(utils.Enum):
2419
2727
  SK = "Slovakia"
2420
2728
  ES = "Spain"
2421
2729
  SE = "Sweden"
2730
+
2731
+
2732
+ class CountryCode(utils.Enum):
2733
+ AD = "AND" # Andorra
2734
+ AE = "ARE" # United Arab Emirates
2735
+ AF = "AFG" # Afghanistan
2736
+ AG = "ATG" # Antigua
2737
+ AI = "AIA" # Anguilla
2738
+ AL = "ALB" # Albania
2739
+ AM = "ARM" # Armenia
2740
+ AN = "ANT" # Netherlands Antilles
2741
+ AO = "AGO" # Angola
2742
+ AR = "ARG" # Argentina
2743
+ AS = "ASM" # American Samoa
2744
+ AT = "AUT" # Austria
2745
+ AU = "AUS" # Australia
2746
+ AW = "ABW" # Aruba
2747
+ AZ = "AZE" # Azerbaijan
2748
+ BA = "BIH" # Bosnia And Herzegovina
2749
+ BB = "BRB" # Barbados
2750
+ BD = "BGD" # Bangladesh
2751
+ BE = "BEL" # Belgium
2752
+ BF = "BFA" # Burkina Faso
2753
+ BG = "BGR" # Bulgaria
2754
+ BH = "BHR" # Bahrain
2755
+ BI = "BDI" # Burundi
2756
+ BJ = "BEN" # Benin
2757
+ BM = "BMU" # Bermuda
2758
+ BN = "BRN" # Brunei
2759
+ BO = "BOL" # Bolivia
2760
+ BR = "BRA" # Brazil
2761
+ BS = "BHS" # Bahamas
2762
+ BT = "BTN" # Bhutan
2763
+ BW = "BWA" # Botswana
2764
+ BY = "BLR" # Belarus
2765
+ BZ = "BLZ" # Belize
2766
+ CA = "CAN" # Canada
2767
+ CD = "COD" # Congo, Democratic Republic of the
2768
+ CF = "CAF" # Central African Republic
2769
+ CG = "COG" # Congo
2770
+ CH = "CHE" # Switzerland
2771
+ CI = "CIV" # Cote D Ivoire
2772
+ CK = "COK" # Cook Islands
2773
+ CL = "CHL" # Chile
2774
+ CM = "CMR" # Cameroon
2775
+ CN = "CHN" # China
2776
+ CO = "COL" # Colombia
2777
+ CR = "CRI" # Costa Rica
2778
+ CU = "CUB" # Cuba
2779
+ CV = "CPV" # Cape Verde
2780
+ CY = "CYP" # Cyprus
2781
+ CZ = "CZE" # Czech Republic
2782
+ DE = "DEU" # Germany
2783
+ DJ = "DJI" # Djibouti
2784
+ DK = "DNK" # Denmark
2785
+ DM = "DMA" # Dominica
2786
+ DO = "DOM" # Dominican Republic
2787
+ DZ = "DZA" # Algeria
2788
+ EC = "ECU" # Ecuador
2789
+ EE = "EST" # Estonia
2790
+ EG = "EGY" # Egypt
2791
+ ER = "ERI" # Eritrea
2792
+ ES = "ESP" # Spain
2793
+ ET = "ETH" # Ethiopia
2794
+ FI = "FIN" # Finland
2795
+ FJ = "FJI" # Fiji
2796
+ FK = "FLK" # Falkland Islands
2797
+ FM = "FSM" # Micronesia, Federated States Of
2798
+ FO = "FRO" # Faroe Islands
2799
+ FR = "FRA" # France
2800
+ GA = "GAB" # Gabon
2801
+ GB = "GBR" # United Kingdom
2802
+ GD = "GRD" # Grenada
2803
+ GE = "GEO" # Georgia
2804
+ GF = "GUF" # French Guyana
2805
+ GG = "GGY" # Guernsey
2806
+ GH = "GHA" # Ghana
2807
+ GI = "GIB" # Gibraltar
2808
+ GL = "GRL" # Greenland
2809
+ GM = "GMB" # Gambia
2810
+ GN = "GIN" # Guinea Republic
2811
+ GP = "GLP" # Guadeloupe
2812
+ GQ = "GNQ" # Guinea-equatorial
2813
+ GR = "GRC" # Greece
2814
+ GT = "GTM" # Guatemala
2815
+ GU = "GUM" # Guam
2816
+ GW = "GNB" # Guinea-bissau
2817
+ GY = "GUY" # Guyana (british)
2818
+ HK = "HKG" # Hong Kong
2819
+ HN = "HND" # Honduras
2820
+ HR = "HRV" # Croatia
2821
+ HT = "HTI" # Haiti
2822
+ HU = "HUN" # Hungary
2823
+ IC = "ICA" # Canary Islands
2824
+ ID = "IDN" # Indonesia
2825
+ IE = "IRL" # Ireland
2826
+ IL = "ISR" # Israel
2827
+ IN = "IND" # India
2828
+ IQ = "IRQ" # Iraq
2829
+ IR = "IRN" # Iran
2830
+ IS = "ISL" # Iceland
2831
+ IT = "ITA" # Italy
2832
+ JE = "JEY" # Jersey
2833
+ JM = "JAM" # Jamaica
2834
+ JO = "JOR" # Jordan
2835
+ JP = "JPN" # Japan
2836
+ KE = "KEN" # Kenya
2837
+ KG = "KGZ" # Kyrgyzstan
2838
+ KH = "KHM" # Cambodia
2839
+ KI = "KIR" # Kiribati
2840
+ KM = "COM" # Comoros
2841
+ KN = "KNA" # St. Kitts
2842
+ KP = "PRK" # Korea, The D.p.r Of (north K.)
2843
+ KR = "KOR" # Korea, Republic of (South Korea)
2844
+ KV = "XKX" # Kosovo
2845
+ KW = "KWT" # Kuwait
2846
+ KY = "CYM" # Cayman Islands
2847
+ KZ = "KAZ" # Kazakhstan
2848
+ LA = "LAO" # Lao Peoples Democratic Republic
2849
+ LB = "LBN" # Lebanon
2850
+ LC = "LCA" # St. Lucia
2851
+ LI = "LIE" # Liechtenstein
2852
+ LK = "LKA" # Sri Lanka
2853
+ LR = "LBR" # Liberia
2854
+ LS = "LSO" # Lesotho
2855
+ LT = "LTU" # Lithuania
2856
+ LU = "LUX" # Luxembourg
2857
+ LV = "LVA" # Latvia
2858
+ LY = "LBY" # Libya
2859
+ MA = "MAR" # Morocco
2860
+ MC = "MCO" # Monaco
2861
+ MD = "MDA" # Moldova
2862
+ ME = "MNE" # Montenegro
2863
+ MG = "MDG" # Madagascar
2864
+ MH = "MHL" # Marshall Islands
2865
+ MK = "MKD" # Macedonia
2866
+ ML = "MLI" # Mali
2867
+ MM = "MMR" # Myanmar
2868
+ MN = "MNG" # Mongolia
2869
+ MO = "MAC" # Macau
2870
+ MP = "MNP" # Nothern Mariana Islands, Commonwealth of
2871
+ MQ = "MTQ" # Martinique
2872
+ MR = "MRT" # Mauritania
2873
+ MS = "MSR" # Montserrat
2874
+ MT = "MLT" # Malta
2875
+ MU = "MUS" # Mauritius
2876
+ MV = "MDV" # Maldives
2877
+ MW = "MWI" # Malawi
2878
+ MX = "MEX" # Mexico
2879
+ MY = "MYS" # Malaysia
2880
+ MZ = "MOZ" # Mozambique
2881
+ NA = "NAM" # Namibia
2882
+ NC = "NCL" # New Caledonia
2883
+ NE = "NER" # Niger
2884
+ NG = "NGA" # Nigeria
2885
+ NI = "NIC" # Nicaragua
2886
+ NL = "NLD" # Netherlands
2887
+ NO = "NOR" # Norway
2888
+ NP = "NPL" # Nepal
2889
+ NR = "NRU" # Nauru
2890
+ NU = "NIU" # Niue
2891
+ NZ = "NZL" # New Zealand
2892
+ OM = "OMN" # Oman
2893
+ PA = "PAN" # Panama
2894
+ PE = "PER" # Peru
2895
+ PF = "PYF" # Tahiti
2896
+ PG = "PNG" # Papua New Guinea
2897
+ PH = "PHL" # Philippines
2898
+ PK = "PAK" # Pakistan
2899
+ PL = "POL" # Poland
2900
+ PR = "PRI" # Puerto Rico
2901
+ PT = "PRT" # Portugal
2902
+ PW = "PLW" # Palau
2903
+ PY = "PRY" # Paraguay
2904
+ QA = "QAT" # Qatar
2905
+ RE = "REU" # Reunion
2906
+ RO = "ROU" # Romania
2907
+ RS = "SRB" # Serbia
2908
+ RU = "RUS" # Russia
2909
+ RW = "RWA" # Rwanda
2910
+ SA = "SAU" # Saudi Arabia
2911
+ SB = "SLB" # Solomon Islands
2912
+ SC = "SYC" # Seychelles
2913
+ SD = "SDN" # Sudan
2914
+ SE = "SWE" # Sweden
2915
+ SG = "SGP" # Singapore
2916
+ SH = "SHN" # Saint Helena
2917
+ SI = "SVN" # Slovenia
2918
+ SK = "SVK" # Slovakia
2919
+ SL = "SLE" # Sierra Leone
2920
+ SM = "SMR" # San Marino
2921
+ SN = "SEN" # Senegal
2922
+ SO = "SOM" # Somalia
2923
+ SR = "SUR" # Suriname
2924
+ SS = "SSD" # South Sudan
2925
+ ST = "STP" # Sao Tome And Principe
2926
+ SV = "SLV" # El Salvador
2927
+ SY = "SYR" # Syria
2928
+ SZ = "SWZ" # Swaziland
2929
+ TC = "TCA" # Turks And Caicos Islands
2930
+ TD = "TCD" # Chad
2931
+ TG = "TGO" # Togo
2932
+ TH = "THA" # Thailand
2933
+ TJ = "TJK" # Tajikistan
2934
+ TL = "TLS" # Timor Leste
2935
+ TN = "TUN" # Tunisia
2936
+ TO = "TON" # Tonga
2937
+ TR = "TUR" # Turkey
2938
+ TT = "TTO" # Trinidad And Tobago
2939
+ TV = "TUV" # Tuvalu
2940
+ TW = "TWN" # Taiwan
2941
+ TZ = "TZA" # Tanzania
2942
+ UA = "UKR" # Ukraine
2943
+ UG = "UGA" # Uganda
2944
+ US = "USA" # United States
2945
+ UY = "URY" # Uruguay
2946
+ UZ = "UZB" # Uzbekistan
2947
+ VA = "VAT" # Vatican City
2948
+ VC = "VCT" # St. Vincent
2949
+ VE = "VEN" # Venezuela
2950
+ VG = "VGB" # British Virgin Islands
2951
+ VI = "VIR" # U.S. Virgin Islands
2952
+ VN = "VNM" # Vietnam
2953
+ VU = "VUT" # Vanuatu
2954
+ WS = "WSM" # Samoa
2955
+ XB = "BES" # Bonaire
2956
+ XC = "CUW" # Curacao
2957
+ XE = "EUX" # St. Eustatius
2958
+ XM = "SXM" # St. Maarten
2959
+ XN = "KNA" # Nevis
2960
+ XS = "SOM" # Somaliland, Rep Of (north Somalia)
2961
+ XY = "BLM" # St. Barthelemy
2962
+ YE = "YEM" # Yemen
2963
+ YT = "MYT" # Mayotte
2964
+ ZA = "ZAF" # South Africa
2965
+ ZM = "ZMB" # Zambia
2966
+ ZW = "ZWE" # Zimbabwe