karrio-landmark 2025.5__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.
@@ -0,0 +1,477 @@
1
+ """Karrio Landmark Global shipment creation implementation."""
2
+
3
+ import karrio.schemas.landmark.import_request as import_req
4
+ import karrio.schemas.landmark.import_response as import_res
5
+ import karrio.schemas.landmark.ship_request as ship_req
6
+ import karrio.schemas.landmark.ship_response as ship_res
7
+
8
+ import typing
9
+ import karrio.lib as lib
10
+ import karrio.core.units as units
11
+ import karrio.core.models as models
12
+ import karrio.providers.landmark.error as error
13
+ import karrio.providers.landmark.utils as provider_utils
14
+ import karrio.providers.landmark.units as provider_units
15
+
16
+
17
+ def parse_shipment_response(
18
+ _response: lib.Deserializable[lib.Element],
19
+ settings: provider_utils.Settings,
20
+ ) -> typing.Tuple[models.ShipmentDetails, typing.List[models.Message]]:
21
+ response = _response.deserialize()
22
+ messages = error.parse_error_response(response, settings)
23
+
24
+ shipment = (
25
+ _extract_details(response, settings, ctx=_response.ctx)
26
+ if len(lib.find_element("TrackingNumber", response)) > 0
27
+ else None
28
+ )
29
+
30
+ return shipment, messages
31
+
32
+
33
+ def _extract_details(
34
+ data: lib.Element,
35
+ settings: provider_utils.Settings,
36
+ ctx: dict = dict(),
37
+ ) -> models.ShipmentDetails:
38
+ """Extract shipment details from ImportResponse or ShipResponse"""
39
+ # fmt: off
40
+ label_format = ctx.get("label_format", "PDF")
41
+ packages = lib.find_element("Package", data, ship_res.PackageType)
42
+ result = lib.find_element("Result", data, ship_res.ResultType, first=True)
43
+ label_images = lib.find_element("LabelImages", data, ship_res.LabelImagesType)
44
+
45
+ last_mile_carrier = getattr(result, "ShippingCarrier", None)
46
+ tracking_numbers = [_.LandmarkTrackingNumber for _ in packages if _.LandmarkTrackingNumber is not None]
47
+ last_mile_tracking_numbers = [_.TrackingNumber for _ in packages if _.TrackingNumber is not None]
48
+ package_references = [_.PackageReference for _ in packages if _.PackageReference is not None]
49
+ barcode_datas = [_.BarcodeData for _ in packages if _.BarcodeData is not None]
50
+ landmark_ids = [_.PackageID for _ in packages if _.PackageID is not None]
51
+
52
+ tracking_number = next(iter(tracking_numbers), None)
53
+ shipment_identifier = next(iter(landmark_ids), tracking_number)
54
+ last_mile_tracking_number = next(iter(last_mile_tracking_numbers), None) if last_mile_carrier else None
55
+ last_mile_tracking_numbers = last_mile_tracking_numbers if last_mile_carrier else []
56
+ shipment_identifiers = landmark_ids if len(landmark_ids) > 0 else tracking_numbers
57
+ label = (
58
+ lib.bundle_base64(
59
+ [_.LabelImage[0] for _ in label_images if len(_.LabelImage) > 0],
60
+ label_format,
61
+ )
62
+ if any(_.LabelImage for _ in label_images)
63
+ else ""
64
+ )
65
+ # fmt: on
66
+
67
+ return models.ShipmentDetails(
68
+ carrier_id=settings.carrier_id,
69
+ carrier_name=settings.carrier_name,
70
+ tracking_number=tracking_number,
71
+ shipment_identifier=shipment_identifier,
72
+ label_type=label_format,
73
+ docs=models.Documents(label=label),
74
+ meta=lib.to_dict(
75
+ dict(
76
+ last_mile_carrier=last_mile_carrier,
77
+ last_mile_tracking_number=last_mile_tracking_number,
78
+ last_mile_tracking_numbers=last_mile_tracking_numbers,
79
+ shipment_identifiers=shipment_identifiers,
80
+ package_references=package_references,
81
+ tracking_numbers=tracking_numbers,
82
+ barcode_datas=barcode_datas,
83
+ )
84
+ ),
85
+ )
86
+
87
+
88
+ def shipment_request(
89
+ payload: models.ShipmentRequest,
90
+ settings: provider_utils.Settings,
91
+ ) -> lib.Serializable:
92
+ """Create a shipment request for the carrier API"""
93
+ # Convert karrio models to carrier-specific format
94
+ shipper = lib.to_address(payload.shipper)
95
+ recipient = lib.to_address(payload.recipient)
96
+ return_address = lib.to_address(payload.return_address)
97
+ packages = lib.to_packages(payload.parcels)
98
+ service = provider_units.ShippingService.map(payload.service).value_or_key
99
+ options = lib.to_shipping_options(
100
+ payload.options,
101
+ package_options=packages.options,
102
+ initializer=provider_units.shipping_options_initializer,
103
+ )
104
+ weight_unit, dim_unit = packages.compatible_units
105
+
106
+ customs = lib.to_customs_info(
107
+ payload.customs,
108
+ shipper=payload.shipper,
109
+ recipient=payload.recipient,
110
+ weight_unit=weight_unit.value,
111
+ )
112
+ vendor = lib.to_address(
113
+ dict(
114
+ sender=payload.shipper,
115
+ recipient=payload.recipient,
116
+ third_party=customs.duty_billing_address,
117
+ )[customs.duty.paid_by]
118
+ )
119
+ label_format = lib.identity(
120
+ payload.label_type or settings.connection_config.label_type.state
121
+ )
122
+ label_encoding = "BASE64"
123
+ is_import_request = lib.identity(
124
+ options.landmark_import_request.state
125
+ if options.landmark_import_request.state is not None
126
+ else settings.connection_config.import_request_by_default.state
127
+ )
128
+ produce_label = lib.identity(
129
+ options.landmark_produce_label.state
130
+ if options.landmark_produce_label.state is not None
131
+ else (
132
+ settings.connection_config.impport_request_produce_label.state
133
+ if settings.connection_config.impport_request_produce_label.state
134
+ is not None
135
+ else False
136
+ )
137
+ )
138
+ items = lib.identity(customs.commodities if payload.customs else packages.items)
139
+
140
+ request = lib.identity(
141
+ import_req.ImportRequest(
142
+ Login=import_req.LoginType(
143
+ Username=settings.username,
144
+ Password=settings.password,
145
+ ),
146
+ Test=settings.test_mode,
147
+ ClientID=settings.client_id,
148
+ AccountNumber=settings.account_number,
149
+ Reference=payload.reference,
150
+ ShipTo=import_req.ShipToType(
151
+ Name=recipient.company_name or recipient.person_name or "",
152
+ Attention=recipient.person_name,
153
+ Address1=recipient.address_line1 or "",
154
+ Address2=recipient.address_line2,
155
+ Address3=None,
156
+ City=recipient.city or "",
157
+ State=lib.text(recipient.state_code, max=25) or "",
158
+ PostalCode=recipient.postal_code or "",
159
+ Country=recipient.country_code or "",
160
+ Phone=recipient.phone_number,
161
+ Email=recipient.email,
162
+ ConsigneeTaxID=recipient.tax_id,
163
+ ),
164
+ ShippingLane=import_req.ShippingLaneType(
165
+ Region=settings.region,
166
+ ),
167
+ ShipMethod=service,
168
+ OrderTotal=lib.identity(
169
+ customs.duty.declared_value or options.declared_value.state
170
+ ),
171
+ OrderInsuranceFreightTotal=options.landmark_order_insurance_freight_total.state,
172
+ ShipmentInsuranceFreight=options.landmark_shipment_insurance_freight.state,
173
+ ItemsCurrency=options.currency.state,
174
+ IsCommercialShipment=("1" if customs.commercial_invoice else "0"),
175
+ ProduceLabel=produce_label,
176
+ LabelFormat=label_format,
177
+ LabelEncoding=label_encoding,
178
+ ShipOptions=None,
179
+ VendorInformation=lib.identity(
180
+ import_req.VendorInformationType(
181
+ VendorName=vendor.company_name or vendor.person_name or "",
182
+ VendorPhone=vendor.phone_number or "",
183
+ VendorEmail=vendor.email or "",
184
+ VendorAddress1=vendor.address_line1 or "",
185
+ VendorAddress2=vendor.address_line2,
186
+ VendorCity=vendor.city or "",
187
+ VendorState=lib.text(vendor.state_code, max=25) or "",
188
+ VendorPostalCode=vendor.postal_code or "",
189
+ VendorCountry=vendor.country_code or "",
190
+ VendorLowValueTaxID=customs.options.low_value_tax_id.state,
191
+ VendorCCN=customs.options.ccn.state,
192
+ VendorBusinessNumber=customs.options.business_number.state,
193
+ VendorRGRNumber=customs.options.rgr_number.state,
194
+ VendorIOSSNumber=customs.options.ioss.state,
195
+ VendorEORINumber=customs.options.eori_number.state,
196
+ )
197
+ if payload.customs
198
+ else None
199
+ ),
200
+ FulfillmentAddress=import_req.FulfillmentAddressType(
201
+ Name=shipper.company_name or shipper.person_name or "",
202
+ Attention=shipper.person_name,
203
+ Address1=shipper.address_line1 or "",
204
+ Address2=shipper.address_line2,
205
+ Address3=None,
206
+ City=shipper.city or "",
207
+ State=lib.text(shipper.state_code, max=25) or "",
208
+ PostalCode=shipper.postal_code or "",
209
+ Country=shipper.country_code or "",
210
+ ),
211
+ ReturnAddress=lib.identity(
212
+ import_req.SendReturnToAddressType(
213
+ Code=options.landmark_return_address_code.state,
214
+ Name=return_address.company_name
215
+ or return_address.person_name
216
+ or "",
217
+ Attention=return_address.person_name,
218
+ Address1=return_address.address_line1 or "",
219
+ Address2=return_address.address_line2,
220
+ Address3=None,
221
+ City=return_address.city or "",
222
+ State=lib.text(return_address.state_code, max=25) or "",
223
+ PostalCode=return_address.postal_code or "",
224
+ Country=return_address.country_code or "",
225
+ )
226
+ if payload.return_address
227
+ else None
228
+ ),
229
+ AdditionalFields=None,
230
+ PickSlipAdditions=None,
231
+ ValueAddedServices=None,
232
+ Packages=lib.identity(
233
+ import_req.PackagesType(
234
+ Package=[
235
+ import_req.PackageType(
236
+ WeightUnit=weight_unit.value,
237
+ Weight=pkg.weight[weight_unit.value],
238
+ DimensionsUnit=dim_unit.value,
239
+ Length=pkg.length[dim_unit.value],
240
+ Width=pkg.width[dim_unit.value],
241
+ Height=pkg.height[dim_unit.value],
242
+ PackageReference=pkg.reference_number,
243
+ )
244
+ for pkg in packages
245
+ ]
246
+ )
247
+ if options.fulfilled_by_landmark.state is not True
248
+ else None
249
+ ),
250
+ Items=lib.identity(
251
+ import_req.ItemsType(
252
+ Item=[
253
+ import_req.ItemType(
254
+ Sku=item.sku or "",
255
+ LineNumber=item.metadata.get("LineNumber"),
256
+ Quantity=lib.to_int(item.quantity),
257
+ UnitPrice=lib.to_money(item.value_amount),
258
+ Description=item.description or item.title or "",
259
+ HSCode=item.hs_code,
260
+ CountryOfOrigin=item.origin_country,
261
+ URL=item.product_url,
262
+ USMID=item.metadata.get("USMID"),
263
+ ContentCategory=import_req.ContentCategoryType(
264
+ ReturnCustomsInfo=lib.identity(
265
+ import_req.ReturnCustomsInfoType(
266
+ HSCode=item.hs_code,
267
+ HSRegionCode=item.origin_country,
268
+ )
269
+ if item.hs_code or item.origin_country
270
+ else None
271
+ ),
272
+ DangerousGoodsInformation=lib.identity(
273
+ import_req.DangerousGoodsInformationType(
274
+ UNCode=item.metadata.get("UNCode"),
275
+ PackingGroup=item.metadata.get("PackingGroup"),
276
+ PackingInstructions=item.metadata.get(
277
+ "PackingInstructions"
278
+ ),
279
+ ItemWeight=item.weight,
280
+ ItemWeightUnit=(
281
+ item.weight_unit.lower()
282
+ if item.weight_unit
283
+ else None
284
+ ),
285
+ ItemVolume=item.metadata.get("ItemVolume"),
286
+ ItemVolumeUnit=item.metadata.get(
287
+ "ItemVolumeUnit"
288
+ ),
289
+ )
290
+ if options.dangerous_goods.state
291
+ else None
292
+ ),
293
+ ValueAddedServices=None,
294
+ ),
295
+ )
296
+ for item in items
297
+ ]
298
+ )
299
+ if len(items) > 0
300
+ else None
301
+ ),
302
+ FreightDetails=lib.identity(
303
+ import_req.FreightDetailsType(
304
+ ProNumber=options.landmark_freight_pro_number.state or "",
305
+ PieceUnit=options.landmark_freight_piece_unit.state or "",
306
+ )
307
+ if options.landmark_freight_pro_number.state
308
+ and options.landmark_freight_piece_unit.state
309
+ else None
310
+ ),
311
+ )
312
+ if is_import_request
313
+ else ship_req.ShipRequest(
314
+ Login=ship_req.LoginType(
315
+ Username=settings.username,
316
+ Password=settings.password,
317
+ ),
318
+ Test=settings.test_mode,
319
+ ClientID=settings.client_id,
320
+ AccountNumber=settings.account_number,
321
+ Reference=payload.reference,
322
+ ShipTo=ship_req.ShipToType(
323
+ Name=recipient.company_name or recipient.person_name or "",
324
+ Attention=recipient.person_name,
325
+ Address1=recipient.address_line1 or "",
326
+ Address2=recipient.address_line2,
327
+ Address3=None,
328
+ City=recipient.city or "",
329
+ State=lib.text(recipient.state_code, max=25) or "",
330
+ PostalCode=recipient.postal_code or "",
331
+ Country=recipient.country_code or "",
332
+ Phone=recipient.phone_number,
333
+ Email=recipient.email,
334
+ ConsigneeTaxID=recipient.tax_id,
335
+ ),
336
+ ShippingLane=lib.identity(
337
+ ship_req.ShippingLaneType(Region=settings.region)
338
+ if settings.region
339
+ else None
340
+ ),
341
+ ShipMethod=service,
342
+ OrderTotal=lib.identity(
343
+ customs.duty.declared_value
344
+ if customs.duty and customs.duty.declared_value
345
+ else options.declared_value.state
346
+ ),
347
+ OrderInsuranceFreightTotal=options.landmark_order_insurance_freight_total.state,
348
+ ShipmentInsuranceFreight=options.landmark_shipment_insurance_freight.state,
349
+ ItemsCurrency=options.currency.state,
350
+ IsCommercialShipment="1" if customs.commercial_invoice else "0",
351
+ LabelFormat=label_format,
352
+ LabelDPI=("300" if label_format == "ZPL" else None),
353
+ LabelEncoding=label_encoding,
354
+ ShipOptions=None,
355
+ VendorInformation=lib.identity(
356
+ ship_req.VendorInformationType(
357
+ VendorName=vendor.company_name or vendor.person_name or "",
358
+ VendorPhone=vendor.phone_number or "",
359
+ VendorEmail=vendor.email or "",
360
+ VendorAddress1=vendor.address_line1 or "",
361
+ VendorAddress2=vendor.address_line2,
362
+ VendorCity=vendor.city or "",
363
+ VendorState=lib.text(vendor.state_code, max=25) or "",
364
+ VendorPostalCode=vendor.postal_code or "",
365
+ VendorCountry=vendor.country_code or "",
366
+ VendorLowValueTaxID=customs.options.low_value_tax_id.state,
367
+ VendorCCN=customs.options.ccn.state,
368
+ VendorBusinessNumber=customs.options.business_number.state,
369
+ VendorRGRNumber=customs.options.rgr_number.state,
370
+ VendorIOSSNumber=customs.options.ioss.state,
371
+ VendorEORINumber=customs.options.eori_number.state,
372
+ )
373
+ if payload.customs
374
+ else None
375
+ ),
376
+ ReturnInformation=None,
377
+ FulfillmentAddress=ship_req.FulfillmentAddressType(
378
+ Name=shipper.company_name or shipper.person_name or "",
379
+ Attention=shipper.person_name,
380
+ Address1=shipper.address_line1 or "",
381
+ Address2=shipper.address_line2,
382
+ Address3=None,
383
+ City=shipper.city or "",
384
+ State=lib.text(shipper.state_code, max=25) or "",
385
+ PostalCode=shipper.postal_code or "",
386
+ Country=shipper.country_code or "",
387
+ ),
388
+ SendReturnToAddress=lib.identity(
389
+ ship_req.SendReturnToAddressType(
390
+ Code=options.landmark_return_address_code.state,
391
+ Name=return_address.company_name
392
+ or return_address.person_name
393
+ or "",
394
+ Attention=return_address.person_name,
395
+ Address1=return_address.address_line1 or "",
396
+ Address2=return_address.address_line2,
397
+ Address3=None,
398
+ City=return_address.city or "",
399
+ State=lib.text(return_address.state_code, max=25) or "",
400
+ PostalCode=return_address.postal_code or "",
401
+ Country=return_address.country_code or "",
402
+ )
403
+ if payload.return_address
404
+ else None
405
+ ),
406
+ AdditionalFields=None,
407
+ Packages=lib.identity(
408
+ ship_req.PackagesType(
409
+ Package=[
410
+ ship_req.PackageType(
411
+ WeightUnit=pkg.weight_unit.value,
412
+ Weight=pkg.weight[weight_unit.value],
413
+ DimensionsUnit=dim_unit.value,
414
+ Length=pkg.length[dim_unit.value],
415
+ Width=pkg.width[dim_unit.value],
416
+ Height=pkg.height[dim_unit.value],
417
+ PackageReference=pkg.parcel.reference_number,
418
+ )
419
+ for pkg in packages
420
+ ]
421
+ )
422
+ if options.fulfilled_by_landmark.state is not True
423
+ else None
424
+ ),
425
+ Items=lib.identity(
426
+ ship_req.ItemsType(
427
+ Item=[
428
+ ship_req.ItemType(
429
+ Sku=item.sku or "",
430
+ LineNumber=item.metadata.get("LineNumber"),
431
+ Quantity=item.quantity,
432
+ UnitPrice=item.value_amount,
433
+ Description=item.description or item.title or "",
434
+ HSCode=item.hs_code,
435
+ CountryOfOrigin=item.origin_country,
436
+ ContentCategory=item.category,
437
+ URL=item.product_url,
438
+ USMID=item.metadata.get("USMID"),
439
+ ReturnCustomsInfo=lib.identity(
440
+ ship_req.ReturnCustomsInfoType(
441
+ HSCode=item.hs_code,
442
+ HSRegionCode=item.origin_country,
443
+ )
444
+ if item.hs_code or item.origin_country
445
+ else None
446
+ ),
447
+ DangerousGoodsInformation=None,
448
+ )
449
+ for item in items
450
+ ]
451
+ )
452
+ if len(items) > 0
453
+ else None
454
+ ),
455
+ FreightDetails=lib.identity(
456
+ ship_req.FreightDetailsType(
457
+ ProNumber=options.landmark_freight_pro_number.state or "",
458
+ PieceUnit=options.landmark_freight_piece_unit.state or "",
459
+ )
460
+ if options.landmark_freight_pro_number.state
461
+ and options.landmark_freight_piece_unit.state
462
+ else None
463
+ ),
464
+ )
465
+ )
466
+
467
+ return lib.Serializable(
468
+ request,
469
+ lib.to_xml,
470
+ ctx=dict(
471
+ API=("Import" if is_import_request else "Ship"),
472
+ label_format=label_format,
473
+ label_encoding=label_encoding,
474
+ is_import_request=is_import_request,
475
+ produce_label=(produce_label if is_import_request else None),
476
+ ),
477
+ )
@@ -0,0 +1,139 @@
1
+ """Karrio Landmark Global tracking API implementation."""
2
+
3
+ import karrio.schemas.landmark.track_request as landmark_req
4
+ import karrio.schemas.landmark.track_response as landmark_res
5
+
6
+ import typing
7
+ import karrio.lib as lib
8
+ import karrio.core.models as models
9
+ import karrio.providers.landmark.error as error
10
+ import karrio.providers.landmark.utils as provider_utils
11
+ import karrio.providers.landmark.units as provider_units
12
+
13
+
14
+ # Supported datetime formats for Landmark Global
15
+ DATETIME_FORMATS = [
16
+ "%m/%d/%Y %I:%M %p", # 10/01/2025 03:02 PM
17
+ "%-m/%d/%Y %I:%M %p", # 0/01/2025 03:03 PM (single digit month)
18
+ "%Y-%m-%d %H:%M:%S", # 2019-01-01 13:21:45
19
+ ]
20
+
21
+
22
+ def parse_tracking_response(
23
+ _response: lib.Deserializable[typing.List[typing.Tuple[str, lib.Element]]],
24
+ settings: provider_utils.Settings,
25
+ ) -> typing.Tuple[typing.List[models.TrackingDetails], typing.List[models.Message]]:
26
+ responses = _response.deserialize()
27
+
28
+ messages: typing.List[models.Message] = sum(
29
+ [
30
+ error.parse_error_response(
31
+ response, settings, tracking_number=tracking_number
32
+ )
33
+ for tracking_number, response in responses
34
+ ],
35
+ start=[],
36
+ )
37
+
38
+ tracking_details = [
39
+ _extract_details(details, settings)
40
+ for _, details in responses
41
+ if len(lib.find_element("TrackingNumber", details)) > 0
42
+ ]
43
+
44
+ return tracking_details, messages
45
+
46
+
47
+ def _extract_details(
48
+ data: lib.Element,
49
+ settings: provider_utils.Settings,
50
+ ) -> models.TrackingDetails:
51
+ """Extract tracking details from carrier response data"""
52
+
53
+ details = lib.find_element(
54
+ "ShipmentDetails", data, landmark_res.ShipmentDetailsType, first=True
55
+ )
56
+ package = lib.find_element("Package", data, landmark_res.PackageType, first=True)
57
+
58
+ # Transform events to TrackingEvent models
59
+ tracking_events = lib.sort_events(
60
+ [
61
+ models.TrackingEvent(
62
+ date=lib.fdate(event.DateTime, try_formats=DATETIME_FORMATS),
63
+ time=lib.flocaltime(
64
+ event.DateTime,
65
+ output_format="%I:%M %p",
66
+ try_formats=DATETIME_FORMATS,
67
+ ),
68
+ description=event.Status,
69
+ code=event.EventCode,
70
+ location=event.Location,
71
+ )
72
+ for event in package.Events.Event
73
+ ]
74
+ )
75
+
76
+ # Determine status based on the most recent event
77
+ latest_event = tracking_events[0] if tracking_events else None
78
+ status = next(
79
+ (
80
+ status.name
81
+ for status in list(provider_units.TrackingStatus)
82
+ if latest_event and latest_event.code in status.value
83
+ ),
84
+ provider_units.TrackingStatus.in_transit.name,
85
+ )
86
+
87
+ return models.TrackingDetails(
88
+ carrier_id=settings.carrier_id,
89
+ carrier_name=settings.carrier_name,
90
+ tracking_number=package.LandmarkTrackingNumber,
91
+ events=tracking_events,
92
+ delivered=status == "delivered",
93
+ status=status,
94
+ info=models.TrackingInfo(
95
+ carrier_tracking_link=settings.tracking_url.format(
96
+ package.LandmarkTrackingNumber
97
+ ),
98
+ ),
99
+ meta=lib.to_dict(
100
+ dict(
101
+ last_mile_tracking_number=package.TrackingNumber,
102
+ last_mile_carrier=lib.identity(
103
+ "landmark"
104
+ if "routed" in details.EndDeliveryCarrier.lower()
105
+ else details.EndDeliveryCarrier
106
+ ),
107
+ )
108
+ ),
109
+ )
110
+
111
+
112
+ def tracking_request(
113
+ payload: models.TrackingRequest,
114
+ settings: provider_utils.Settings,
115
+ ) -> lib.Serializable:
116
+ """Create tracking requests for the carrier API"""
117
+ # Create a request for each tracking number
118
+ requests = [
119
+ landmark_req.TrackRequest(
120
+ Login=landmark_req.LoginType(
121
+ Username=settings.username,
122
+ Password=settings.password,
123
+ ),
124
+ Test=settings.test_mode,
125
+ ClientID=settings.client_id,
126
+ Reference=payload.reference,
127
+ TrackingNumber=tracking_number,
128
+ PackageReference=None,
129
+ RetrievalType="Historical",
130
+ )
131
+ for tracking_number in payload.tracking_numbers
132
+ ]
133
+
134
+ return lib.Serializable(
135
+ requests,
136
+ lambda __: [
137
+ lib.typed(number=_.TrackingNumber, request=lib.to_xml(_)) for _ in __
138
+ ],
139
+ )