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,454 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud Products API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Optional, Union
7
+
8
+ from ..models.assignments import ProductAssignment
9
+ from ..models.misc import SearchType
10
+ from ..models.product import Product, ProductSupplier, Variant, VariantOverrides
11
+ from ..models.spec import Spec
12
+ from ..models.shared import ListPage, MetaWithFacets
13
+ from .base import BaseResource
14
+
15
+ __all__ = ["ProductsResource"]
16
+
17
+
18
+ class ProductsResource(BaseResource):
19
+ """Operations on OrderCloud Products."""
20
+
21
+ async def list(
22
+ self,
23
+ *,
24
+ catalog_id: Optional[str] = None,
25
+ category_id: Optional[str] = None,
26
+ supplier_id: Optional[str] = None,
27
+ search: Optional[str] = None,
28
+ search_on: Optional[str] = None,
29
+ search_type: Optional[SearchType] = None,
30
+ sort_by: Optional[str] = None,
31
+ page: Optional[int] = None,
32
+ page_size: Optional[int] = None,
33
+ filters: Optional[dict[str, Any]] = None,
34
+ ) -> ListPage[Product]:
35
+ """List products
36
+
37
+ Args:
38
+ catalog_id: ID of the catalog.
39
+ category_id: ID of the category.
40
+ supplier_id: ID of the supplier.
41
+ search: Word or phrase to search for.
42
+ search_on: Comma-delimited list of fields to search on.
43
+ search_type: Type of search to perform.
44
+ sort_by: Comma-delimited list of fields to sort by.
45
+ 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.
46
+ page_size: Number of results to return per page.
47
+ 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.???'
48
+
49
+ Returns:
50
+ A paginated list of Product objects.
51
+ """
52
+ params = self._build_list_params(
53
+ search=search,
54
+ search_on=search_on,
55
+ sort_by=sort_by,
56
+ page=page,
57
+ page_size=page_size,
58
+ filters=filters,
59
+ )
60
+ if catalog_id is not None:
61
+ params["catalogID"] = catalog_id
62
+ if category_id is not None:
63
+ params["categoryID"] = category_id
64
+ if supplier_id is not None:
65
+ params["supplierID"] = supplier_id
66
+ if search_type is not None:
67
+ params["searchType"] = search_type
68
+ resp = await self._http.get("/products", **params)
69
+ return self._parse_list(resp.json(), Product, meta_cls=MetaWithFacets)
70
+
71
+ async def create(
72
+ self,
73
+ product: Union[Product, dict[str, Any]],
74
+ ) -> Product:
75
+ """Create a product
76
+
77
+ Args:
78
+ product: A ``Product`` model or dict. Required fields: Name.
79
+
80
+ Returns:
81
+ The Product object.
82
+ """
83
+ resp = await self._http.post("/products", json=self._serialize(product))
84
+ return Product(**resp.json())
85
+
86
+ async def get(
87
+ self,
88
+ product_id: str,
89
+ ) -> Product:
90
+ """Retrieve a product
91
+
92
+ Args:
93
+ product_id: ID of the product.
94
+
95
+ Returns:
96
+ The Product object.
97
+ """
98
+ resp = await self._http.get(f"/products/{product_id}")
99
+ return Product(**resp.json())
100
+
101
+ async def save(
102
+ self,
103
+ product_id: str,
104
+ product: Union[Product, dict[str, Any]],
105
+ ) -> Product:
106
+ """Create or update a product
107
+
108
+ Args:
109
+ product_id: ID of the product.
110
+ product: A ``Product`` model or dict. Required fields: Name.
111
+
112
+ Returns:
113
+ The Product object.
114
+ """
115
+ resp = await self._http.put(
116
+ f"/products/{product_id}",
117
+ json=self._serialize(product),
118
+ )
119
+ return Product(**resp.json())
120
+
121
+ async def delete(
122
+ self,
123
+ product_id: str,
124
+ ) -> None:
125
+ """Delete a product
126
+
127
+ Args:
128
+ product_id: ID of the product.
129
+ """
130
+ await self._http.delete(f"/products/{product_id}")
131
+
132
+ async def patch(
133
+ self,
134
+ product_id: str,
135
+ partial: dict[str, Any],
136
+ ) -> Product:
137
+ """Partially update a product
138
+
139
+ Args:
140
+ product_id: ID of the product.
141
+ partial: A dict of fields to update.
142
+
143
+ Returns:
144
+ The Product object.
145
+ """
146
+ resp = await self._http.patch(f"/products/{product_id}", json=partial)
147
+ return Product(**resp.json())
148
+
149
+ async def delete_assignment(
150
+ self,
151
+ product_id: str,
152
+ buyer_id: str,
153
+ *,
154
+ user_id: Optional[str] = None,
155
+ user_group_id: Optional[str] = None,
156
+ seller_id: Optional[str] = None,
157
+ ) -> None:
158
+ """Delete a product assignment
159
+
160
+ Args:
161
+ product_id: ID of the product.
162
+ buyer_id: ID of the buyer.
163
+ user_id: ID of the user.
164
+ user_group_id: ID of the user group.
165
+ seller_id: ID of the seller.
166
+ """
167
+ _params: dict[str, Any] = {}
168
+ if user_id is not None:
169
+ _params["userID"] = user_id
170
+ if user_group_id is not None:
171
+ _params["userGroupID"] = user_group_id
172
+ if seller_id is not None:
173
+ _params["sellerID"] = seller_id
174
+ await self._http.delete(f"/products/{product_id}/assignments/{buyer_id}", **_params)
175
+
176
+ async def list_specs(
177
+ self,
178
+ product_id: str,
179
+ *,
180
+ search: Optional[str] = None,
181
+ search_on: Optional[str] = None,
182
+ sort_by: Optional[str] = None,
183
+ page: Optional[int] = None,
184
+ page_size: Optional[int] = None,
185
+ filters: Optional[dict[str, Any]] = None,
186
+ ) -> ListPage[Spec]:
187
+ """List product specs
188
+
189
+ Args:
190
+ product_id: ID of the product.
191
+ search: Word or phrase to search for.
192
+ search_on: Comma-delimited list of fields to search on.
193
+ sort_by: Comma-delimited list of fields to sort by.
194
+ 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.
195
+ page_size: Number of results to return per page.
196
+ 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.???'
197
+
198
+ Returns:
199
+ A paginated list of Spec objects.
200
+ """
201
+ params = self._build_list_params(
202
+ search=search,
203
+ search_on=search_on,
204
+ sort_by=sort_by,
205
+ page=page,
206
+ page_size=page_size,
207
+ filters=filters,
208
+ )
209
+ resp = await self._http.get(f"/products/{product_id}/specs", **params)
210
+ return self._parse_list(resp.json(), Spec)
211
+
212
+ async def list_suppliers(
213
+ self,
214
+ product_id: str,
215
+ *,
216
+ search: Optional[str] = None,
217
+ search_on: Optional[str] = None,
218
+ sort_by: Optional[str] = None,
219
+ page: Optional[int] = None,
220
+ page_size: Optional[int] = None,
221
+ filters: Optional[dict[str, Any]] = None,
222
+ ) -> ListPage[ProductSupplier]:
223
+ """List product suppliers
224
+
225
+ Args:
226
+ product_id: ID of the product.
227
+ search: Word or phrase to search for.
228
+ search_on: Comma-delimited list of fields to search on.
229
+ sort_by: Comma-delimited list of fields to sort by.
230
+ 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.
231
+ page_size: Number of results to return per page.
232
+ 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.???'
233
+
234
+ Returns:
235
+ A paginated list of ProductSupplier objects.
236
+ """
237
+ params = self._build_list_params(
238
+ search=search,
239
+ search_on=search_on,
240
+ sort_by=sort_by,
241
+ page=page,
242
+ page_size=page_size,
243
+ filters=filters,
244
+ )
245
+ resp = await self._http.get(f"/products/{product_id}/suppliers", **params)
246
+ return self._parse_list(resp.json(), ProductSupplier)
247
+
248
+ async def save_supplier(
249
+ self,
250
+ product_id: str,
251
+ supplier_id: str,
252
+ *,
253
+ default_price_schedule_id: Optional[str] = None,
254
+ ) -> None:
255
+ """Create or update a product supplier
256
+
257
+ Args:
258
+ product_id: ID of the product.
259
+ supplier_id: ID of the supplier.
260
+ default_price_schedule_id: ID of the default price schedule.
261
+ """
262
+ _params: dict[str, Any] = {}
263
+ if default_price_schedule_id is not None:
264
+ _params["defaultPriceScheduleID"] = default_price_schedule_id
265
+ await self._http.put(
266
+ f"/products/{product_id}/suppliers/{supplier_id}", params=_params or None
267
+ )
268
+
269
+ async def remove_supplier(
270
+ self,
271
+ product_id: str,
272
+ supplier_id: str,
273
+ ) -> None:
274
+ """Remove a product supplier
275
+
276
+ Args:
277
+ product_id: ID of the product.
278
+ supplier_id: ID of the supplier.
279
+ """
280
+ await self._http.delete(f"/products/{product_id}/suppliers/{supplier_id}")
281
+
282
+ async def list_variants(
283
+ self,
284
+ product_id: str,
285
+ *,
286
+ search: Optional[str] = None,
287
+ search_on: Optional[str] = None,
288
+ sort_by: Optional[str] = None,
289
+ page: Optional[int] = None,
290
+ page_size: Optional[int] = None,
291
+ filters: Optional[dict[str, Any]] = None,
292
+ ) -> ListPage[Variant]:
293
+ """List product variants
294
+
295
+ Args:
296
+ product_id: ID of the product.
297
+ search: Word or phrase to search for.
298
+ search_on: Comma-delimited list of fields to search on.
299
+ sort_by: Comma-delimited list of fields to sort by.
300
+ 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.
301
+ page_size: Number of results to return per page.
302
+ 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.???'
303
+
304
+ Returns:
305
+ A paginated list of Variant objects.
306
+ """
307
+ params = self._build_list_params(
308
+ search=search,
309
+ search_on=search_on,
310
+ sort_by=sort_by,
311
+ page=page,
312
+ page_size=page_size,
313
+ filters=filters,
314
+ )
315
+ resp = await self._http.get(f"/products/{product_id}/variants", **params)
316
+ return self._parse_list(resp.json(), Variant)
317
+
318
+ async def get_variant(
319
+ self,
320
+ product_id: str,
321
+ variant_id: str,
322
+ ) -> Variant:
323
+ """Retrieve a product variant
324
+
325
+ Args:
326
+ product_id: ID of the product.
327
+ variant_id: ID of the variant.
328
+
329
+ Returns:
330
+ The Variant object.
331
+ """
332
+ resp = await self._http.get(f"/products/{product_id}/variants/{variant_id}")
333
+ return Variant(**resp.json())
334
+
335
+ async def save_variant(
336
+ self,
337
+ product_id: str,
338
+ variant_id: str,
339
+ variant: Union[Variant, dict[str, Any]],
340
+ ) -> Variant:
341
+ """Update a product variant
342
+
343
+ Args:
344
+ product_id: ID of the product.
345
+ variant_id: ID of the variant.
346
+ variant: A ``Variant`` model or dict.
347
+
348
+ Returns:
349
+ The Variant object.
350
+ """
351
+ resp = await self._http.put(
352
+ f"/products/{product_id}/variants/{variant_id}",
353
+ json=self._serialize(variant),
354
+ )
355
+ return Variant(**resp.json())
356
+
357
+ async def patch_variant(
358
+ self,
359
+ product_id: str,
360
+ variant_id: str,
361
+ partial: dict[str, Any],
362
+ ) -> Variant:
363
+ """Partially update a product variant
364
+
365
+ Args:
366
+ product_id: ID of the product.
367
+ variant_id: ID of the variant.
368
+ partial: A dict of fields to update.
369
+
370
+ Returns:
371
+ The Variant object.
372
+ """
373
+ resp = await self._http.patch(f"/products/{product_id}/variants/{variant_id}", json=partial)
374
+ return Variant(**resp.json())
375
+
376
+ async def generate_variants(
377
+ self,
378
+ product_id: str,
379
+ variant_overrides: Union[VariantOverrides, dict[str, Any]],
380
+ *,
381
+ overwrite_existing: Optional[bool] = None,
382
+ ) -> Product:
383
+ """Generate variants
384
+
385
+ Args:
386
+ product_id: ID of the product.
387
+ variant_overrides: A ``VariantOverrides`` model or dict.
388
+ overwrite_existing: Overwrite existing of the product.
389
+
390
+ Returns:
391
+ The Product object.
392
+ """
393
+ _params: dict[str, Any] = {}
394
+ if overwrite_existing is not None:
395
+ _params["overwriteExisting"] = overwrite_existing
396
+ resp = await self._http.post(
397
+ f"/products/{product_id}/variants/generate",
398
+ json=self._serialize(variant_overrides),
399
+ params=_params or None,
400
+ )
401
+ return Product(**resp.json())
402
+
403
+ async def list_assignments(
404
+ self,
405
+ *,
406
+ product_id: Optional[str] = None,
407
+ price_schedule_id: Optional[str] = None,
408
+ buyer_id: Optional[str] = None,
409
+ user_group_id: Optional[str] = None,
410
+ level: Optional[str] = None,
411
+ page: Optional[int] = None,
412
+ page_size: Optional[int] = None,
413
+ ) -> ListPage[ProductAssignment]:
414
+ """List product assignments
415
+
416
+ Args:
417
+ product_id: ID of the product.
418
+ price_schedule_id: ID of the price schedule.
419
+ buyer_id: ID of the buyer.
420
+ user_group_id: ID of the user group.
421
+ level: Level of the product assignment. Possible values: Group, Company, BuyerGroup.
422
+ 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.
423
+ page_size: Number of results to return per page.
424
+
425
+ Returns:
426
+ A paginated list of ProductAssignment objects.
427
+ """
428
+ params = self._build_list_params(
429
+ page=page,
430
+ page_size=page_size,
431
+ )
432
+ if product_id is not None:
433
+ params["productID"] = product_id
434
+ if price_schedule_id is not None:
435
+ params["priceScheduleID"] = price_schedule_id
436
+ if buyer_id is not None:
437
+ params["buyerID"] = buyer_id
438
+ if user_group_id is not None:
439
+ params["userGroupID"] = user_group_id
440
+ if level is not None:
441
+ params["level"] = level
442
+ resp = await self._http.get("/products/assignments", **params)
443
+ return self._parse_list(resp.json(), ProductAssignment)
444
+
445
+ async def save_assignment(
446
+ self,
447
+ product_assignment: Union[ProductAssignment, dict[str, Any]],
448
+ ) -> None:
449
+ """Create or update a product assignment
450
+
451
+ Args:
452
+ product_assignment: A ``ProductAssignment`` model or dict. Required fields: ProductID, BuyerID.
453
+ """
454
+ await self._http.post("/products/assignments", json=self._serialize(product_assignment))
@@ -0,0 +1,65 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud PromotionIntegrations API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Union
7
+
8
+ from ..models.promotion import PromotionIntegration
9
+ from .base import BaseResource
10
+
11
+ __all__ = ["PromotionIntegrationsResource"]
12
+
13
+
14
+ class PromotionIntegrationsResource(BaseResource):
15
+ """Operations on OrderCloud PromotionIntegrations."""
16
+
17
+ async def get(
18
+ self,
19
+ ) -> PromotionIntegration:
20
+ """Retrieve a promotion integration
21
+
22
+ Returns:
23
+ The PromotionIntegration object.
24
+ """
25
+ resp = await self._http.get("/integrations/promotion")
26
+ return PromotionIntegration(**resp.json())
27
+
28
+ async def save(
29
+ self,
30
+ promotion_integration: Union[PromotionIntegration, dict[str, Any]],
31
+ ) -> PromotionIntegration:
32
+ """Create or update a promotion integration
33
+
34
+ Args:
35
+ promotion_integration: A ``PromotionIntegration`` model or dict. Required fields: HashKey.
36
+
37
+ Returns:
38
+ The PromotionIntegration object.
39
+ """
40
+ resp = await self._http.put(
41
+ "/integrations/promotion",
42
+ json=self._serialize(promotion_integration),
43
+ )
44
+ return PromotionIntegration(**resp.json())
45
+
46
+ async def delete(
47
+ self,
48
+ ) -> None:
49
+ """Delete a promotion integration"""
50
+ await self._http.delete("/integrations/promotion")
51
+
52
+ async def patch(
53
+ self,
54
+ partial: dict[str, Any],
55
+ ) -> PromotionIntegration:
56
+ """Partially update a promotion integration
57
+
58
+ Args:
59
+ partial: A dict of fields to update.
60
+
61
+ Returns:
62
+ The PromotionIntegration object.
63
+ """
64
+ resp = await self._http.patch("/integrations/promotion", json=partial)
65
+ return PromotionIntegration(**resp.json())