stepxmlclient 1.0.0__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.
- stepxmlclient/__init__.py +22 -0
- stepxmlclient/client.py +373 -0
- stepxmlclient/creator.py +317 -0
- stepxmlclient/model/__init__.py +418 -0
- stepxmlclient/model/asset.py +250 -0
- stepxmlclient/model/attribute.py +288 -0
- stepxmlclient/model/business.py +233 -0
- stepxmlclient/model/classification.py +409 -0
- stepxmlclient/model/complex_elements.py +260 -0
- stepxmlclient/model/deletion.py +87 -0
- stepxmlclient/model/entity.py +368 -0
- stepxmlclient/model/metadata.py +199 -0
- stepxmlclient/model/organization.py +167 -0
- stepxmlclient/model/product.py +519 -0
- stepxmlclient/model/relations.py +105 -0
- stepxmlclient/model/replacement.py +417 -0
- stepxmlclient/parser.py +2805 -0
- stepxmlclient/rest_client/__init__.py +16 -0
- stepxmlclient/rest_client/base.py +388 -0
- stepxmlclient/rest_client/client.py +127 -0
- stepxmlclient/rest_client/exceptions.py +97 -0
- stepxmlclient/rest_client/models/__init__.py +175 -0
- stepxmlclient/rest_client/models/asset.py +253 -0
- stepxmlclient/rest_client/models/attribute.py +112 -0
- stepxmlclient/rest_client/models/background_process.py +23 -0
- stepxmlclient/rest_client/models/batch.py +41 -0
- stepxmlclient/rest_client/models/classification.py +57 -0
- stepxmlclient/rest_client/models/collection.py +26 -0
- stepxmlclient/rest_client/models/common.py +192 -0
- stepxmlclient/rest_client/models/context.py +16 -0
- stepxmlclient/rest_client/models/data_type_group.py +15 -0
- stepxmlclient/rest_client/models/entity.py +63 -0
- stepxmlclient/rest_client/models/event_processor.py +15 -0
- stepxmlclient/rest_client/models/import_export.py +43 -0
- stepxmlclient/rest_client/models/integration_endpoint.py +16 -0
- stepxmlclient/rest_client/models/product.py +200 -0
- stepxmlclient/rest_client/models/relations.py +280 -0
- stepxmlclient/rest_client/models/system_information.py +11 -0
- stepxmlclient/rest_client/models/user.py +28 -0
- stepxmlclient/rest_client/models/workflow.py +30 -0
- stepxmlclient/rest_client/operations/__init__.py +54 -0
- stepxmlclient/rest_client/operations/assets.py +652 -0
- stepxmlclient/rest_client/operations/attributes.py +252 -0
- stepxmlclient/rest_client/operations/background_processes.py +84 -0
- stepxmlclient/rest_client/operations/batch.py +28 -0
- stepxmlclient/rest_client/operations/classifications.py +248 -0
- stepxmlclient/rest_client/operations/collection_groups.py +46 -0
- stepxmlclient/rest_client/operations/collections.py +67 -0
- stepxmlclient/rest_client/operations/contexts.py +88 -0
- stepxmlclient/rest_client/operations/data_type_groups.py +68 -0
- stepxmlclient/rest_client/operations/entities.py +295 -0
- stepxmlclient/rest_client/operations/event_processors.py +109 -0
- stepxmlclient/rest_client/operations/exports.py +153 -0
- stepxmlclient/rest_client/operations/gateway.py +53 -0
- stepxmlclient/rest_client/operations/inbound.py +472 -0
- stepxmlclient/rest_client/operations/outbound.py +64 -0
- stepxmlclient/rest_client/operations/products.py +489 -0
- stepxmlclient/rest_client/operations/relations.py +349 -0
- stepxmlclient/rest_client/operations/reports.py +27 -0
- stepxmlclient/rest_client/operations/system_information.py +28 -0
- stepxmlclient/rest_client/operations/user_groups.py +79 -0
- stepxmlclient/rest_client/operations/users.py +119 -0
- stepxmlclient/rest_client/operations/workflow_tasks.py +61 -0
- stepxmlclient/rest_client/operations/workflows.py +50 -0
- stepxmlclient/upload.py +293 -0
- stepxmlclient-1.0.0.dist-info/METADATA +666 -0
- stepxmlclient-1.0.0.dist-info/RECORD +70 -0
- stepxmlclient-1.0.0.dist-info/WHEEL +5 -0
- stepxmlclient-1.0.0.dist-info/licenses/LICENSE +21 -0
- stepxmlclient-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Outbound integration endpoint operations for STEP REST API v2."""
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
5
|
+
from ..exceptions import NotFoundError
|
|
6
|
+
from ..models.integration_endpoint import IntegrationEndpointResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OutboundOperations(BaseOperation):
|
|
10
|
+
def __init__(self, client, logger=None, context=None, workspace=None):
|
|
11
|
+
super().__init__(client, operation_name="OutboundOperations", logger=logger, context=context, workspace=workspace)
|
|
12
|
+
|
|
13
|
+
@handle_rest_errors
|
|
14
|
+
def get_outbound_endpoints(self) -> list[dict[str, Any]]:
|
|
15
|
+
self._log_operation("getOutboundIntegrationEndpoints", {})
|
|
16
|
+
r = self.client.getOutboundIntegrationEndpoints(**self._build_context_params())
|
|
17
|
+
return r if isinstance(r, list) else []
|
|
18
|
+
|
|
19
|
+
@handle_rest_errors
|
|
20
|
+
def get_outbound_endpoint(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
21
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
22
|
+
self._log_operation("getOutboundIntegrationEndpoint", {"id": ep_id})
|
|
23
|
+
try:
|
|
24
|
+
r = self.client.getOutboundIntegrationEndpoint(id=ep_id, **self._build_context_params())
|
|
25
|
+
except Exception as e:
|
|
26
|
+
if "404" in str(e): raise NotFoundError(ep_id, "OutboundIntegrationEndpoint")
|
|
27
|
+
raise
|
|
28
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
29
|
+
|
|
30
|
+
@handle_rest_errors
|
|
31
|
+
def get_outbound_endpoint_status(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
32
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
33
|
+
self._log_operation("getOutboundIntegrationEndpointStatus", {"id": ep_id})
|
|
34
|
+
try:
|
|
35
|
+
r = self.client.getOutboundIntegrationEndpointStatus(id=ep_id, **self._build_context_params())
|
|
36
|
+
except Exception as e:
|
|
37
|
+
if "404" in str(e): raise NotFoundError(ep_id, "OutboundIntegrationEndpoint")
|
|
38
|
+
raise
|
|
39
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
40
|
+
|
|
41
|
+
@handle_rest_errors
|
|
42
|
+
def enable_outbound_endpoint(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
43
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
44
|
+
self._log_operation("enableOutboundIntegrationEndpoint", {"id": ep_id})
|
|
45
|
+
r = self.client.enableOutboundIntegrationEndpoint(id=ep_id, **self._build_context_params())
|
|
46
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
47
|
+
|
|
48
|
+
@handle_rest_errors
|
|
49
|
+
def disable_outbound_endpoint(self, ep_id: str) -> IntegrationEndpointResponse:
|
|
50
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
51
|
+
self._log_operation("disableOutboundIntegrationEndpoint", {"id": ep_id})
|
|
52
|
+
r = self.client.disableOutboundIntegrationEndpoint(id=ep_id, **self._build_context_params())
|
|
53
|
+
return IntegrationEndpointResponse(**r) if isinstance(r, dict) else r
|
|
54
|
+
|
|
55
|
+
@handle_rest_errors
|
|
56
|
+
def get_outbound_endpoint_execution_report(self, ep_id: str) -> list[dict[str, Any]]:
|
|
57
|
+
self._validate_required_params({"ep_id": ep_id}, ["ep_id"])
|
|
58
|
+
self._log_operation("getOutboundIntegrationEndpointExecutionReport", {"id": ep_id})
|
|
59
|
+
try:
|
|
60
|
+
r = self.client.getOutboundIntegrationEndpointExecutionReport(id=ep_id, **self._build_context_params())
|
|
61
|
+
except Exception as e:
|
|
62
|
+
if "404" in str(e): raise NotFoundError(ep_id, "OutboundIntegrationEndpoint")
|
|
63
|
+
raise
|
|
64
|
+
return r if isinstance(r, list) else []
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
"""Product operations for STEP REST API.
|
|
2
|
+
|
|
3
|
+
Provides CRUD and search operations for products.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any, Optional
|
|
8
|
+
|
|
9
|
+
import requests_openapi as roa
|
|
10
|
+
|
|
11
|
+
from .. import exceptions as exc
|
|
12
|
+
from ..base import BaseOperation, handle_rest_errors
|
|
13
|
+
from ..models.product import (
|
|
14
|
+
ProductCreateRequest,
|
|
15
|
+
ProductListResponse,
|
|
16
|
+
ProductResponse,
|
|
17
|
+
ProductUpdateRequest,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProductOperations(BaseOperation):
|
|
22
|
+
"""Product CRUD and search operations.
|
|
23
|
+
|
|
24
|
+
Provides methods for:
|
|
25
|
+
- Retrieving single products
|
|
26
|
+
- Searching and listing products
|
|
27
|
+
- Creating new products
|
|
28
|
+
- Updating existing products
|
|
29
|
+
- Deleting products
|
|
30
|
+
- Accessing product attributes and values
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, client: roa.Client, logger: Optional[logging.Logger] = None,
|
|
34
|
+
context: Optional[str] = None, workspace: Optional[str] = None):
|
|
35
|
+
"""Initialize ProductOperations.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
client: The requests-openapi Client instance
|
|
39
|
+
logger: Logger instance (optional)
|
|
40
|
+
context: STEP context ID for all API calls
|
|
41
|
+
workspace: STEP workspace ID (defaults to "Main" server-side)
|
|
42
|
+
"""
|
|
43
|
+
super().__init__(client, operation_name="ProductOperations", logger=logger,
|
|
44
|
+
context=context, workspace=workspace)
|
|
45
|
+
|
|
46
|
+
@handle_rest_errors
|
|
47
|
+
def get_product(self, product_id: str,
|
|
48
|
+
key_id: Optional[str] = None,
|
|
49
|
+
include_inherited_data: bool = False) -> ProductResponse:
|
|
50
|
+
"""Retrieve a single product by ID.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
product_id: The product ID (or alternate key value if key_id is set)
|
|
54
|
+
key_id: Alternate key ID to use for lookup (optional)
|
|
55
|
+
include_inherited_data: Whether to include inherited attribute values (default: False)
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
ProductResponse with product data
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
NotFoundError: If product not found
|
|
62
|
+
RestApiError: For other API errors
|
|
63
|
+
"""
|
|
64
|
+
self._validate_required_params(
|
|
65
|
+
{"product_id": product_id},
|
|
66
|
+
["product_id"]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
query_params: dict[str, Any] = self._build_context_params()
|
|
70
|
+
if key_id:
|
|
71
|
+
query_params["keyId"] = key_id
|
|
72
|
+
if include_inherited_data:
|
|
73
|
+
query_params["includeInheritedData"] = include_inherited_data
|
|
74
|
+
self._log_operation("getProduct", {"product_id": product_id})
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
response = self.client.getProduct(id=product_id, **query_params)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
if "404" in str(e) or "not found" in str(e).lower():
|
|
80
|
+
raise exc.NotFoundError(product_id, "Product")
|
|
81
|
+
raise
|
|
82
|
+
|
|
83
|
+
# Convert response to ProductResponse if needed
|
|
84
|
+
if isinstance(response, dict):
|
|
85
|
+
return ProductResponse(**response)
|
|
86
|
+
return response
|
|
87
|
+
|
|
88
|
+
@handle_rest_errors
|
|
89
|
+
def search_products(self, condition: dict) -> ProductListResponse:
|
|
90
|
+
"""Search for products using a STEP condition query.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
condition: A STEP condition object defining the search criteria.
|
|
94
|
+
Supported conditionTypes: 'and', 'or', 'id', 'name',
|
|
95
|
+
'textvalue', 'numericvalue', 'objecttype', 'simplebelow',
|
|
96
|
+
'lovvalue', 'hasreferenceto', 'hasdatacontainerobject'.
|
|
97
|
+
Example: {"conditionType": "objecttype", "objectType": "MyType"}
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
ProductListResponse with matching products
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
ValidationError: If condition is invalid
|
|
104
|
+
RestApiError: For API errors
|
|
105
|
+
"""
|
|
106
|
+
self._validate_required_params({"condition": condition}, ["condition"])
|
|
107
|
+
body = {"condition": condition}
|
|
108
|
+
self._log_operation("createProductSearch", {"condition": condition})
|
|
109
|
+
|
|
110
|
+
response = self.client.createProductSearch(json=body, **self._build_context_params())
|
|
111
|
+
|
|
112
|
+
if isinstance(response, dict):
|
|
113
|
+
items = response.get("items", [])
|
|
114
|
+
total = response.get("total")
|
|
115
|
+
else:
|
|
116
|
+
items = getattr(response, "items", [])
|
|
117
|
+
total = getattr(response, "total", None)
|
|
118
|
+
|
|
119
|
+
product_items = [
|
|
120
|
+
ProductResponse(**item) if isinstance(item, dict) else item
|
|
121
|
+
for item in items
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
return ProductListResponse(
|
|
125
|
+
items=product_items,
|
|
126
|
+
total=total,
|
|
127
|
+
limit=max(len(product_items), 1),
|
|
128
|
+
offset=0,
|
|
129
|
+
has_more=False
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@handle_rest_errors
|
|
133
|
+
def create_product(self, product_data: ProductCreateRequest) -> ProductResponse:
|
|
134
|
+
"""Create a new product.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
product_data: ProductCreateRequest with product data
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
ProductResponse with created product data
|
|
141
|
+
|
|
142
|
+
Raises:
|
|
143
|
+
ValidationError: If product data is invalid
|
|
144
|
+
ConflictError: If product ID already exists
|
|
145
|
+
RestApiError: For other API errors
|
|
146
|
+
"""
|
|
147
|
+
# POST /products requires objectType and parent. ID is auto-generated server-side.
|
|
148
|
+
self._validate_required_params(
|
|
149
|
+
{
|
|
150
|
+
"objectType": product_data.objectType,
|
|
151
|
+
"parent": product_data.parent,
|
|
152
|
+
},
|
|
153
|
+
["objectType", "parent"]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Convert request to dict for API call
|
|
157
|
+
product_dict = product_data.model_dump(exclude_none=True)
|
|
158
|
+
self._log_operation("createProduct", {"objectType": product_data.objectType, "parent": product_data.parent})
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
response = self.client.createProduct(json=product_dict, **self._build_context_params())
|
|
162
|
+
except Exception as e:
|
|
163
|
+
if "409" in str(e) or "conflict" in str(e).lower():
|
|
164
|
+
raise exc.ConflictError(409, "Product conflict while creating product")
|
|
165
|
+
if "400" in str(e):
|
|
166
|
+
raise exc.ValidationError(str(e))
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
# Convert response to ProductResponse
|
|
170
|
+
if isinstance(response, dict):
|
|
171
|
+
return ProductResponse(**response)
|
|
172
|
+
return response
|
|
173
|
+
|
|
174
|
+
@handle_rest_errors
|
|
175
|
+
def update_product(self, product_id: str,
|
|
176
|
+
updates: ProductUpdateRequest,
|
|
177
|
+
key_id: Optional[str] = None) -> ProductResponse:
|
|
178
|
+
"""Partially update an existing product (PATCH).
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
product_id: The product ID (or alternate key value if key_id is set)
|
|
182
|
+
updates: ProductUpdateRequest with fields to update
|
|
183
|
+
key_id: Alternate key ID to use for lookup (optional)
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
ProductResponse with updated product data
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
NotFoundError: If product not found
|
|
190
|
+
ValidationError: If updates are invalid
|
|
191
|
+
RestApiError: For other API errors
|
|
192
|
+
"""
|
|
193
|
+
self._validate_required_params(
|
|
194
|
+
{"product_id": product_id},
|
|
195
|
+
["product_id"]
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
updates_dict = updates.model_dump(exclude_none=True)
|
|
199
|
+
query_params = self._build_context_params()
|
|
200
|
+
if key_id:
|
|
201
|
+
query_params["keyId"] = key_id
|
|
202
|
+
self._log_operation("updateProduct", {"product_id": product_id})
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
response = self.client.updateProduct(
|
|
206
|
+
id=product_id,
|
|
207
|
+
json=updates_dict,
|
|
208
|
+
**query_params
|
|
209
|
+
)
|
|
210
|
+
except Exception as e:
|
|
211
|
+
if "404" in str(e):
|
|
212
|
+
raise exc.NotFoundError(product_id, "Product")
|
|
213
|
+
if "400" in str(e):
|
|
214
|
+
raise exc.ValidationError(str(e))
|
|
215
|
+
raise
|
|
216
|
+
|
|
217
|
+
if isinstance(response, dict):
|
|
218
|
+
return ProductResponse(**response)
|
|
219
|
+
return response
|
|
220
|
+
|
|
221
|
+
@handle_rest_errors
|
|
222
|
+
def replace_product(self, product_id: str,
|
|
223
|
+
product_data: ProductCreateRequest,
|
|
224
|
+
key_id: Optional[str] = None,
|
|
225
|
+
allow_overwrite: bool = False) -> ProductResponse:
|
|
226
|
+
"""Fully replace a product (PUT). Creates it if it does not exist.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
product_id: The product ID (or alternate key value if key_id is set)
|
|
230
|
+
product_data: Complete product data to replace with
|
|
231
|
+
key_id: Alternate key ID to use for lookup (optional)
|
|
232
|
+
allow_overwrite: Whether to allow overwriting an existing product
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
ProductResponse with replaced product data
|
|
236
|
+
|
|
237
|
+
Raises:
|
|
238
|
+
NotFoundError: If product not found and allow_overwrite is False
|
|
239
|
+
ValidationError: If data is invalid
|
|
240
|
+
RestApiError: For other API errors
|
|
241
|
+
"""
|
|
242
|
+
self._validate_required_params(
|
|
243
|
+
{"product_id": product_id},
|
|
244
|
+
["product_id"]
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
product_dict = product_data.model_dump(exclude_none=True)
|
|
248
|
+
query_params: dict[str, Any] = self._build_context_params()
|
|
249
|
+
if key_id:
|
|
250
|
+
query_params["keyId"] = key_id
|
|
251
|
+
if allow_overwrite:
|
|
252
|
+
query_params["allow-overwrite"] = allow_overwrite
|
|
253
|
+
self._log_operation("createOrReplaceProduct", {"product_id": product_id})
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
response = self.client.createOrReplaceProduct(
|
|
257
|
+
id=product_id,
|
|
258
|
+
json=product_dict,
|
|
259
|
+
**query_params
|
|
260
|
+
)
|
|
261
|
+
except Exception as e:
|
|
262
|
+
if "404" in str(e):
|
|
263
|
+
raise exc.NotFoundError(product_id, "Product")
|
|
264
|
+
if "400" in str(e) or "409" in str(e):
|
|
265
|
+
raise exc.ValidationError(str(e))
|
|
266
|
+
raise
|
|
267
|
+
|
|
268
|
+
if isinstance(response, dict):
|
|
269
|
+
return ProductResponse(**response)
|
|
270
|
+
return response
|
|
271
|
+
|
|
272
|
+
@handle_rest_errors
|
|
273
|
+
def delete_product(self, product_id: str,
|
|
274
|
+
key_id: Optional[str] = None) -> bool:
|
|
275
|
+
"""Delete a product.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
product_id: The product ID (or alternate key value if key_id is set)
|
|
279
|
+
key_id: Alternate key ID to use for lookup (optional)
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
True if deletion was successful
|
|
283
|
+
|
|
284
|
+
Raises:
|
|
285
|
+
NotFoundError: If product not found
|
|
286
|
+
RestApiError: For other API errors
|
|
287
|
+
"""
|
|
288
|
+
self._validate_required_params(
|
|
289
|
+
{"product_id": product_id},
|
|
290
|
+
["product_id"]
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
query_params = self._build_context_params()
|
|
294
|
+
if key_id:
|
|
295
|
+
query_params["keyId"] = key_id
|
|
296
|
+
self._log_operation("deleteProduct", {"product_id": product_id})
|
|
297
|
+
|
|
298
|
+
try:
|
|
299
|
+
self.client.deleteProduct(id=product_id, **query_params)
|
|
300
|
+
return True
|
|
301
|
+
except Exception as e:
|
|
302
|
+
if "404" in str(e):
|
|
303
|
+
raise exc.NotFoundError(product_id, "Product")
|
|
304
|
+
raise
|
|
305
|
+
|
|
306
|
+
def search_by_type(self, user_type_id: str) -> ProductListResponse:
|
|
307
|
+
"""Search products by object type (convenience method).
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
user_type_id: Object type ID to filter by
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
ProductListResponse with matching products
|
|
314
|
+
"""
|
|
315
|
+
return self.search_products(
|
|
316
|
+
condition={"conditionType": "objecttype", "objectType": user_type_id}
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
def search_by_id(self, product_id: str) -> ProductListResponse:
|
|
320
|
+
"""Search products by ID condition (convenience method).
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
product_id: Product ID or pattern to search for
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
ProductListResponse with matching products
|
|
327
|
+
"""
|
|
328
|
+
return self.search_products(
|
|
329
|
+
condition={"conditionType": "id", "id": product_id}
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
# ------------------------------------------------------------------
|
|
333
|
+
# Approval & lifecycle (v1.4.0)
|
|
334
|
+
# ------------------------------------------------------------------
|
|
335
|
+
|
|
336
|
+
@handle_rest_errors
|
|
337
|
+
def get_product_approval_status(self, product_id: str,
|
|
338
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
339
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
340
|
+
qp = self._build_context_params()
|
|
341
|
+
if key_id: qp["keyId"] = key_id
|
|
342
|
+
self._log_operation("getProductApprovalStatus", {"id": product_id})
|
|
343
|
+
try:
|
|
344
|
+
r = self.client.getProductApprovalStatus(id=product_id, **qp)
|
|
345
|
+
except Exception as e:
|
|
346
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
347
|
+
raise
|
|
348
|
+
return r if isinstance(r, dict) else r
|
|
349
|
+
|
|
350
|
+
@handle_rest_errors
|
|
351
|
+
def approve_product(self, product_id: str,
|
|
352
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
353
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
354
|
+
qp = self._build_context_params()
|
|
355
|
+
if key_id: qp["keyId"] = key_id
|
|
356
|
+
self._log_operation("approveProduct", {"id": product_id})
|
|
357
|
+
try:
|
|
358
|
+
r = self.client.approveProduct(id=product_id, **qp)
|
|
359
|
+
except Exception as e:
|
|
360
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
361
|
+
raise
|
|
362
|
+
return r if isinstance(r, dict) else r
|
|
363
|
+
|
|
364
|
+
@handle_rest_errors
|
|
365
|
+
def approve_product_deletion(self, product_id: str,
|
|
366
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
367
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
368
|
+
qp = self._build_context_params()
|
|
369
|
+
if key_id: qp["keyId"] = key_id
|
|
370
|
+
self._log_operation("approveProductDeletion", {"id": product_id})
|
|
371
|
+
try:
|
|
372
|
+
r = self.client.approveProductDeletion(id=product_id, **qp)
|
|
373
|
+
except Exception as e:
|
|
374
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
375
|
+
raise
|
|
376
|
+
return r if isinstance(r, dict) else r
|
|
377
|
+
|
|
378
|
+
@handle_rest_errors
|
|
379
|
+
def purge_product(self, product_id: str,
|
|
380
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
381
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
382
|
+
qp = self._build_context_params()
|
|
383
|
+
if key_id: qp["keyId"] = key_id
|
|
384
|
+
self._log_operation("purgeProduct", {"id": product_id})
|
|
385
|
+
try:
|
|
386
|
+
r = self.client.purgeProduct(id=product_id, **qp)
|
|
387
|
+
except Exception as e:
|
|
388
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
389
|
+
raise
|
|
390
|
+
return r if isinstance(r, dict) else r
|
|
391
|
+
|
|
392
|
+
@handle_rest_errors
|
|
393
|
+
def get_product_children(self, product_id: str,
|
|
394
|
+
key_id: Optional[str] = None) -> list[str]:
|
|
395
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
396
|
+
qp = self._build_context_params()
|
|
397
|
+
if key_id: qp["keyId"] = key_id
|
|
398
|
+
self._log_operation("getProductChildren", {"id": product_id})
|
|
399
|
+
try:
|
|
400
|
+
r = self.client.getProductChildren(id=product_id, **qp)
|
|
401
|
+
except Exception as e:
|
|
402
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
403
|
+
raise
|
|
404
|
+
return r if isinstance(r, list) else []
|
|
405
|
+
|
|
406
|
+
@handle_rest_errors
|
|
407
|
+
def get_product_data_containers(self, product_id: str,
|
|
408
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
409
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
410
|
+
qp = self._build_context_params()
|
|
411
|
+
if key_id: qp["keyId"] = key_id
|
|
412
|
+
self._log_operation("getProductDataContainers", {"id": product_id})
|
|
413
|
+
try:
|
|
414
|
+
r = self.client.getProductDataContainers(id=product_id, **qp)
|
|
415
|
+
except Exception as e:
|
|
416
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
417
|
+
raise
|
|
418
|
+
return r if isinstance(r, dict) else r
|
|
419
|
+
|
|
420
|
+
@handle_rest_errors
|
|
421
|
+
def get_product_incoming_references(self, product_id: str,
|
|
422
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
423
|
+
self._validate_required_params({"product_id": product_id}, ["product_id"])
|
|
424
|
+
qp = self._build_context_params()
|
|
425
|
+
if key_id: qp["keyId"] = key_id
|
|
426
|
+
self._log_operation("getProductIncomingReferences", {"id": product_id})
|
|
427
|
+
try:
|
|
428
|
+
r = self.client.getProductIncomingReferences(id=product_id, **qp)
|
|
429
|
+
except Exception as e:
|
|
430
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
431
|
+
raise
|
|
432
|
+
return r if isinstance(r, dict) else r
|
|
433
|
+
|
|
434
|
+
@handle_rest_errors
|
|
435
|
+
def get_product_value(self, product_id: str, attribute_id: str,
|
|
436
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
437
|
+
self._validate_required_params(
|
|
438
|
+
{"product_id": product_id, "attribute_id": attribute_id},
|
|
439
|
+
["product_id", "attribute_id"])
|
|
440
|
+
qp = self._build_context_params()
|
|
441
|
+
if key_id: qp["keyId"] = key_id
|
|
442
|
+
self._log_operation("getProductValueByAttributeId",
|
|
443
|
+
{"id": product_id, "attributeId": attribute_id})
|
|
444
|
+
try:
|
|
445
|
+
r = self.client.getProductValueByAttributeId(
|
|
446
|
+
id=product_id, attributeId=attribute_id, **qp)
|
|
447
|
+
except Exception as e:
|
|
448
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
449
|
+
raise
|
|
450
|
+
return r if isinstance(r, dict) else r
|
|
451
|
+
|
|
452
|
+
@handle_rest_errors
|
|
453
|
+
def replace_product_value(self, product_id: str, attribute_id: str,
|
|
454
|
+
value: dict[str, Any],
|
|
455
|
+
key_id: Optional[str] = None) -> dict[str, Any]:
|
|
456
|
+
self._validate_required_params(
|
|
457
|
+
{"product_id": product_id, "attribute_id": attribute_id},
|
|
458
|
+
["product_id", "attribute_id"])
|
|
459
|
+
qp = self._build_context_params()
|
|
460
|
+
if key_id: qp["keyId"] = key_id
|
|
461
|
+
self._log_operation("replaceProductValueByAttributeId",
|
|
462
|
+
{"id": product_id, "attributeId": attribute_id})
|
|
463
|
+
try:
|
|
464
|
+
r = self.client.replaceProductValueByAttributeId(
|
|
465
|
+
id=product_id, attributeId=attribute_id, json=value, **qp)
|
|
466
|
+
except Exception as e:
|
|
467
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
468
|
+
if "400" in str(e): raise exc.ValidationError(str(e))
|
|
469
|
+
raise
|
|
470
|
+
return r if isinstance(r, dict) else r
|
|
471
|
+
|
|
472
|
+
@handle_rest_errors
|
|
473
|
+
def delete_product_value(self, product_id: str, attribute_id: str,
|
|
474
|
+
key_id: Optional[str] = None) -> bool:
|
|
475
|
+
self._validate_required_params(
|
|
476
|
+
{"product_id": product_id, "attribute_id": attribute_id},
|
|
477
|
+
["product_id", "attribute_id"])
|
|
478
|
+
qp = self._build_context_params()
|
|
479
|
+
if key_id: qp["keyId"] = key_id
|
|
480
|
+
self._log_operation("deleteProductValueByAttributeId",
|
|
481
|
+
{"id": product_id, "attributeId": attribute_id})
|
|
482
|
+
try:
|
|
483
|
+
self.client.deleteProductValueByAttributeId(
|
|
484
|
+
id=product_id, attributeId=attribute_id, **qp)
|
|
485
|
+
return True
|
|
486
|
+
except Exception as e:
|
|
487
|
+
if "404" in str(e): raise exc.NotFoundError(product_id, "Product")
|
|
488
|
+
raise
|
|
489
|
+
|