ordercloud-python 2026.4.1__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.
Files changed (114) hide show
  1. ordercloud/__init__.py +37 -0
  2. ordercloud/auth.py +136 -0
  3. ordercloud/client.py +211 -0
  4. ordercloud/config.py +42 -0
  5. ordercloud/errors.py +47 -0
  6. ordercloud/http.py +218 -0
  7. ordercloud/middleware.py +66 -0
  8. ordercloud/models/__init__.py +271 -0
  9. ordercloud/models/address.py +47 -0
  10. ordercloud/models/api_client.py +116 -0
  11. ordercloud/models/approval.py +73 -0
  12. ordercloud/models/assignments.py +402 -0
  13. ordercloud/models/auth_models.py +114 -0
  14. ordercloud/models/bundle.py +31 -0
  15. ordercloud/models/buyer.py +271 -0
  16. ordercloud/models/catalog.py +33 -0
  17. ordercloud/models/category.py +35 -0
  18. ordercloud/models/cost_center.py +27 -0
  19. ordercloud/models/credit_card.py +35 -0
  20. ordercloud/models/delivery.py +277 -0
  21. ordercloud/models/discount.py +63 -0
  22. ordercloud/models/integration.py +76 -0
  23. ordercloud/models/inventory_record.py +53 -0
  24. ordercloud/models/line_item.py +95 -0
  25. ordercloud/models/line_item_types.py +89 -0
  26. ordercloud/models/message_sender.py +80 -0
  27. ordercloud/models/misc.py +280 -0
  28. ordercloud/models/open_id_connect.py +47 -0
  29. ordercloud/models/order.py +477 -0
  30. ordercloud/models/order_return.py +92 -0
  31. ordercloud/models/payment.py +77 -0
  32. ordercloud/models/price_schedule.py +76 -0
  33. ordercloud/models/product.py +227 -0
  34. ordercloud/models/product_collection.py +186 -0
  35. ordercloud/models/promotion.py +297 -0
  36. ordercloud/models/security.py +89 -0
  37. ordercloud/models/shared.py +131 -0
  38. ordercloud/models/shipment.py +150 -0
  39. ordercloud/models/spec.py +67 -0
  40. ordercloud/models/spending_account.py +33 -0
  41. ordercloud/models/subscription.py +125 -0
  42. ordercloud/models/supplier.py +43 -0
  43. ordercloud/models/sync.py +172 -0
  44. ordercloud/models/user.py +207 -0
  45. ordercloud/models/user_group.py +27 -0
  46. ordercloud/models/webhook.py +58 -0
  47. ordercloud/py.typed +0 -0
  48. ordercloud/resources/__init__.py +65 -0
  49. ordercloud/resources/addresses.py +228 -0
  50. ordercloud/resources/admin_addresses.py +128 -0
  51. ordercloud/resources/admin_user_groups.py +185 -0
  52. ordercloud/resources/admin_users.py +150 -0
  53. ordercloud/resources/api_clients.py +308 -0
  54. ordercloud/resources/approval_rules.py +144 -0
  55. ordercloud/resources/base.py +145 -0
  56. ordercloud/resources/bundle_line_items.py +59 -0
  57. ordercloud/resources/bundle_subscription_items.py +54 -0
  58. ordercloud/resources/bundles.py +278 -0
  59. ordercloud/resources/buyer_groups.py +128 -0
  60. ordercloud/resources/buyers.py +164 -0
  61. ordercloud/resources/cart.py +613 -0
  62. ordercloud/resources/catalogs.py +311 -0
  63. ordercloud/resources/categories.py +392 -0
  64. ordercloud/resources/cost_centers.py +222 -0
  65. ordercloud/resources/credit_cards.py +227 -0
  66. ordercloud/resources/delivery_configurations.py +132 -0
  67. ordercloud/resources/discounts.py +201 -0
  68. ordercloud/resources/entity_syncs.py +534 -0
  69. ordercloud/resources/error_configs.py +71 -0
  70. ordercloud/resources/forgotten_credentials.py +74 -0
  71. ordercloud/resources/group_orders.py +28 -0
  72. ordercloud/resources/impersonation_configs.py +132 -0
  73. ordercloud/resources/incrementors.py +128 -0
  74. ordercloud/resources/integration_events.py +203 -0
  75. ordercloud/resources/inventory_integrations.py +65 -0
  76. ordercloud/resources/inventory_records.py +484 -0
  77. ordercloud/resources/line_items.py +262 -0
  78. ordercloud/resources/locales.py +203 -0
  79. ordercloud/resources/me.py +1882 -0
  80. ordercloud/resources/message_senders.py +261 -0
  81. ordercloud/resources/open_id_connects.py +128 -0
  82. ordercloud/resources/order_returns.py +306 -0
  83. ordercloud/resources/order_syncs.py +65 -0
  84. ordercloud/resources/orders.py +689 -0
  85. ordercloud/resources/payments.py +176 -0
  86. ordercloud/resources/price_schedules.py +164 -0
  87. ordercloud/resources/product_collections.py +116 -0
  88. ordercloud/resources/product_facets.py +128 -0
  89. ordercloud/resources/product_syncs.py +76 -0
  90. ordercloud/resources/products.py +454 -0
  91. ordercloud/resources/promotion_integrations.py +65 -0
  92. ordercloud/resources/promotions.py +203 -0
  93. ordercloud/resources/security_profiles.py +222 -0
  94. ordercloud/resources/seller_approval_rules.py +128 -0
  95. ordercloud/resources/shipments.py +256 -0
  96. ordercloud/resources/specs.py +313 -0
  97. ordercloud/resources/spending_accounts.py +227 -0
  98. ordercloud/resources/subscription_integrations.py +65 -0
  99. ordercloud/resources/subscription_items.py +146 -0
  100. ordercloud/resources/subscriptions.py +128 -0
  101. ordercloud/resources/supplier_addresses.py +144 -0
  102. ordercloud/resources/supplier_user_groups.py +210 -0
  103. ordercloud/resources/supplier_users.py +170 -0
  104. ordercloud/resources/suppliers.py +190 -0
  105. ordercloud/resources/tracking_events.py +130 -0
  106. ordercloud/resources/user_groups.py +210 -0
  107. ordercloud/resources/users.py +254 -0
  108. ordercloud/resources/webhooks.py +128 -0
  109. ordercloud/resources/xp_indices.py +77 -0
  110. ordercloud/sync_client.py +170 -0
  111. ordercloud_python-2026.4.1.dist-info/METADATA +552 -0
  112. ordercloud_python-2026.4.1.dist-info/RECORD +114 -0
  113. ordercloud_python-2026.4.1.dist-info/WHEEL +4 -0
  114. ordercloud_python-2026.4.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,689 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud Orders API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Optional, Union
7
+
8
+ from ..models.address import Address
9
+ from ..models.misc import OrderDirection, SearchType
10
+ from ..models.order import Order, OrderApproval, OrderApprovalInfo, OrderPromotion, OrderSplitResult
11
+ from ..models.promotion import EligiblePromotion, RefreshPromosResponse
12
+ from ..models.shipment import Shipment
13
+ from ..models.user import User
14
+ from ..models.shared import ListPage
15
+ from .base import BaseResource
16
+
17
+ __all__ = ["OrdersResource"]
18
+
19
+
20
+ class OrdersResource(BaseResource):
21
+ """Operations on OrderCloud Orders."""
22
+
23
+ async def list(
24
+ self,
25
+ direction: OrderDirection,
26
+ *,
27
+ buyer_id: Optional[str] = None,
28
+ supplier_id: Optional[str] = None,
29
+ from_: Optional[str] = None,
30
+ to: Optional[str] = None,
31
+ search: Optional[str] = None,
32
+ search_on: Optional[str] = None,
33
+ search_type: Optional[SearchType] = None,
34
+ sort_by: Optional[str] = None,
35
+ page: Optional[int] = None,
36
+ page_size: Optional[int] = None,
37
+ filters: Optional[dict[str, Any]] = None,
38
+ ) -> ListPage[Order]:
39
+ """List orders
40
+
41
+ Args:
42
+ direction: Direction of the order, from the current user's perspective.
43
+ buyer_id: ID of the buyer.
44
+ supplier_id: ID of the supplier.
45
+ from_: Lower bound of date range that the order was created.
46
+ to: Upper bound of date range that the order was created.
47
+ search: Word or phrase to search for.
48
+ search_on: Comma-delimited list of fields to search on.
49
+ search_type: Type of search to perform.
50
+ sort_by: Comma-delimited list of fields to sort by.
51
+ page: Page of results to return. When paginating through many items (> page 30), we recommend the "Last ID" method, as outlined in the Advanced Querying documentation.
52
+ page_size: Number of results to return per page.
53
+ filters: An object or dictionary representing key/value pairs to apply as filters. Valid keys are top-level properties of the returned model or 'xp.???'
54
+
55
+ Returns:
56
+ A paginated list of Order objects.
57
+ """
58
+ params = self._build_list_params(
59
+ search=search,
60
+ search_on=search_on,
61
+ sort_by=sort_by,
62
+ page=page,
63
+ page_size=page_size,
64
+ filters=filters,
65
+ )
66
+ if buyer_id is not None:
67
+ params["buyerID"] = buyer_id
68
+ if supplier_id is not None:
69
+ params["supplierID"] = supplier_id
70
+ if from_ is not None:
71
+ params["from"] = from_
72
+ if to is not None:
73
+ params["to"] = to
74
+ if search_type is not None:
75
+ params["searchType"] = search_type
76
+ resp = await self._http.get(f"/orders/{direction}", **params)
77
+ return self._parse_list(resp.json(), Order)
78
+
79
+ async def create(
80
+ self,
81
+ direction: OrderDirection,
82
+ order: Union[Order, dict[str, Any]],
83
+ ) -> Order:
84
+ """Create an order
85
+
86
+ Args:
87
+ direction: Direction of the order, from the current user's perspective.
88
+ order: A ``Order`` model or dict.
89
+
90
+ Returns:
91
+ The Order object.
92
+ """
93
+ resp = await self._http.post(f"/orders/{direction}", json=self._serialize(order))
94
+ return Order(**resp.json())
95
+
96
+ async def get(
97
+ self,
98
+ direction: OrderDirection,
99
+ order_id: str,
100
+ ) -> Order:
101
+ """Retrieve an order
102
+
103
+ Args:
104
+ direction: Direction of the order, from the current user's perspective.
105
+ order_id: ID of the order.
106
+
107
+ Returns:
108
+ The Order object.
109
+ """
110
+ resp = await self._http.get(f"/orders/{direction}/{order_id}")
111
+ return Order(**resp.json())
112
+
113
+ async def save(
114
+ self,
115
+ direction: OrderDirection,
116
+ order_id: str,
117
+ order: Union[Order, dict[str, Any]],
118
+ ) -> Order:
119
+ """Create or update an order
120
+
121
+ Args:
122
+ direction: Direction of the order, from the current user's perspective.
123
+ order_id: ID of the order.
124
+ order: A ``Order`` model or dict.
125
+
126
+ Returns:
127
+ The Order object.
128
+ """
129
+ resp = await self._http.put(
130
+ f"/orders/{direction}/{order_id}",
131
+ json=self._serialize(order),
132
+ )
133
+ return Order(**resp.json())
134
+
135
+ async def delete(
136
+ self,
137
+ direction: OrderDirection,
138
+ order_id: str,
139
+ ) -> None:
140
+ """Delete an order
141
+
142
+ Args:
143
+ direction: Direction of the order, from the current user's perspective.
144
+ order_id: ID of the order.
145
+ """
146
+ await self._http.delete(f"/orders/{direction}/{order_id}")
147
+
148
+ async def patch(
149
+ self,
150
+ direction: OrderDirection,
151
+ order_id: str,
152
+ partial: dict[str, Any],
153
+ ) -> Order:
154
+ """Partially update an order
155
+
156
+ Args:
157
+ direction: Direction of the order, from the current user's perspective.
158
+ order_id: ID of the order.
159
+ partial: A dict of fields to update.
160
+
161
+ Returns:
162
+ The Order object.
163
+ """
164
+ resp = await self._http.patch(f"/orders/{direction}/{order_id}", json=partial)
165
+ return Order(**resp.json())
166
+
167
+ async def apply_promotions(
168
+ self,
169
+ direction: OrderDirection,
170
+ order_id: str,
171
+ ) -> Order:
172
+ """Auto-apply promotions to an order
173
+
174
+ Args:
175
+ direction: Direction of the order, from the current user's perspective.
176
+ order_id: ID of the order.
177
+
178
+ Returns:
179
+ The Order object.
180
+ """
181
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/applypromotions")
182
+ return Order(**resp.json())
183
+
184
+ async def list_approvals(
185
+ self,
186
+ direction: OrderDirection,
187
+ order_id: str,
188
+ *,
189
+ search: Optional[str] = None,
190
+ search_on: Optional[str] = None,
191
+ sort_by: Optional[str] = None,
192
+ page: Optional[int] = None,
193
+ page_size: Optional[int] = None,
194
+ filters: Optional[dict[str, Any]] = None,
195
+ ) -> ListPage[OrderApproval]:
196
+ """List order approvals
197
+
198
+ Args:
199
+ direction: Direction of the order, from the current user's perspective.
200
+ order_id: ID of the order.
201
+ search: Word or phrase to search for.
202
+ search_on: Comma-delimited list of fields to search on.
203
+ sort_by: Comma-delimited list of fields to sort by.
204
+ page: Page of results to return. When paginating through many items (> page 30), we recommend the "Last ID" method, as outlined in the Advanced Querying documentation.
205
+ page_size: Number of results to return per page.
206
+ filters: An object or dictionary representing key/value pairs to apply as filters. Valid keys are top-level properties of the returned model or 'xp.???'
207
+
208
+ Returns:
209
+ A paginated list of OrderApproval objects.
210
+ """
211
+ params = self._build_list_params(
212
+ search=search,
213
+ search_on=search_on,
214
+ sort_by=sort_by,
215
+ page=page,
216
+ page_size=page_size,
217
+ filters=filters,
218
+ )
219
+ resp = await self._http.get(f"/orders/{direction}/{order_id}/approvals", **params)
220
+ return self._parse_list(resp.json(), OrderApproval)
221
+
222
+ async def approve(
223
+ self,
224
+ direction: OrderDirection,
225
+ order_id: str,
226
+ order_approval_info: Union[OrderApprovalInfo, dict[str, Any]],
227
+ ) -> Order:
228
+ """Approve an order
229
+
230
+ Args:
231
+ direction: Direction of the order, from the current user's perspective.
232
+ order_id: ID of the order.
233
+ order_approval_info: A ``OrderApprovalInfo`` model or dict.
234
+
235
+ Returns:
236
+ The Order object.
237
+ """
238
+ resp = await self._http.post(
239
+ f"/orders/{direction}/{order_id}/approve", json=self._serialize(order_approval_info)
240
+ )
241
+ return Order(**resp.json())
242
+
243
+ async def set_billing_address(
244
+ self,
245
+ direction: OrderDirection,
246
+ order_id: str,
247
+ address: Union[Address, dict[str, Any]],
248
+ ) -> Order:
249
+ """Set a billing address
250
+
251
+ Args:
252
+ direction: Direction of the order, from the current user's perspective.
253
+ order_id: ID of the order.
254
+ address: A ``Address`` model or dict. Required fields: Street1, City, Country.
255
+
256
+ Returns:
257
+ The Order object.
258
+ """
259
+ resp = await self._http.put(
260
+ f"/orders/{direction}/{order_id}/billto",
261
+ json=self._serialize(address),
262
+ )
263
+ return Order(**resp.json())
264
+
265
+ async def patch_billing_address(
266
+ self,
267
+ direction: OrderDirection,
268
+ order_id: str,
269
+ partial: dict[str, Any],
270
+ ) -> Order:
271
+ """Partially update an order billing address
272
+
273
+ Args:
274
+ direction: Direction of the order, from the current user's perspective.
275
+ order_id: ID of the order.
276
+ partial: A dict of fields to update.
277
+
278
+ Returns:
279
+ The Order object.
280
+ """
281
+ resp = await self._http.patch(f"/orders/{direction}/{order_id}/billto", json=partial)
282
+ return Order(**resp.json())
283
+
284
+ async def cancel(
285
+ self,
286
+ direction: OrderDirection,
287
+ order_id: str,
288
+ ) -> Order:
289
+ """Cancel an order
290
+
291
+ Args:
292
+ direction: Direction of the order, from the current user's perspective.
293
+ order_id: ID of the order.
294
+
295
+ Returns:
296
+ The Order object.
297
+ """
298
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/cancel")
299
+ return Order(**resp.json())
300
+
301
+ async def complete(
302
+ self,
303
+ direction: OrderDirection,
304
+ order_id: str,
305
+ ) -> Order:
306
+ """Complete an order
307
+
308
+ Args:
309
+ direction: Direction of the order, from the current user's perspective.
310
+ order_id: ID of the order.
311
+
312
+ Returns:
313
+ The Order object.
314
+ """
315
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/complete")
316
+ return Order(**resp.json())
317
+
318
+ async def decline(
319
+ self,
320
+ direction: OrderDirection,
321
+ order_id: str,
322
+ order_approval_info: Union[OrderApprovalInfo, dict[str, Any]],
323
+ ) -> Order:
324
+ """Decline an order
325
+
326
+ Args:
327
+ direction: Direction of the order, from the current user's perspective.
328
+ order_id: ID of the order.
329
+ order_approval_info: A ``OrderApprovalInfo`` model or dict.
330
+
331
+ Returns:
332
+ The Order object.
333
+ """
334
+ resp = await self._http.post(
335
+ f"/orders/{direction}/{order_id}/decline", json=self._serialize(order_approval_info)
336
+ )
337
+ return Order(**resp.json())
338
+
339
+ async def list_eligible_approvers(
340
+ self,
341
+ direction: OrderDirection,
342
+ order_id: str,
343
+ *,
344
+ search: Optional[str] = None,
345
+ search_on: Optional[str] = None,
346
+ sort_by: Optional[str] = None,
347
+ page: Optional[int] = None,
348
+ page_size: Optional[int] = None,
349
+ filters: Optional[dict[str, Any]] = None,
350
+ ) -> ListPage[User]:
351
+ """List order eligible approvers
352
+
353
+ Args:
354
+ direction: Direction of the order, from the current user's perspective.
355
+ order_id: ID of the order.
356
+ search: Word or phrase to search for.
357
+ search_on: Comma-delimited list of fields to search on.
358
+ sort_by: Comma-delimited list of fields to sort by.
359
+ page: Page of results to return. When paginating through many items (> page 30), we recommend the "Last ID" method, as outlined in the Advanced Querying documentation.
360
+ page_size: Number of results to return per page.
361
+ filters: An object or dictionary representing key/value pairs to apply as filters. Valid keys are top-level properties of the returned model or 'xp.???'
362
+
363
+ Returns:
364
+ A paginated list of User objects.
365
+ """
366
+ params = self._build_list_params(
367
+ search=search,
368
+ search_on=search_on,
369
+ sort_by=sort_by,
370
+ page=page,
371
+ page_size=page_size,
372
+ filters=filters,
373
+ )
374
+ resp = await self._http.get(f"/orders/{direction}/{order_id}/eligibleapprovers", **params)
375
+ return self._parse_list(resp.json(), User)
376
+
377
+ async def list_eligible_promotions(
378
+ self,
379
+ direction: OrderDirection,
380
+ order_id: str,
381
+ *,
382
+ search: Optional[str] = None,
383
+ search_on: Optional[str] = None,
384
+ sort_by: Optional[str] = None,
385
+ page: Optional[int] = None,
386
+ page_size: Optional[int] = None,
387
+ filters: Optional[dict[str, Any]] = None,
388
+ ) -> ListPage[EligiblePromotion]:
389
+ """List eligible promotions for an order
390
+
391
+ Args:
392
+ direction: Direction of the order, from the current user's perspective.
393
+ order_id: ID of the order.
394
+ search: Word or phrase to search for.
395
+ search_on: Comma-delimited list of fields to search on.
396
+ sort_by: Comma-delimited list of fields to sort by.
397
+ page: Page of results to return. When paginating through many items (> page 30), we recommend the "Last ID" method, as outlined in the Advanced Querying documentation.
398
+ page_size: Number of results to return per page.
399
+ filters: An object or dictionary representing key/value pairs to apply as filters. Valid keys are top-level properties of the returned model or 'xp.???'
400
+
401
+ Returns:
402
+ A paginated list of EligiblePromotion objects.
403
+ """
404
+ params = self._build_list_params(
405
+ search=search,
406
+ search_on=search_on,
407
+ sort_by=sort_by,
408
+ page=page,
409
+ page_size=page_size,
410
+ filters=filters,
411
+ )
412
+ resp = await self._http.get(f"/orders/{direction}/{order_id}/eligiblepromotions", **params)
413
+ return self._parse_list(resp.json(), EligiblePromotion)
414
+
415
+ async def forward(
416
+ self,
417
+ direction: OrderDirection,
418
+ order_id: str,
419
+ ) -> OrderSplitResult:
420
+ """Forward an order
421
+
422
+ Args:
423
+ direction: Direction of the order, from the current user's perspective.
424
+ order_id: ID of the order.
425
+
426
+ Returns:
427
+ The OrderSplitResult object.
428
+ """
429
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/forward")
430
+ return OrderSplitResult(**resp.json())
431
+
432
+ async def patch_from_user(
433
+ self,
434
+ direction: OrderDirection,
435
+ order_id: str,
436
+ partial: dict[str, Any],
437
+ ) -> Order:
438
+ """Partially update an order from user
439
+
440
+ Args:
441
+ direction: Direction of the order, from the current user's perspective.
442
+ order_id: ID of the order.
443
+ partial: A dict of fields to update.
444
+
445
+ Returns:
446
+ The Order object.
447
+ """
448
+ resp = await self._http.patch(f"/orders/{direction}/{order_id}/fromuser", json=partial)
449
+ return Order(**resp.json())
450
+
451
+ async def list_promotions(
452
+ self,
453
+ direction: OrderDirection,
454
+ order_id: str,
455
+ *,
456
+ search: Optional[str] = None,
457
+ search_on: Optional[str] = None,
458
+ sort_by: Optional[str] = None,
459
+ page: Optional[int] = None,
460
+ page_size: Optional[int] = None,
461
+ filters: Optional[dict[str, Any]] = None,
462
+ ) -> ListPage[OrderPromotion]:
463
+ """List order promotions
464
+
465
+ Args:
466
+ direction: Direction of the order, from the current user's perspective.
467
+ order_id: ID of the order.
468
+ search: Word or phrase to search for.
469
+ search_on: Comma-delimited list of fields to search on.
470
+ sort_by: Comma-delimited list of fields to sort by.
471
+ page: Page of results to return. When paginating through many items (> page 30), we recommend the "Last ID" method, as outlined in the Advanced Querying documentation.
472
+ page_size: Number of results to return per page.
473
+ filters: An object or dictionary representing key/value pairs to apply as filters. Valid keys are top-level properties of the returned model or 'xp.???'
474
+
475
+ Returns:
476
+ A paginated list of OrderPromotion objects.
477
+ """
478
+ params = self._build_list_params(
479
+ search=search,
480
+ search_on=search_on,
481
+ sort_by=sort_by,
482
+ page=page,
483
+ page_size=page_size,
484
+ filters=filters,
485
+ )
486
+ resp = await self._http.get(f"/orders/{direction}/{order_id}/promotions", **params)
487
+ return self._parse_list(resp.json(), OrderPromotion)
488
+
489
+ async def add_promotion(
490
+ self,
491
+ direction: OrderDirection,
492
+ order_id: str,
493
+ promo_code: str,
494
+ ) -> OrderPromotion:
495
+ """Add a promotion to an order
496
+
497
+ Args:
498
+ direction: Direction of the order, from the current user's perspective.
499
+ order_id: ID of the order.
500
+ promo_code: Promo code of the order promotion.
501
+
502
+ Returns:
503
+ The OrderPromotion object.
504
+ """
505
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/promotions/{promo_code}")
506
+ return OrderPromotion(**resp.json())
507
+
508
+ async def remove_promotion(
509
+ self,
510
+ direction: OrderDirection,
511
+ order_id: str,
512
+ promo_code: str,
513
+ ) -> Order:
514
+ """Remove a promotion from an order
515
+
516
+ Args:
517
+ direction: Direction of the order, from the current user's perspective.
518
+ order_id: ID of the order.
519
+ promo_code: Promo code of the order.
520
+
521
+ Returns:
522
+ The Order object.
523
+ """
524
+ resp = await self._http.delete(f"/orders/{direction}/{order_id}/promotions/{promo_code}")
525
+ return Order(**resp.json())
526
+
527
+ async def refresh_promotions(
528
+ self,
529
+ direction: OrderDirection,
530
+ order_id: str,
531
+ ) -> RefreshPromosResponse:
532
+ """Refresh promotions on an order
533
+
534
+ Args:
535
+ direction: Direction of the order, from the current user's perspective.
536
+ order_id: ID of the order.
537
+
538
+ Returns:
539
+ The RefreshPromosResponse object.
540
+ """
541
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/refreshpromotions")
542
+ return RefreshPromosResponse(**resp.json())
543
+
544
+ async def ship(
545
+ self,
546
+ direction: OrderDirection,
547
+ order_id: str,
548
+ shipment: Union[Shipment, dict[str, Any]],
549
+ ) -> Order:
550
+ """Create a new shipment containing all items on an order
551
+
552
+ Args:
553
+ direction: Direction of the order, from the current user's perspective.
554
+ order_id: ID of the order.
555
+ shipment: A ``Shipment`` model or dict.
556
+
557
+ Returns:
558
+ The Order object.
559
+ """
560
+ resp = await self._http.post(
561
+ f"/orders/{direction}/{order_id}/ship", json=self._serialize(shipment)
562
+ )
563
+ return Order(**resp.json())
564
+
565
+ async def list_shipments(
566
+ self,
567
+ direction: OrderDirection,
568
+ order_id: str,
569
+ *,
570
+ search: Optional[str] = None,
571
+ search_on: Optional[str] = None,
572
+ sort_by: Optional[str] = None,
573
+ page: Optional[int] = None,
574
+ page_size: Optional[int] = None,
575
+ filters: Optional[dict[str, Any]] = None,
576
+ ) -> ListPage[Shipment]:
577
+ """List shipments for an order
578
+
579
+ Args:
580
+ direction: Direction of the order, from the current user's perspective.
581
+ order_id: ID of the order.
582
+ search: Word or phrase to search for.
583
+ search_on: Comma-delimited list of fields to search on.
584
+ sort_by: Comma-delimited list of fields to sort by.
585
+ page: Page of results to return. When paginating through many items (> page 30), we recommend the "Last ID" method, as outlined in the Advanced Querying documentation.
586
+ page_size: Number of results to return per page.
587
+ filters: An object or dictionary representing key/value pairs to apply as filters. Valid keys are top-level properties of the returned model or 'xp.???'
588
+
589
+ Returns:
590
+ A paginated list of Shipment objects.
591
+ """
592
+ params = self._build_list_params(
593
+ search=search,
594
+ search_on=search_on,
595
+ sort_by=sort_by,
596
+ page=page,
597
+ page_size=page_size,
598
+ filters=filters,
599
+ )
600
+ resp = await self._http.get(f"/orders/{direction}/{order_id}/shipments", **params)
601
+ return self._parse_list(resp.json(), Shipment)
602
+
603
+ async def set_shipping_address(
604
+ self,
605
+ direction: OrderDirection,
606
+ order_id: str,
607
+ address: Union[Address, dict[str, Any]],
608
+ ) -> Order:
609
+ """Set a shipping address
610
+
611
+ Args:
612
+ direction: Direction of the order, from the current user's perspective.
613
+ order_id: ID of the order.
614
+ address: A ``Address`` model or dict. Required fields: Street1, City, Country.
615
+
616
+ Returns:
617
+ The Order object.
618
+ """
619
+ resp = await self._http.put(
620
+ f"/orders/{direction}/{order_id}/shipto",
621
+ json=self._serialize(address),
622
+ )
623
+ return Order(**resp.json())
624
+
625
+ async def patch_shipping_address(
626
+ self,
627
+ direction: OrderDirection,
628
+ order_id: str,
629
+ partial: dict[str, Any],
630
+ ) -> Order:
631
+ """Partially update an order shipping address
632
+
633
+ Args:
634
+ direction: Direction of the order, from the current user's perspective.
635
+ order_id: ID of the order.
636
+ partial: A dict of fields to update.
637
+
638
+ Returns:
639
+ The Order object.
640
+ """
641
+ resp = await self._http.patch(f"/orders/{direction}/{order_id}/shipto", json=partial)
642
+ return Order(**resp.json())
643
+
644
+ async def split(
645
+ self,
646
+ direction: OrderDirection,
647
+ order_id: str,
648
+ ) -> OrderSplitResult:
649
+ """Split an order
650
+
651
+ Args:
652
+ direction: Direction of the order, from the current user's perspective.
653
+ order_id: ID of the order.
654
+
655
+ Returns:
656
+ The OrderSplitResult object.
657
+ """
658
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/split")
659
+ return OrderSplitResult(**resp.json())
660
+
661
+ async def submit(
662
+ self,
663
+ direction: OrderDirection,
664
+ order_id: str,
665
+ ) -> Order:
666
+ """Submit an order
667
+
668
+ Args:
669
+ direction: Direction of the order, from the current user's perspective.
670
+ order_id: ID of the order.
671
+
672
+ Returns:
673
+ The Order object.
674
+ """
675
+ resp = await self._http.post(f"/orders/{direction}/{order_id}/submit")
676
+ return Order(**resp.json())
677
+
678
+ async def validate(
679
+ self,
680
+ direction: OrderDirection,
681
+ order_id: str,
682
+ ) -> None:
683
+ """Validate an order in its current state
684
+
685
+ Args:
686
+ direction: Direction of the order, from the current user's perspective.
687
+ order_id: ID of the order.
688
+ """
689
+ await self._http.post(f"/orders/{direction}/{order_id}/validate")