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,145 @@
1
+ """Base resource class with shared helpers for OrderCloud API resources."""
2
+
3
+ from collections.abc import AsyncIterator, Awaitable, Callable
4
+ from typing import Any, Optional, TypeVar
5
+
6
+ from pydantic import BaseModel
7
+
8
+ from ..http import HttpClient
9
+ from ..models.shared import ListPage, Meta
10
+
11
+ T = TypeVar("T", bound=BaseModel)
12
+
13
+ __all__ = ["BaseResource", "paginate"]
14
+
15
+
16
+ async def paginate(
17
+ list_method: Callable[..., Awaitable[ListPage[T]]],
18
+ *args: Any,
19
+ page_size: int = 100,
20
+ **kwargs: Any,
21
+ ) -> AsyncIterator[T]:
22
+ """Auto-paginate any list endpoint, yielding individual items.
23
+
24
+ Calls ``list_method`` repeatedly, incrementing the page number until
25
+ all pages have been fetched. Yields items one at a time.
26
+
27
+ Args:
28
+ list_method: A bound list method (e.g. ``client.products.list``).
29
+ *args: Positional arguments forwarded to the list method.
30
+ page_size: Items per page (default 100, the API maximum).
31
+ **kwargs: Keyword arguments forwarded to the list method.
32
+
33
+ Yields:
34
+ Individual items across all pages.
35
+
36
+ Example::
37
+
38
+ from ordercloud.resources import paginate
39
+
40
+ async for product in paginate(client.products.list, search="widget"):
41
+ print(product.name)
42
+ """
43
+ page = 1
44
+ kwargs["page_size"] = page_size
45
+ while True:
46
+ kwargs["page"] = page
47
+ result = await list_method(*args, **kwargs)
48
+ for item in result.items:
49
+ yield item
50
+ if page >= result.meta.total_pages:
51
+ break
52
+ page += 1
53
+
54
+
55
+ class BaseResource:
56
+ """Base class for OrderCloud API resource clients.
57
+
58
+ Provides shared infrastructure used by all resource implementations:
59
+ HTTP client storage, list-parameter building, response parsing,
60
+ and model serialisation.
61
+ """
62
+
63
+ def __init__(self, http: HttpClient) -> None:
64
+ self._http = http
65
+
66
+ @staticmethod
67
+ def _build_list_params(
68
+ *,
69
+ search: Optional[str] = None,
70
+ search_on: Optional[str] = None,
71
+ sort_by: Optional[str] = None,
72
+ page: Optional[int] = None,
73
+ page_size: Optional[int] = None,
74
+ depth: Optional[str] = None,
75
+ filters: Optional[dict[str, Any]] = None,
76
+ ) -> dict[str, Any]:
77
+ """Build query parameters for a list endpoint.
78
+
79
+ Maps snake_case Python parameter names to the camelCase names
80
+ expected by the OrderCloud API. Only non-None values are included.
81
+
82
+ Args:
83
+ search: Free-text search term.
84
+ search_on: Comma-separated field names to search on.
85
+ sort_by: Field name to sort by (prefix with ``!`` to reverse).
86
+ page: 1-based page number.
87
+ page_size: Number of items per page (max 100).
88
+ depth: Category tree depth (categories only).
89
+ filters: Arbitrary key/value filters merged into the params.
90
+
91
+ Returns:
92
+ A dict of query parameters ready to pass to the HTTP client.
93
+ """
94
+ params: dict[str, Any] = {}
95
+ if search is not None:
96
+ params["search"] = search
97
+ if search_on is not None:
98
+ params["searchOn"] = search_on
99
+ if sort_by is not None:
100
+ params["sortBy"] = sort_by
101
+ if page is not None:
102
+ params["page"] = page
103
+ if page_size is not None:
104
+ params["pageSize"] = page_size
105
+ if depth is not None:
106
+ params["depth"] = depth
107
+ if filters:
108
+ params.update(filters)
109
+ return params
110
+
111
+ @staticmethod
112
+ def _parse_list(
113
+ data: dict[str, Any], model_cls: type[T], meta_cls: type[Meta] = Meta
114
+ ) -> ListPage[T]:
115
+ """Parse a raw JSON dict into a typed ``ListPage``.
116
+
117
+ Args:
118
+ data: Decoded JSON body from a list endpoint response.
119
+ model_cls: The Pydantic model class for individual items.
120
+ meta_cls: The metadata class (``Meta`` or ``MetaWithFacets``).
121
+
122
+ Returns:
123
+ A ``ListPage`` containing parsed items and pagination metadata.
124
+ """
125
+ return ListPage[model_cls]( # type: ignore[valid-type]
126
+ items=[model_cls.model_validate(item) for item in data.get("Items", [])],
127
+ meta=meta_cls.model_validate(data.get("Meta", {})),
128
+ )
129
+
130
+ @staticmethod
131
+ def _serialize(model: BaseModel | dict[str, Any]) -> dict[str, Any]:
132
+ """Serialise a Pydantic model or plain dict for an API request body.
133
+
134
+ Accepts either a Pydantic ``BaseModel`` instance (serialised with
135
+ ``exclude_none=True``) or a raw ``dict`` (passed through unchanged).
136
+
137
+ Args:
138
+ model: A Pydantic model instance or a dict.
139
+
140
+ Returns:
141
+ A JSON-serialisable dict.
142
+ """
143
+ if isinstance(model, BaseModel):
144
+ return model.model_dump(by_alias=True, exclude_none=True)
145
+ return model
@@ -0,0 +1,59 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud BundleLineItems API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Union
7
+
8
+ from ..models.line_item import BundleItems, LineItem
9
+ from ..models.misc import OrderDirection
10
+ from .base import BaseResource
11
+
12
+ __all__ = ["BundleLineItemsResource"]
13
+
14
+
15
+ class BundleLineItemsResource(BaseResource):
16
+ """Operations on OrderCloud BundleLineItems."""
17
+
18
+ async def create(
19
+ self,
20
+ direction: OrderDirection,
21
+ order_id: str,
22
+ bundle_id: str,
23
+ bundle_items: Union[BundleItems, dict[str, Any]],
24
+ ) -> LineItem:
25
+ """Create a bundle line item
26
+
27
+ Args:
28
+ direction: Direction of the order, from the current user's perspective.
29
+ order_id: ID of the order.
30
+ bundle_id: ID of the bundle.
31
+ bundle_items: A ``BundleItems`` model or dict.
32
+
33
+ Returns:
34
+ The LineItem object.
35
+ """
36
+ resp = await self._http.post(
37
+ f"/orders/{direction}/{order_id}/bundles/{bundle_id}",
38
+ json=self._serialize(bundle_items),
39
+ )
40
+ return LineItem(**resp.json())
41
+
42
+ async def delete(
43
+ self,
44
+ direction: OrderDirection,
45
+ order_id: str,
46
+ bundle_id: str,
47
+ bundle_item_id: str,
48
+ ) -> None:
49
+ """Delete a bundle line item
50
+
51
+ Args:
52
+ direction: Direction of the order, from the current user's perspective.
53
+ order_id: ID of the order.
54
+ bundle_id: ID of the bundle.
55
+ bundle_item_id: ID of the bundle item.
56
+ """
57
+ await self._http.delete(
58
+ f"/orders/{direction}/{order_id}/bundles/{bundle_id}/{bundle_item_id}"
59
+ )
@@ -0,0 +1,54 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud BundleSubscriptionItems API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Union
7
+
8
+ from ..models.line_item import BundleItems, LineItem
9
+ from .base import BaseResource
10
+
11
+ __all__ = ["BundleSubscriptionItemsResource"]
12
+
13
+
14
+ class BundleSubscriptionItemsResource(BaseResource):
15
+ """Operations on OrderCloud BundleSubscriptionItems."""
16
+
17
+ async def create(
18
+ self,
19
+ subscription_id: str,
20
+ bundle_id: str,
21
+ bundle_items: Union[BundleItems, dict[str, Any]],
22
+ ) -> LineItem:
23
+ """Create a bundle subscription item
24
+
25
+ Args:
26
+ subscription_id: ID of the subscription.
27
+ bundle_id: ID of the bundle.
28
+ bundle_items: A ``BundleItems`` model or dict.
29
+
30
+ Returns:
31
+ The LineItem object.
32
+ """
33
+ resp = await self._http.post(
34
+ f"/subscriptions/{subscription_id}/bundles/{bundle_id}",
35
+ json=self._serialize(bundle_items),
36
+ )
37
+ return LineItem(**resp.json())
38
+
39
+ async def delete(
40
+ self,
41
+ subscription_id: str,
42
+ bundle_id: str,
43
+ bundle_item_id: str,
44
+ ) -> None:
45
+ """Delete a bundle subscription item
46
+
47
+ Args:
48
+ subscription_id: ID of the subscription.
49
+ bundle_id: ID of the bundle.
50
+ bundle_item_id: ID of the bundle item.
51
+ """
52
+ await self._http.delete(
53
+ f"/subscriptions/{subscription_id}/bundles/{bundle_id}/{bundle_item_id}"
54
+ )
@@ -0,0 +1,278 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud Bundles API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Optional, Union
7
+
8
+ from ..models.assignments import BundleAssignment, BundleProductAssignment
9
+ from ..models.bundle import Bundle
10
+ from ..models.misc import SearchType
11
+ from ..models.shared import ListPage, MetaWithFacets
12
+ from .base import BaseResource
13
+
14
+ __all__ = ["BundlesResource"]
15
+
16
+
17
+ class BundlesResource(BaseResource):
18
+ """Operations on OrderCloud Bundles."""
19
+
20
+ async def list(
21
+ self,
22
+ *,
23
+ catalog_id: Optional[str] = None,
24
+ category_id: Optional[str] = None,
25
+ supplier_id: Optional[str] = None,
26
+ search: Optional[str] = None,
27
+ search_on: Optional[str] = None,
28
+ search_type: Optional[SearchType] = None,
29
+ sort_by: Optional[str] = None,
30
+ page: Optional[int] = None,
31
+ page_size: Optional[int] = None,
32
+ filters: Optional[dict[str, Any]] = None,
33
+ ) -> ListPage[Bundle]:
34
+ """List bundles
35
+
36
+ Args:
37
+ catalog_id: ID of the catalog.
38
+ category_id: ID of the category.
39
+ supplier_id: ID of the supplier.
40
+ search: Word or phrase to search for.
41
+ search_on: Comma-delimited list of fields to search on.
42
+ search_type: Type of search to perform.
43
+ sort_by: Comma-delimited list of fields to sort by.
44
+ 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.
45
+ page_size: Number of results to return per page.
46
+ 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.???'
47
+
48
+ Returns:
49
+ A paginated list of Bundle objects.
50
+ """
51
+ params = self._build_list_params(
52
+ search=search,
53
+ search_on=search_on,
54
+ sort_by=sort_by,
55
+ page=page,
56
+ page_size=page_size,
57
+ filters=filters,
58
+ )
59
+ if catalog_id is not None:
60
+ params["catalogID"] = catalog_id
61
+ if category_id is not None:
62
+ params["categoryID"] = category_id
63
+ if supplier_id is not None:
64
+ params["supplierID"] = supplier_id
65
+ if search_type is not None:
66
+ params["searchType"] = search_type
67
+ resp = await self._http.get("/bundles", **params)
68
+ return self._parse_list(resp.json(), Bundle, meta_cls=MetaWithFacets)
69
+
70
+ async def create(
71
+ self,
72
+ bundle: Union[Bundle, dict[str, Any]],
73
+ ) -> Bundle:
74
+ """Create a bundle
75
+
76
+ Args:
77
+ bundle: A ``Bundle`` model or dict. Required fields: Name.
78
+
79
+ Returns:
80
+ The Bundle object.
81
+ """
82
+ resp = await self._http.post("/bundles", json=self._serialize(bundle))
83
+ return Bundle(**resp.json())
84
+
85
+ async def get(
86
+ self,
87
+ bundle_id: str,
88
+ ) -> Bundle:
89
+ """Retrieve a bundle
90
+
91
+ Args:
92
+ bundle_id: ID of the bundle.
93
+
94
+ Returns:
95
+ The Bundle object.
96
+ """
97
+ resp = await self._http.get(f"/bundles/{bundle_id}")
98
+ return Bundle(**resp.json())
99
+
100
+ async def save(
101
+ self,
102
+ bundle_id: str,
103
+ bundle: Union[Bundle, dict[str, Any]],
104
+ ) -> Bundle:
105
+ """Create or update a bundle
106
+
107
+ Args:
108
+ bundle_id: ID of the bundle.
109
+ bundle: A ``Bundle`` model or dict. Required fields: Name.
110
+
111
+ Returns:
112
+ The Bundle object.
113
+ """
114
+ resp = await self._http.put(
115
+ f"/bundles/{bundle_id}",
116
+ json=self._serialize(bundle),
117
+ )
118
+ return Bundle(**resp.json())
119
+
120
+ async def delete(
121
+ self,
122
+ bundle_id: str,
123
+ ) -> None:
124
+ """Delete a bundle
125
+
126
+ Args:
127
+ bundle_id: ID of the bundle.
128
+ """
129
+ await self._http.delete(f"/bundles/{bundle_id}")
130
+
131
+ async def patch(
132
+ self,
133
+ bundle_id: str,
134
+ partial: dict[str, Any],
135
+ ) -> Bundle:
136
+ """Partially update a bundle
137
+
138
+ Args:
139
+ bundle_id: ID of the bundle.
140
+ partial: A dict of fields to update.
141
+
142
+ Returns:
143
+ The Bundle object.
144
+ """
145
+ resp = await self._http.patch(f"/bundles/{bundle_id}", json=partial)
146
+ return Bundle(**resp.json())
147
+
148
+ async def delete_assignment(
149
+ self,
150
+ bundle_id: str,
151
+ buyer_id: str,
152
+ *,
153
+ user_id: Optional[str] = None,
154
+ user_group_id: Optional[str] = None,
155
+ seller_id: Optional[str] = None,
156
+ ) -> None:
157
+ """Delete a bundle assignment
158
+
159
+ Args:
160
+ bundle_id: ID of the bundle.
161
+ buyer_id: ID of the buyer.
162
+ user_id: ID of the user.
163
+ user_group_id: ID of the user group.
164
+ seller_id: ID of the seller.
165
+ """
166
+ _params: dict[str, Any] = {}
167
+ if user_id is not None:
168
+ _params["userID"] = user_id
169
+ if user_group_id is not None:
170
+ _params["userGroupID"] = user_group_id
171
+ if seller_id is not None:
172
+ _params["sellerID"] = seller_id
173
+ await self._http.delete(f"/bundles/{bundle_id}/assignments/{buyer_id}", **_params)
174
+
175
+ async def delete_product_assignment(
176
+ self,
177
+ bundle_id: str,
178
+ product_id: str,
179
+ ) -> None:
180
+ """Delete a bundle product assignment
181
+
182
+ Args:
183
+ bundle_id: ID of the bundle.
184
+ product_id: ID of the product.
185
+ """
186
+ await self._http.delete(f"/bundles/{bundle_id}/productassignments/{product_id}")
187
+
188
+ async def list_assignments(
189
+ self,
190
+ *,
191
+ bundle_id: Optional[str] = None,
192
+ buyer_id: Optional[str] = None,
193
+ user_group_id: Optional[str] = None,
194
+ level: Optional[str] = None,
195
+ page: Optional[int] = None,
196
+ page_size: Optional[int] = None,
197
+ ) -> ListPage[BundleAssignment]:
198
+ """List bundle assignments
199
+
200
+ Args:
201
+ bundle_id: ID of the bundle.
202
+ buyer_id: ID of the buyer.
203
+ user_group_id: ID of the user group.
204
+ level: Level of the bundle assignment. Possible values: Group, Company, BuyerGroup.
205
+ 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.
206
+ page_size: Number of results to return per page.
207
+
208
+ Returns:
209
+ A paginated list of BundleAssignment objects.
210
+ """
211
+ params = self._build_list_params(
212
+ page=page,
213
+ page_size=page_size,
214
+ )
215
+ if bundle_id is not None:
216
+ params["bundleID"] = bundle_id
217
+ if buyer_id is not None:
218
+ params["buyerID"] = buyer_id
219
+ if user_group_id is not None:
220
+ params["userGroupID"] = user_group_id
221
+ if level is not None:
222
+ params["level"] = level
223
+ resp = await self._http.get("/bundles/assignments", **params)
224
+ return self._parse_list(resp.json(), BundleAssignment)
225
+
226
+ async def save_assignment(
227
+ self,
228
+ bundle_assignment: Union[BundleAssignment, dict[str, Any]],
229
+ ) -> None:
230
+ """Create or update a bundle assignment
231
+
232
+ Args:
233
+ bundle_assignment: A ``BundleAssignment`` model or dict. Required fields: BundleID, BuyerID.
234
+ """
235
+ await self._http.post("/bundles/assignments", json=self._serialize(bundle_assignment))
236
+
237
+ async def list_product_assignments(
238
+ self,
239
+ *,
240
+ bundle_id: Optional[str] = None,
241
+ product_id: Optional[str] = None,
242
+ page: Optional[int] = None,
243
+ page_size: Optional[int] = None,
244
+ ) -> ListPage[BundleProductAssignment]:
245
+ """List bundle product assignments
246
+
247
+ Args:
248
+ bundle_id: ID of the bundle.
249
+ product_id: ID of the product.
250
+ 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.
251
+ page_size: Number of results to return per page.
252
+
253
+ Returns:
254
+ A paginated list of BundleProductAssignment objects.
255
+ """
256
+ params = self._build_list_params(
257
+ page=page,
258
+ page_size=page_size,
259
+ )
260
+ if bundle_id is not None:
261
+ params["bundleID"] = bundle_id
262
+ if product_id is not None:
263
+ params["productID"] = product_id
264
+ resp = await self._http.get("/bundles/productassignments", **params)
265
+ return self._parse_list(resp.json(), BundleProductAssignment)
266
+
267
+ async def save_product_assignment(
268
+ self,
269
+ bundle_product_assignment: Union[BundleProductAssignment, dict[str, Any]],
270
+ ) -> None:
271
+ """Create or update a bundle product assignment
272
+
273
+ Args:
274
+ bundle_product_assignment: A ``BundleProductAssignment`` model or dict. Required fields: ProductID, BundleID, Required.
275
+ """
276
+ await self._http.post(
277
+ "/bundles/productassignments", json=self._serialize(bundle_product_assignment)
278
+ )
@@ -0,0 +1,128 @@
1
+ # GENERATED by tools/codegen — DO NOT EDIT
2
+ # Source: ordercloud-openapi-v3.json
3
+ """OrderCloud BuyerGroups API resource."""
4
+
5
+ from __future__ import annotations
6
+ from typing import Any, Optional, Union
7
+
8
+ from ..models.buyer import BuyerGroup
9
+ from ..models.shared import ListPage
10
+ from .base import BaseResource
11
+
12
+ __all__ = ["BuyerGroupsResource"]
13
+
14
+
15
+ class BuyerGroupsResource(BaseResource):
16
+ """Operations on OrderCloud BuyerGroups."""
17
+
18
+ async def list(
19
+ self,
20
+ *,
21
+ search: Optional[str] = None,
22
+ search_on: Optional[str] = None,
23
+ sort_by: Optional[str] = None,
24
+ page: Optional[int] = None,
25
+ page_size: Optional[int] = None,
26
+ filters: Optional[dict[str, Any]] = None,
27
+ ) -> ListPage[BuyerGroup]:
28
+ """List buyer groups
29
+
30
+ Args:
31
+ search: Word or phrase to search for.
32
+ search_on: Comma-delimited list of fields to search on.
33
+ sort_by: Comma-delimited list of fields to sort by.
34
+ 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.
35
+ page_size: Number of results to return per page.
36
+ 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.???'
37
+
38
+ Returns:
39
+ A paginated list of BuyerGroup objects.
40
+ """
41
+ params = self._build_list_params(
42
+ search=search,
43
+ search_on=search_on,
44
+ sort_by=sort_by,
45
+ page=page,
46
+ page_size=page_size,
47
+ filters=filters,
48
+ )
49
+ resp = await self._http.get("/buyergroups", **params)
50
+ return self._parse_list(resp.json(), BuyerGroup)
51
+
52
+ async def create(
53
+ self,
54
+ buyer_group: Union[BuyerGroup, dict[str, Any]],
55
+ ) -> BuyerGroup:
56
+ """Create a buyer group
57
+
58
+ Args:
59
+ buyer_group: A ``BuyerGroup`` model or dict. Required fields: Name.
60
+
61
+ Returns:
62
+ The BuyerGroup object.
63
+ """
64
+ resp = await self._http.post("/buyergroups", json=self._serialize(buyer_group))
65
+ return BuyerGroup(**resp.json())
66
+
67
+ async def get(
68
+ self,
69
+ buyer_group_id: str,
70
+ ) -> BuyerGroup:
71
+ """Retrieve a buyer group
72
+
73
+ Args:
74
+ buyer_group_id: ID of the buyer group.
75
+
76
+ Returns:
77
+ The BuyerGroup object.
78
+ """
79
+ resp = await self._http.get(f"/buyergroups/{buyer_group_id}")
80
+ return BuyerGroup(**resp.json())
81
+
82
+ async def save(
83
+ self,
84
+ buyer_group_id: str,
85
+ buyer_group: Union[BuyerGroup, dict[str, Any]],
86
+ ) -> BuyerGroup:
87
+ """Create or update a buyer group
88
+
89
+ Args:
90
+ buyer_group_id: ID of the buyer group.
91
+ buyer_group: A ``BuyerGroup`` model or dict. Required fields: Name.
92
+
93
+ Returns:
94
+ The BuyerGroup object.
95
+ """
96
+ resp = await self._http.put(
97
+ f"/buyergroups/{buyer_group_id}",
98
+ json=self._serialize(buyer_group),
99
+ )
100
+ return BuyerGroup(**resp.json())
101
+
102
+ async def delete(
103
+ self,
104
+ buyer_group_id: str,
105
+ ) -> None:
106
+ """Delete a buyer group
107
+
108
+ Args:
109
+ buyer_group_id: ID of the buyer group.
110
+ """
111
+ await self._http.delete(f"/buyergroups/{buyer_group_id}")
112
+
113
+ async def patch(
114
+ self,
115
+ buyer_group_id: str,
116
+ partial: dict[str, Any],
117
+ ) -> BuyerGroup:
118
+ """Partially update a buyer group
119
+
120
+ Args:
121
+ buyer_group_id: ID of the buyer group.
122
+ partial: A dict of fields to update.
123
+
124
+ Returns:
125
+ The BuyerGroup object.
126
+ """
127
+ resp = await self._http.patch(f"/buyergroups/{buyer_group_id}", json=partial)
128
+ return BuyerGroup(**resp.json())